3

いくつかの機能を追加して、独自の「PictureBox のような」コントロールを作成しようとしています。たとえば、マウスをクリックしてドラッグするだけで、大きな画像をパンできるようにしたいと考えています。

問題は私の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;
    }
}

...ドラッグが以前のようにスムーズではなく、時々奇妙な動作をすることがわかります(ラグなどで)。

私は何を間違っていますか?

また、この問題を解決するために絶望的な動きのすべての「ベース」コールを削除しようとしましたが、やはりうまくいきませんでした。

御時間ありがとうございます。

4

2 に答える 2

3

最後に、解決策を見つけることができました:

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;
    }
}
于 2010-04-22T12:19:51.320 に答える
2

これは私がそれをしなければならないたびにいつも混乱します。このスレッドに新しく到着した人のために、スムーズなパンを提供する少し単純なソリューションを考え出しました。

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")))
于 2012-01-19T15:59:46.207 に答える