I am using Emgucv and Zxing to create a QR Code Scanner And I have created a customer PictureBox to scan QR Code.The webcam is responsible for scanning the QR Code to PictureBox.And I also want to make an animation of a scan in PictureBox.The code works fine but the animation of the red line doesn't show up in the PictureBox when I start to scan QR code.Here's my Code:
Customer picturebox:
public partial class qrCodeViewer : PictureBox
{
int y = 0;
public Timer _timer;
public qrCodeViewer()
{
InitializeComponent();
}
public void _timer_Tick(object sender, EventArgs e)
{
y += 10;
if (y >= 300)
{
y = 0;
}
Invalidate();
}
protected override void OnPaint(PaintEventArgs pe)
{
Graphics g = pe.Graphics;
g.DrawLine(new Pen(Color.Red, 2f), new Point(0, y), new Point(360, y));
base.OnPaint(pe);
}
}
WinForms:
private void readQR_Click(object sender, EventArgs e)
{
qrRealTime._timer = new Timer();
qrRealTime._timer.Start();
qrRealTime._timer.Interval = 50;
qrRealTime._timer.Tick += new EventHandler(qrRealTime._timer_Tick);
openWebCam();
_timer.Start();
_timer.Tick += new EventHandler(TimerEventProcessor);
}
private void TimerEventProcessor(object sender, EventArgs e)
{
Image<Bgr, Byte> frame = new Image<Bgr, Byte>(360, 280);
frame = cap.QueryFrame();
qrRealTime.Image = frame.ToBitmap();
ZXing.IBarcodeReader reader = new ZXing.BarcodeReader();
ZXing.Result result = reader.Decode(frame.ToBitmap());
if (result != null)
{
}
}
My problem is how to show up the animation in PictureBox?
WinForms's image
The call order in the OnPaint method matters.
First call
base.OnPaint(pe);
to draw the beneath image.
Then call the other two lines to draw the red line. Now the code looks like
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
Graphics g = pe.Graphics;
g.DrawLine(new Pen(Color.Red, 2f), new Point(0, y), new Point(360, y));
}
Related
I created in a Window Form 4 PictureBoxes (pictureBox1, pictureBox2, pictureBox3 and pictureBox4). I also created a function to draw a rectangle on a pictureBox like this:
To create the rectangle:
private void PictureBox_MouseMove(object sender, MouseEventArgs e)
{
var x = e.X;
var y = e.Y;
var width = 10;
var height = 10;
FwRect = new[]
{
new PointF(x, y), new PointF(x, y + height), new PointF(x + width, y + height),
new PointF(x + width, y)
};
FwRectan = new Rectangle((int)x, (int)y, (int)width, (int)height);
Refresh();
}
Then I added this event for each pictureBox:
this.pictureBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PictureBox_MouseMove);
this.pictureBox2.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PictureBox_MouseMove);
this.pictureBox3.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PictureBox_MouseMove);
this.pictureBox4.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PictureBox_MouseMove);
To draw the rectangle:
private void PictureBox_Paint(object sender, PaintEventArgs e)
{
using (var pen = new Pen(Color.Black, 2))
{
//Draw the rectangle on our form with the pen
e.Graphics.DrawRectangle(pen, FwRectan);
}
}
Eventually, if I move the mouse inside the pictureBox1 and draw a rectangle, it also draw a rectangle for each pictureBox. How can I draw a rectangle only on the pictureBox that the mouse is located at?
Thank you very much!
You have 4 PictureBox, so you need 4 Rectangle to draw current mouse movement:
Rectangle[] _rectangle = new Rectangle[4];
then in both common PictureBox_MouseMove and PictureBox_Paint events you need to identify which value to use, index of picturebox. It can be done by using Tag property or by putting all pictureboxes into array so that their index there will match:
PictureBox _control = new PictureBox[] { pictureBox1, pictureBox2, pictureBox3, pictureBox4 };
The event handles will looks like this
void PictureBox_MouseMove(object sender, MouseEventArgs e)
{
var x = e.X;
var y = e.Y;
var width = 10;
var height = 10;
FwRect = new[]
{
new PointF(x, y), new PointF(x, y + height), new PointF(x + width, y + height),
new PointF(x + width, y)
};
var index = _control.IndexOf(sender);
_rectangle[index] = new Rectangle((int)x, (int)y, (int)width, (int)height);
_rectangle[index].Invalidate();
}
void PictureBox_Paint(object sender, PaintEventArgs e)
{
var index = _control.IndexOf(sender);
using (var pen = new Pen(Color.Black, 2))
{
//Draw the rectangle on our form with the pen
e.Graphics.DrawRectangle(pen, _rectangle[index]);
}
}
Edit:
Actually above solution will remember rectangle for each picturebox. Might not be what you want. The simple fix would be to clear other rectangles in mousemove. Though the more proper solution would be to remember sender from mousemove and only paint matching sender in paint.
Here's an example showing how to store the Rectangle in the .Tag property as mentioned by Sinatr in his post. This example also clears the Rectangle when the mouse leaves so you only ever have one Rectangle being drawn in the current PictureBox:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.pictureBox1.MouseMove += this.PictureBox_MouseMove;
this.pictureBox2.MouseMove += this.PictureBox_MouseMove;
this.pictureBox3.MouseMove += this.PictureBox_MouseMove;
this.pictureBox4.MouseMove += this.PictureBox_MouseMove;
this.pictureBox1.MouseLeave += this.pictureBox_MouseLeave;
this.pictureBox2.MouseLeave += this.pictureBox_MouseLeave;
this.pictureBox3.MouseLeave += this.pictureBox_MouseLeave;
this.pictureBox4.MouseLeave += this.pictureBox_MouseLeave;
this.pictureBox1.Paint += this.PictureBox_Paint;
this.pictureBox2.Paint += this.PictureBox_Paint;
this.pictureBox3.Paint += this.PictureBox_Paint;
this.pictureBox4.Paint += this.PictureBox_Paint;
}
private int bxWidth = 10;
private int bxHeight = 10;
private void PictureBox_MouseMove(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Tag = new Rectangle(e.X, e.Y, bxWidth, bxHeight);
pb.Invalidate();
}
private void PictureBox_Paint(object sender, PaintEventArgs e)
{
PictureBox pb = (PictureBox)sender;
if (pb.Tag != null && pb.Tag is Rectangle)
{
Rectangle rc = (Rectangle)pb.Tag;
using (var pen = new Pen(Color.Black, 2))
{
//Draw the rectangle on our form with the pen
e.Graphics.DrawRectangle(pen, rc);
}
}
}
private void pictureBox_MouseLeave(object sender, EventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.Tag = null; // if you want the box to disappear when the mouse leaves?
pb.Invalidate();
}
}
Here's what it looks like running:
Here is my source code. I can't seem to get the bitmap to show the lines drawn on the panel when I move the mouse with the button pressed. Frustrated and looking for someone to help me finish the code so I can complete the app for my 9-yo daughter. Thank you in advance...
namespace TV_PAINT
{
public partial class ALANA_PAINT : Form
{
Graphics g;
Pen p = new Pen(Color.Black, 7);
Point sp = new Point(0, 0);
Point ep = new Point(0, 0);
int m = 0;
Bitmap BP;
public ALANA_PAINT()
{
InitializeComponent();
tb1.Text = p.Width.ToString();
BP = new Bitmap(pnl1.ClientSize.Width, pnl1.ClientSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
}
private void closeButton_Click(object sender, EventArgs e)
{
pnl1.Dispose();
p.Dispose();
this.Close();
}
private void clearButton_Click(object sender, EventArgs e)
{
//pnl1.Invalidate();
p.Color = System.Drawing.Color.Black;
p.Width = 7;
tb1.Text = p.Width.ToString();
//pnl1.Invalidate();
}
private void pnl1_MouseDown(object sender, MouseEventArgs e)
{
sp = e.Location;
if (e.Button == MouseButtons.Left)
m = 1;
if (e.Button == MouseButtons.Right)
m = 1;
}
private void pnl1_MouseMove(object sender, MouseEventArgs e)
{
if (m == 1)
{
ep = e.Location;
//g = pnl1.CreateGraphics();
Graphics g = Graphics.FromImage(BP);
g.DrawLine(p, sp, ep);
}
sp = ep;
}
private void pnl1_MouseUp(object sender, MouseEventArgs e)
{
m = 0;
}
BP is just a variable in the form. As I can see, it is not displayed anywhere in your form. Why do you need a bitmap for it.
You can do something like this, just get the graphics of your form, and draw using that graphic. https://msdn.microsoft.com/en-us/library/ztxk24yx(v=vs.110).aspx
Noted: you need to do it on PaintEvent of the form, otherwise your drawing will be removed after the next repaint, so you need some variables to store all of your lines, then draw all of them in the paint event.
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphics;
formGraphics = this.CreateGraphics();
formGraphics.FillRectangle(myBrush, new Rectangle(0, 0, 200, 300));
myBrush.Dispose();
formGraphics.Dispose();
Updated:
If you want to save your change to a bitmap. You can use Form.DrawToBitmap to save your drawing in the form to a bitmap, then call bitmap.Save() to a file in directory.
I am attempting to save an image as modified by graphics tools such as pens and shapes that can be drawn onto the image. I have done this using a panel with background image and trying to set up a bit map that will save changes within this panel:
private void saveToolStripButton_Click(object sender, EventArgs e)
{
//sets panel1 contents as bit map to be saved at set locations
int width = panel1.Size.Width;
int height = panel1.Size.Height;
using (Bitmap bmp = new Bitmap(width, height))
{
panel1.DrawToBitmap(bmp, new Rectangle(0, 0, width, height));
bmp.Save(#"C:\Users\Me\Pics\testBitmap.jpeg", ImageFormat.Jpeg);
}
MessageBox.Show("Your image has been saved");
}
Once the save button is clicked, the image saves ok but the changes made with the graphics tools do not show up. Can anyone suggest a solution?
Here is some code regarding the graphics tool i've set up for use within the panel:
{
InitializeComponent();
//Create graphics object in panel1
g = panel1.CreateGraphics();
}
private void btnExit2_Click(object sender, EventArgs e)
{
this.Close();
}
Graphics g;
//set a drawing boolean
bool draw = false;
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
draw = true;
if (drawSq)
{
SolidBrush brush = new SolidBrush(Color.FromArgb(128, 255, 0, 0));
if (toolStripTextBox1.Text != "")
{
g.FillRectangle(brush, e.X, e.Y, Convert.ToInt32(toolStripTextBox1.Text), Convert.ToInt32(toolStripTextBox1.Text));
}
else if (toolStripTextBox1.Text == "")
{
MessageBox.Show("Please enter a shape size");
}
draw = false;
drawSq = false;
}
}
and more:
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
mouseX = null;
mouseY = null;
}
//null values allow freehand style drawing
int? mouseX = null;
int? mouseY = null;
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
//creates a pen tool and sets properties by mouse location
if (draw)
{
Pen pen = new Pen(btnColor.ForeColor, float.Parse(txtBox1.Text));
g.DrawLine(pen, new Point(mouseX ?? e.X, mouseY ?? e.Y), new Point(e.X, e.Y));
mouseX = e.X;
mouseY = e.Y;
}
}
Let's try to fix this.
Start by creating your image first:
Bitmap bmp;
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
bmp = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
}
Now when you want to draw on it:
void panel1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
using (Graphics g = Graphics.FromImage(bmp)) {
g.FillEllipse(Brushes.Red, new Rectangle(e.X - 4, e.Y - 4, 8, 8));
}
panel1.Invalidate();
}
}
And display the results:
void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.DrawImage(bmp, Point.Empty);
}
To save, just use your bitmap:
bmp.Save(#"c:\filename.png", ImageFormat.Png);
Use Double buffering with Panel to avoid the flickering.
This will works fine. I tested it and worked well........
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace drawing
{
public partial class Form2 : Form
{
Graphics g;
bool startPaint = false;
int? initX = null;
int? initY = null;
bool drawSquare = false;
bool drawRectangle = false;
bool drawCircle = false;
public Form2()
{
InitializeComponent();
bmp = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
}
Bitmap bmp;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (startPaint)
{
using ( g = Graphics.FromImage(bmp))
{
// g.FillEllipse(Brushes.Black, new Rectangle(e.X, e.Y , 5, 5));
Pen p = new Pen(btn_PenColor.BackColor, float.Parse(cmb_PenSize.Text));
g.DrawLine(p, new Point(initX ?? e.X, initY ?? e.Y), new Point(e.X, e.Y));
initX = e.X;
initY = e.Y;
//g.DrawImage(bmp, new Rectangle(e.X - 4, e.Y - 4, 8, 8));
}
panel1.Invalidate();
}
}
private void pnl_Draw_MouseDown(object sender, MouseEventArgs e)
{
startPaint = true;
if (drawSquare)
{
//Use Solid Brush for filling the graphic shapes
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
//setting the width and height same for creating square.
//Getting the width and Heigt value from Textbox(txt_ShapeSize)
g.FillRectangle(sb, e.X, e.Y, int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
//setting startPaint and drawSquare value to false for creating one graphic on one click.
startPaint = false;
drawSquare = false;
}
if (drawRectangle)
{
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
//setting the width twice of the height
g.FillRectangle(sb, e.X, e.Y, 2 * int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
startPaint = false;
drawRectangle = false;
}
if (drawCircle)
{
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
g.FillEllipse(sb, e.X, e.Y, int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
startPaint = false;
drawCircle = false;
}
}
private void pnl_Draw_MouseUp(object sender, MouseEventArgs e)
{
startPaint = false;
initX = null;
initY = null;
}
void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(bmp, Point.Empty);
}
private void button1_Click(object sender, EventArgs e)
{
bmp.Save("D://filename.jpg", ImageFormat.Png);
}
}
}
Im using WFA and C#, and im trying to draw an elipse on top of a picturebox containing an image. here is my code but currently its drawing behind of the PB.
private void Form1_Paint(object sender, PaintEventArgs e)
{
PictureBox pb=new PictureBox();
pb.Location=new Point(10,25);
pb.BackgroundImage = Image.FromFile("fire2_clipped_rev_1.png");
pb.Size = Image.FromFile("fire2_clipped_rev_1.png").Size;
Truck.TruckF(pb.Location, pb.CreateGraphics());
pb.Invalidate();
Controls.Add(pb);
}
static Image truckf = Image.FromFile("fire2_clipped_rev_1.png");
public static void TruckF(Point location, Graphics e)
{
Wheels(truckf.Size,location,e);
}
private static void Wheels(Size simage,Point location,Graphics e)
{
e.FillEllipse(Brushes.Black, location.X / 6F, location.Y / 1.43F, 20, 20);
}
You need to change to handle the Load event on your form. Also the PictureBox is a control and you need to draw an image and hand it to the PictureBox to get this to work. Try this:
private PictureBox pb;
private void Truck_Load(object sender, EventArgs e)
{
pb = new PictureBox();
pb.Location = new Point(10, 25);
Image bg = Image.FromFile("fire2_clipped_rev_1.png");
pb.BackgroundImage = bg;
pb.Size = bg.Size;
Bitmap img = new Bitmap(pb.Size.Width, pb.Size.Height);
pb.Image = img;
using (var g = Graphics.FromImage(img))
{
Truck.TruckF(pb.Location, g);
}
Controls.Add(pb);
}
Everytime I try to add a new line or move the paddle in this game the screen flickers.
How do I keep the screen from flickering when I move the paddle or add a line?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class GameTest : Form
{
int dx=3, dy=3, i =500, o = 100;
int rex = 400, rey = 450 ;
double c =0;
public GameTest()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
Invalidate();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
Graphics g = this.CreateGraphics();
if (e.KeyCode == Keys.Left)
{
//Graphics g = this.CreateGraphics();
Invalidate();
Brush black = new SolidBrush(Color.White);
g.FillRectangle(black, rex, rey, 200, 20);
rex -= 40;
Brush red = new SolidBrush(Color.Green);
g.FillRectangle(red, rex, rey, 200, 20);
}
if (e.KeyCode == Keys.Right)
{
//Graphics g = this.CreateGraphics();
Brush white = new SolidBrush(Color.White);
g.FillRectangle(white, rex, rey, 200, 20);
rex += 40;
Brush red = new SolidBrush(Color.Green);
g.FillRectangle(red, rex, rey, 200, 20);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
DoubleBuffered = false;
Graphics g = this.CreateGraphics();
// Bitmap bmp1 = new Bitmap("G:\c#\Bouncing ball\Pic.jpg");
//TextureBrush tb2 = new TextureBrush(bmp1);
Brush green = new SolidBrush(Color.Green);
g.FillRectangle(green, rex, rey, 200, 20);
Graphics b= this.CreateGraphics();
Brush red = new SolidBrush(Color.Red);
b.FillEllipse(red, i, o, 20, 20);
Pen p = new Pen(Color.Black, 10);
//
g.DrawLine(p, 1000, 480,0,480);
g.DrawLine(p, 1000, 485, 1000, 0);
g .DrawLine(p, 0,480, 0, 0);
}
private void timer1_Tick(object sender, EventArgs e)
{
DoubleBuffered = false;
// int dx=3, dy=3, i = 300, o = 50;
i += dx;
if (i < 0)
{
dx = -dx;
}
else if (i + 50 > 1000)
{
dx = -dx;
}
o += dy;
if ((o +20>= rey) &&(i+20<=rex+200)&&(i+20>=rex))
{
//int rex = 400, rey = 450; RECTANGLE
// int dx=3, dy=3, i(x) = 500, o(y) = 100;
dy =-dy;
//c++;
//label1.Text = c.ToString();
}
// Misgeret\\
if (o < 0)
{
dy = -dy;
}
// Misgeret\\
else if (o + 50 > 600)
{
dy = -dy;
}
this.Invalidate();
}
private void label1_Click(object sender, EventArgs e)
{
label1.Text = c.ToString();
}
}
}
I noticed that you are setting DoubleBuffered to false in multiple areas of your program. That is definitely not helping since the whole reason to use double buffering is to prevent flickering.
The other thing is you are creating Graphics contexts and drawing in multiple places in your application. Try to refactor your code to only draw in the OnPaint() event handler of the form, and do not create a new Graphics context. Use the one provided in the PaintEventArgs of the OnPaint() event.
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
using(Brush green = new SolidBrush(Color.Green))
{
g.FillRectangle(green, rex, rey, 200, 20);
}
// .. etc, etc..
}
Then, when you need to the form to be repainted you just need to invoke the Invalidate() method to tell the GDI that your form, or a portion of it, needs to be repainted. That will in turn cause the Paint event to be fired and the OnPaint() to be called.
As a side note, as #HighCore suggested in the comments, WinForms is definitely not the right framework to create a game in. For games try the XNA framework, or one of several open source ones available on the web such as Unity
UPDATE
To prevent flickering you can use automatic double buffering for your form. This can be enabled in the form constructor, after the call to InitializeComponent(), using a call to SetStyle:
SetStyle( ControlStyles.AllPaintingInWmPaint
| ControlStyles.UserPaint
| ControlStyles.DoubleBuffer , true);