拖动以在 UserControl 上平移

发布于 2024-08-29 05:05:55 字数 2771 浏览 6 评论 0原文

我正在尝试构建自己的“PictureBox like”控件,添加一些功能。例如,我希望能够通过简单地单击并拖动鼠标来平移大图像。

问题似乎出在我的 OnMouseMove 方法上。如果我使用下面的代码,我会得到我想要的拖动速度和精度,但是当然,当我释放鼠标按钮并尝试再次拖动时,图像会恢复到其原始位置。

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

namespace Testing
{
    public partial class ScrollablePictureBox : UserControl
    {
        private Image image;
        private bool centerImage;

        public Image Image
        {
            get { return image; }
            set { image = value; Invalidate(); }
        }

        public bool CenterImage
        {
            get { return centerImage; }
            set { centerImage = value; Invalidate(); }
        }

        public ScrollablePictureBox()
        {
            InitializeComponent();
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
            Image = null;
            AutoScroll = true;
            AutoScrollMinSize = new Size(0, 0);
        }

        private Point clickPosition;
        private Point scrollPosition;

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            clickPosition.X = e.X;
            clickPosition.Y = e.Y;
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (e.Button == MouseButtons.Left)
            {
                scrollPosition.X = clickPosition.X - e.X;
                scrollPosition.Y = clickPosition.Y - e.Y;
                AutoScrollPosition = scrollPosition;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            e.Graphics.FillRectangle(new Pen(BackColor).Brush, 0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);

            if (Image == null)
                return;

            int centeredX = AutoScrollPosition.X;
            int centeredY = AutoScrollPosition.Y;

            if (CenterImage)
            {
               //Something not relevant
            }

            AutoScrollMinSize = new Size(Image.Width, Image.Height);
            e.Graphics.DrawImage(Image, new RectangleF(centeredX, centeredY, Image.Width, Image.Height));
        }
    }
}

但是,如果我将 OnMouseMove 方法修改为如下所示:

protected override void OnMouseMove(MouseEventArgs e)
{
    base.OnMouseMove(e);
    if (e.Button == MouseButtons.Left)
    {
        scrollPosition.X += clickPosition.X - e.X;
        scrollPosition.Y += clickPosition.Y - e.Y;
        AutoScrollPosition = scrollPosition;
    }
}

...您会发现拖动不像以前那样平滑,有时表现得很奇怪(例如有滞后或其他原因)。

我做错了什么?

我还尝试删除所有“基地”呼吁,以绝望的运动来解决这个问题,哈哈,但同样,它没有奏效。

感谢您抽出时间。

I'm trying to build my own "PictureBox like" control adding some functionalities. For example, I want to be able to pan over a big image by simply clicking and dragging with the mouse.

The problem seems to be on my OnMouseMove method. If I use the following code I get the drag speed and precision I want, but of course, when I release the mouse button and try to drag again the image is restored to its original position.

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

namespace Testing
{
    public partial class ScrollablePictureBox : UserControl
    {
        private Image image;
        private bool centerImage;

        public Image Image
        {
            get { return image; }
            set { image = value; Invalidate(); }
        }

        public bool CenterImage
        {
            get { return centerImage; }
            set { centerImage = value; Invalidate(); }
        }

        public ScrollablePictureBox()
        {
            InitializeComponent();
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
            Image = null;
            AutoScroll = true;
            AutoScrollMinSize = new Size(0, 0);
        }

        private Point clickPosition;
        private Point scrollPosition;

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            clickPosition.X = e.X;
            clickPosition.Y = e.Y;
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (e.Button == MouseButtons.Left)
            {
                scrollPosition.X = clickPosition.X - e.X;
                scrollPosition.Y = clickPosition.Y - e.Y;
                AutoScrollPosition = scrollPosition;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            e.Graphics.FillRectangle(new Pen(BackColor).Brush, 0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height);

            if (Image == null)
                return;

            int centeredX = AutoScrollPosition.X;
            int centeredY = AutoScrollPosition.Y;

            if (CenterImage)
            {
               //Something not relevant
            }

            AutoScrollMinSize = new Size(Image.Width, Image.Height);
            e.Graphics.DrawImage(Image, new RectangleF(centeredX, centeredY, Image.Width, Image.Height));
        }
    }
}

But if I modify my OnMouseMove method to look like this:

protected override void OnMouseMove(MouseEventArgs e)
{
    base.OnMouseMove(e);
    if (e.Button == MouseButtons.Left)
    {
        scrollPosition.X += clickPosition.X - e.X;
        scrollPosition.Y += clickPosition.Y - e.Y;
        AutoScrollPosition = scrollPosition;
    }
}

... you will see that the dragging is not smooth as before, and sometimes behaves weird (like with lag or something).

What am I doing wrong?

I've also tried removing all "base" calls on a desperate movement to solve this issue, haha, but again, it didn't work.

Thanks for your time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

另类 2024-09-05 05:05:55

最后,我设法找到了解决方案:

protected Point clickPosition;
protected Point scrollPosition;
protected Point lastPosition;

protected override void OnMouseDown(MouseEventArgs e)
{
    clickPosition.X = e.X;
    clickPosition.Y = e.Y;
}

protected override void OnMouseUp(MouseEventArgs e)
{
    Cursor = Cursors.Default;
    lastPosition.X = AutoScrollPosition.X;
    lastPosition.Y = AutoScrollPosition.Y;
}

protected override void OnMouseMove(MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Cursor = Cursors.Hand;
        scrollPosition.X = clickPosition.X - e.X - lastPosition.X;
        scrollPosition.Y = clickPosition.Y - e.Y - lastPosition.Y;
        AutoScrollPosition = scrollPosition;
    }
}

Finally, I managed to find a solution:

protected Point clickPosition;
protected Point scrollPosition;
protected Point lastPosition;

protected override void OnMouseDown(MouseEventArgs e)
{
    clickPosition.X = e.X;
    clickPosition.Y = e.Y;
}

protected override void OnMouseUp(MouseEventArgs e)
{
    Cursor = Cursors.Default;
    lastPosition.X = AutoScrollPosition.X;
    lastPosition.Y = AutoScrollPosition.Y;
}

protected override void OnMouseMove(MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Cursor = Cursors.Hand;
        scrollPosition.X = clickPosition.X - e.X - lastPosition.X;
        scrollPosition.Y = clickPosition.Y - e.Y - lastPosition.Y;
        AutoScrollPosition = scrollPosition;
    }
}
↙温凉少女 2024-09-05 05:05:55

每次我必须这样做时,这总是令人困惑。
为了那些新到达此线程的人的利益,我想出了一个稍微简单的解决方案,可以实现平滑的平移。

Private GrabPoint As Point

Private Sub OnMouseDown(MouseEventArgs e)
  GrabPoint = e.Location
End Sub

Private Sub OnMouseMove(MouseEventArgs e)
  If e.Button = System.Windows.Forms.MouseButtons.Left Then
    AutoScrollPosition = GrabPoint - e.Location - AutoScrollPosition
  End If
End Sub

Private Sub OnMouseUp(MouseEventArgs e)
  GrabPoint = Point.Empty
End Sub

顺便说一句,抓取和抓取手形光标可以从以下位置下载:
http://theburningmonk.com/2010/ 03/wpf-loading-grab-and-grabbing-cursors-from-resource/

您可以将它们作为嵌入式资源添加到您的项目中,并设置它们:

Cursor = New Cursor(System.Reflection.Assembly.GetExecutingAssembly.GetManifestResourceStream(String.Format("{0}.{1}.cur", Me.GetType.Namespace, "grabbing")))

This is always confusing every time I have to do it.
For the benefit of those newly arriving to this thread I came up with a slightly simpler solution that gives smooth panning.

Private GrabPoint As Point

Private Sub OnMouseDown(MouseEventArgs e)
  GrabPoint = e.Location
End Sub

Private Sub OnMouseMove(MouseEventArgs e)
  If e.Button = System.Windows.Forms.MouseButtons.Left Then
    AutoScrollPosition = GrabPoint - e.Location - AutoScrollPosition
  End If
End Sub

Private Sub OnMouseUp(MouseEventArgs e)
  GrabPoint = Point.Empty
End Sub

By the way, the grab and grabbing hand cursors can be downloaded from:
http://theburningmonk.com/2010/03/wpf-loading-grab-and-grabbing-cursors-from-resource/

You can add them to your project as embedded resources and set them with:

Cursor = New Cursor(System.Reflection.Assembly.GetExecutingAssembly.GetManifestResourceStream(String.Format("{0}.{1}.cur", Me.GetType.Namespace, "grabbing")))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文