【问题标题】:C# WindowForm How can I make line cursor in PictureBox?C# Windows 窗体如何在 PictureBox 中制作行光标?
【发布时间】:2022-01-27 23:25:35
【问题描述】:

你知道,我们可以很容易地为图表制作线条光标(例如:图)。但是有了 PictureBox,我该怎么做呢?有没有人有解决方案?

【问题讨论】:

  • 您需要对 MouseMove 事件进行编码并使用通过 pbox.CreateGraphics() 创建的 Graphics 对象,通常不是一个好主意..
  • @Luke:这是一个可怕的“重复”......!
  • @TaW CreateGraphics 不需要,只需使用 MouseMove 和 Paint 事件。
  • 嗯,这取决于光标是否应该是持久的。通常不是。
  • 问题是当你移动鼠标时,总是需要重新创建光标(因为移动鼠标时两条线的交叉点会改变。(因为线总是从0->宽度和0->高度。

标签: c# image winforms picturebox


【解决方案1】:

您可以拦截 MouseMove 和 Paint 事件。只需在油漆上画十字即可。

使用Paint方法的好处是,原图没有变化,所以不用再恢复被十字准线覆盖的像素。

这是一个例子:

我在 winform 上放置了一个图片框并链接了一些事件。

using System;
using System.Drawing;
using System.Windows.Forms;

namespace MouseCrosshair
{
    public partial class Form1 : Form
    {
        // to store the latest mouse position
        private Point? _mousePos;
        // the pen to draw the crosshair.
        private Pen _pen = new Pen(Brushes.Red);

        public Form1()
        {
            InitializeComponent();
        }

        private void pictureBox1_MouseEnter(object sender, EventArgs e)
        {
            // when the mouse enters the picturebox, we just hide it.
            Cursor.Hide();
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            var pictureBox = (PictureBox)sender;
            // on a mouse move, save the current location (to be used when drawing the crosshair)
            _mousePos = e.Location;
            // force an update to the picturebox.
            pictureBox.Invalidate();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            // if the mousepos is assigned (meaning we have a mouse pos, draw the crosshair)
            if (_mousePos.HasValue)
            {
                var pictureBox = (PictureBox)sender;
                // draw a vertical line
                e.Graphics.DrawLine(_pen, new Point(_mousePos.Value.X, 0), new Point(_mousePos.Value.X, pictureBox.Height));
                // draw a horizontal line
                e.Graphics.DrawLine(_pen, new Point(0, _mousePos.Value.Y), new Point(pictureBox.Width, _mousePos.Value.Y));
            }
        }

        private void pictureBox1_MouseLeave(object sender, EventArgs e)
        {
            // when the mouse is outside the picturebox, clear the mousepos
            _mousePos = null;
            // repaint the picturebox
            pictureBox1.Invalidate();
            // show the mouse cursor again.
            Cursor.Show();
        }
    }
}

由于事件使用sender,您可以将多个图片框链接到这些事件。

也可以继承PictureBox,写一个新的CrosshairPictureBox控件,默认有十字准线。


如果您想在PictureBox 中绘制图表,请使用Bitmap,然后使用Graphics.FromImage(bitmap) 绘制图表并将其放入PictureBox.Image别忘了释放 Graphics 对象。

【讨论】:

  • 非常感谢!我解决了我的问题^^
【解决方案2】:

您可以通过存储收到的最后一个点的位置来实现这一点,然后使用Graphics.DrawLine 方法在旧位置和新位置之间画一条线。

还请注意,当鼠标移动时,鼠标指针经过的每个像素的Control.MouseMove 事件不会在每次移动时都收到。您确实会以相当一致的时间间隔收到Control.MouseMove 事件。这意味着鼠标移动得越快,您实际接收到的点距离就越远。

查看此演练以获取一些示例 - https://www.c-sharpcorner.com/UploadFile/mahesh/drawing-lines-in-gdi/

【讨论】:

  • 我不认为 OP 想用鼠标画一条线。他想用一个大十字准线代替鼠标光标。
【解决方案3】:

如果我正确理解问题,您有兴趣为图表绘制 x 轴和 y 轴,但不使用聊天控件。

在这种情况下,你需要做的是:处理PictureBox的Paint事件,从上中到下,从左中到右中画线。

这是我为生成上图而编写的代码,y = Sin(x) :

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    var axisWidth = 3;
    var axisColor = Color.Red;
    var chartLineWidth = 2;
    var chartLineColor = Color.Blue;
    var scale = 90;
    var gridSize = 45;
    var gridLineWidth = 1;
    var gridLineColor = Color.LightGray;

    var g = e.Graphics;
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    var w = pictureBox1.ClientRectangle.Width / 2;
    var h = pictureBox1.ClientRectangle.Height / 2;
    g.TranslateTransform(w, h);
    g.ScaleTransform(1, -1);

    //Draw grid
    for (int i = -w / gridSize; i <= w / gridSize; i++)
        using (var axisPen = new Pen(gridLineColor, gridLineWidth))
            g.DrawLine(axisPen, i * gridSize, -h, i * gridSize, h);

    for (int i = -h / gridSize; i <= h / gridSize; i++)
        using (var axisPen = new Pen(gridLineColor, gridLineWidth))
            g.DrawLine(axisPen, -w, i * gridSize, w, i * gridSize);

    //Draw axis
    using (var axisPen = new Pen(axisColor, axisWidth))
    {
        g.DrawLine(axisPen, -w, 0, w, 0); //X-Asxis
        g.DrawLine(axisPen, 0, -h, 0, h); //Y-Asxis
    }

    //Draw y = Sin(x) 
    var points = new List<PointF>();
    for (var x = -w; x < w; x++)
    {
        var y = System.Math.Sin(x * Math.PI / 180);
        points.Add(new PointF(x, scale * (float)y));
    }
    using (var chartLinePen = new Pen(chartLineColor, chartLineWidth))
    {
        g.DrawCurve(chartLinePen, points.ToArray());
    }
    g.ResetTransform();
}

您还需要以下代码来处理图片框的大小调整:

private void MyForm_Load(object sender, EventArgs e)
{
    this.pictureBox1.GetType().GetProperty("ResizeRedraw",
        System.Reflection.BindingFlags.NonPublic |
        System.Reflection.BindingFlags.Instance).SetValue(
        this.pictureBox1, true);
}

你也可以add a crosshair and rubber-band rectangle来控制,如下图:

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-20
    相关资源
    最近更新 更多