简体   繁体   中英

Drawing in two pictureBoxes

I created two pictureBoxes on my windows form application. I want to draw in both of them, using FillEllipse(), but for some reason I can only draw in the first pictureBox. I belive the problem is that I don't understand properly how events work. Here is the code:

public Form1()
    {
        InitializeComponent();
        pictureBox1.Paint += new PaintEventHandler(this.pictureBox1_Paint);
        pictureBox2.Paint += new PaintEventHandler(this.pictureBox2_Paint);
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        Graphics gr = e.Graphics;
        Point p1 = pictureBox1.Location;
        gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 40, p1.Y + 40, 20, 20));
        gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 40, p1.Y + 80, 20, 20));
        gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 80, p1.Y + 40, 20, 20));
        gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 80, p1.Y + 80, 20, 20));
    }

    private void pictureBox2_Paint(object sender, PaintEventArgs e)
    {
        Graphics br = e.Graphics;
        Point p2 = pictureBox2.Location;
        br.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p2.X + 40, p2.Y + 40, 20, 20));
        br.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p2.X + 40, p2.Y + 80, 20, 20));
        br.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p2.X + 80, p2.Y + 40, 20, 20));
        br.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p2.X + 80, p2.Y + 80, 20, 20));
    }

You are drawing in pictureBox2. Your problem is that you are drawing outside of the viewport, because you are drawing at pictureBox2's location on the form, but within the picturebox. pictureBox2.Location gives to position of the box on the form. If this box is at position x=240, y=240, you are drawing INSIDE the box at those positions. If your box is only w=50, h=50, you will not see what you are drawing because it's waaaay to the right and bottom

So, this is really inefficient you're drawing everything twice resulting in twice the load. What you need to do is draw once into a bitmap and load the bitmap into the two picture boxes.

https://docs.microsoft.com/en-us/dotnet/framework/winforms/advanced/how-to-create-a-bitmap-at-run-time

However, if working with bitmaps won't allow you to achieve whatever it is you're trying to do, write a custom control. While this wont improve performance all that much it will at least stop code duplication.

https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/creating-a-wf-control-design-time-features

Bitmap img= new Bitmap(100, 100);
Point p1 = pictureBox1.Location;
Graphics gr = Graphics.FromImage(img);
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 40, p1.Y + 40, 20, 20));
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 40, p1.Y + 80, 20, 20));
gr.FillEllipse(new SolidBrush(Color.Red), new Rectangle(p1.X + 80, p1.Y + 40, 20, 20));


picturebox1.Image = img;
picturebox2.Image = img;

The PaintEventArgs e.Graphics gives you a control's DeviceContext (consider it a reference to the graphics surface of a control) and a set of tools that can be used to perform graphics operations on that context.

When using e.Graphics , all drawings occur inside the underlying surface the graphics object references (a PictureBox ClipRectangle in this case).
All coordinates are related to this area.

Thus, you just need to specify the position and size of a drawing using the control's Client Area as the only reference. The drawing area dimensions are also reported by the e.Graphics.ClipBounds (expressed in PageUnits ) and the control ClientRectangle property (expressed in Pixels ).
The ClientRectangle is the area of a control which excludes non-client elements such as Borders , Menus , ScrollBars , TitleBar etc.; it's "inner-body".

The client area definition can, however, change in relation to a control's internal structure (imagine a ListView or a ComboBox control, for example) .

The Paint() event of a control is raised each time a control needs to repaint itself.
It's always raised after a control is first created.
After that, it could be triggered when, for example, a control is for some reasons "obscured" by another control/window or when the Form that contains it is minimized.

It can be raised "manually" invoking the control's Invalidate() method.
This is probably the prefered way to force a control to repaint itself, because the Invalidate() method allows to specify a defined portion (a Rectangle or a Region ) of a control that needs repainting, limiting the painting to this area.

You could modify your code this way:

public Form1()
{
    InitializeComponent();
    pictureBox1.Paint += new PaintEventHandler(this.pictureBox1_Paint);
    pictureBox2.Paint += new PaintEventHandler(this.pictureBox2_Paint);
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.FillEllipse(Brushes.Red, new Rectangle(40, 40, 20, 20));
    e.Graphics.FillEllipse(Brushes.Red, new Rectangle(40, 80, 20, 20));
    e.Graphics.FillEllipse(Brushes.Red, new Rectangle(80, 40, 20, 20));
    e.Graphics.FillEllipse(Brushes.Red, new Rectangle(80, 80, 20, 20));
}

private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.FillEllipse(Brushes.Red, new Rectangle(40, 40, 20, 20));
    e.Graphics.FillEllipse(Brushes.Red, new Rectangle(40, 80, 20, 20));
    e.Graphics.FillEllipse(Brushes.Red, new Rectangle(80, 40, 20, 20));
    e.Graphics.FillEllipse(Brushes.Red, new Rectangle(80, 80, 20, 20));
}

SmoothingMode = SmoothingMode.AntiAlias is used to "prettify" the graphics results.
It which will generate smoother borders.

The Drawing Brush used is a stock object (system-provided) which doesn't need to be Disposed() .
If you create a Brush using one of the brush related classes, the object you create must be disposed.

using (SolidBrush brush = new SolidBrush(Color.Red))
{
    e.Graphics.FillEllipse(brush, new Rectangle(40, 40, 20, 20));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM