Why do the lines not cross the same part of the image when the form is resized?

137 Views Asked by At

I'm creating a program that uses the flycapture camera. I've created a class that extends the pictureBox class in order to draw a crosshair, consisting of two lines, onto the screen. I want to be able to move the crosshair from the center to any other location on the screen.

The problem is when the form is resized, the crosshair moves to a different location as shown here. I want the crosshair to be pointing at the same part of the image as before it was resized (in the example it is no longer pointing at the grey mesh). I'm drawing the crosshair in relation to the height and width of the pictureBox. I want to be able to draw the lines on the image but the image height and width are always the same regardless of the image's size.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace FlyCapture2SimpleGUI_CSharp
{
    class IMSPictureBox : PictureBox
    {

        private Color colorSetting = Color.Black;
        private float width = 1.0f;

        public IMSPictureBox()
        {
            this.Paint += IMSPictureBox_Paint;
        }

        private void IMSPictureBox_Paint(object sender, PaintEventArgs e)
        {
            //Draw if image has loaded
            if (this.Image != null)
            {
                //Draw horizontal line
                e.Graphics.DrawLine(
                  new Pen(this.colorSetting, this.width),
                  new Point(0, this.Size.Height / 2 + 100),
                  new Point(this.Size.Width, this.Size.Height / 2 + 100));

                //Draw vertical line
                e.Graphics.DrawLine(
                  new Pen(this.colorSetting, this.width),
                  new Point(this.Size.Width / 2 + 100, 0),
                  new Point(this.Size.Width / 2 + 100, this.Size.Height));
            }
        }
    }
}

Edit: As DiskJunky suggested, I'm now drawing on the image itself and not using the Paint function above.

Here is the image getting set:

private void UpdateUI(object sender, ProgressChangedEventArgs e)
{
    UpdateStatusBar();

    pictureBox1.SetImage = m_processedImage.bitmap;
    pictureBox1.Invalidate();
}

Here are the lines drawing on the image:

public System.Drawing.Image SetImage
{
    set
    {
        using (Graphics g = Graphics.FromImage(value))
        {
            g.DrawLine(new Pen(Color.Red, 3.0f), new Point(0, 0), new Point(value.Width, value.Height));
            g.Dispose();
        }
        this.Image = value;
    }
    get
    {
        return this.Image;
    }
}

I now have a line that scales with the image, but now it's constantly flickering.

1

There are 1 best solutions below

11
On

This isn't exact but modifying to something like the following will keep the position static as the picture box resizes;

class IMSPictureBox : PictureBox
{

    private Color colorSetting = Color.Black;
    private float width = 1.0f;
    private Tuple<Point, Point> _verticalLine;
    private Tuple<Point, Point> _horizontalLine;

    public IMSPictureBox()
    {
        this.Paint += IMSPictureBox_Paint;
    }

    private void IMSPictureBox_Paint(object sender, PaintEventArgs e)
    {
        //Draw if image has loaded
        if (this.Image != null)
        {
            //Draw vertical line
            if (_verticalLine == null)
            {
                _verticalLine = new Tuple<Point, Point>(new Point(100, 0), new Point(100, this.Size.Height);
            }
            e.Graphics.DrawLine(
              new Pen(this.colorSetting, this.width),
              _verticalLine.Item1,
              _verticalLine.Item2);

            //Draw horizontal line
            if (_horizontalLine == null)
            {
                _horizontalLine = new Tuple<Point, Point>(new Point(0, 100), new Point(this.Size.Width, 100);
            }
            e.Graphics.DrawLine(
              new Pen(this.colorSetting, this.width),
              _horizontalLine.Item1,
              _horizontalLine.Item2);
        }
    }
}

Edit The above solution outlines the concept of preserving the line position. As per discussion in comments below, this developed into a more involved solution for the OP as additional requirements came out of investigating and testing the solution above for the original intent - to cleanly draw a a coordinate marker on an image.

To that end a manual double buffering mechanism is recommended in that scenario as the PictureBox control supports limited drawing capability itself. An example of manually implementing a double buffering solution can be found here; https://learn.microsoft.com/en-us/dotnet/framework/winforms/advanced/how-to-manually-render-buffered-graphics

Rather than calling DrawEllipse() there'll be calls to DrawLine() to display the coordinate marker. One caveat is that if the image is still being displayed in the PictureBox then the PictureBoxSizeMode.Zoom value may still have to be accounted for.