перетащите для панорамирования на UserControl - PullRequest
3 голосов
/ 20 апреля 2010

Я пытаюсь создать свой собственный элемент управления «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;
    }
}

... вы увидите, что перетаскивание не является плавным, как раньше, и иногда ведет себя странно (например, с задержкой или чем-то еще).

Что я делаю не так?

Я также пытался удалить все «базовые» вызовы в отчаянном движении, чтобы решить эту проблему, ха-ха, но опять же, это не сработало.

Спасибо за ваше время.

Ответы [ 2 ]

3 голосов
/ 22 апреля 2010

Наконец мне удалось найти решение:

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;
    }
}
2 голосов
/ 19 января 2012

Это всегда сбивает с толку каждый раз, когда мне приходится это делать.Для новичков, пришедших в эту ветку, я предложил несколько более простое решение, обеспечивающее плавное панорамирование.

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")))
...