winforms 在窗体中分别拖放不同的图形形状

yrefmtwq  于 2023-06-24  发布在  其他
关注(0)|答案(1)|浏览(133)

我试图能够选择,垂直移动和下降2个不同的矩形(可能得到他们的位置,但这是一个问题,另一天)。
这里的代码,我设法把一个形状,但我不能找到一种方法,使它能够执行的行动,通过点击一个不影响其他。

using System.Collections.Generic;
using System.Drawing;
using System.Linq;

public partial class Form1 : Form
{
    Rectangle topMarker = new Rectangle(50, 125, 50, 2);
    Rectangle bottomMarker = new Rectangle(50, 200, 50, 2);
   
    bool isMouseDown = false;
    
    public Form1()
    {
        InitializeComponent();
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.FillRectangle(new SolidBrush(Color.Green), topMarker);
        e.Graphics.FillRectangle(new SolidBrush(Color.Red), bottomMarker);
    }

    
    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        isMouseDown = true;
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (isMouseDown == true)
        {
            topMarker.Location = e.Location;
            topMarker.X = 50;

             if (topMarker.Y < 0)
             {
                topMarker.Y = 0;
             }

             if (topMarker.Y > pictureBox1.Height)
             {
                 topMarker.Y = pictureBox1.Height - topMarker.Height;
             } 
            Refresh();
        }
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
        isMouseDown = false;
    }
}
oaxa6hgo

oaxa6hgo1#

我建议创建一个类对象来描述你的形状。
当您需要与这些对象中的一个对象进行交互时,这些对象的集合更容易处理。
在我看来,类对象应该实现一个接口,允许调用方法并使用所有形状所共有的属性(假设您可以添加不同的形状,而不仅仅是矩形)。
在这里的示例中,Marker类对象实现了一个IShape接口,该接口定义了所有对象必须公开的方法和属性。
它还实现了IDisposable,因为它以GraphicsPath的形式保存非托管资源。记住在Form关闭时对集合的所有元素调用Dispose()

  • Marker的类Move()方法允许指定偏移量(与前一个位置的差值)来移动形状。
  • 它的Draw()方法接受一个Graphics对象作为参数,你只需要传递e.Graphics对象,该对象由绘制形状的画布的Paint事件的PaintEventArgs提供。标记在此设备上下文中绘制自身。
  • 当鼠标位置福尔斯在形状的边界内时,IsMouseOver()返回true或false。它使用GraphicsPath的IsVisible属性

为了避免在拖动时 * 丢失 * 形状(因为鼠标指针可能会移动到它的边界之外),当其中一个Marker对象接收到单击事件时,我们预定义一个 * 选定的形状 *,并存储指针的当前位置。然后在移动鼠标时提前更新。当前选定的形状也会更新(请参见mouseTrackLocationselectedMarker字段)
这就是它的全部,除了你可以添加一些 tolerance 到代码中来识别鼠标指针下的形状(可以用一些不可见的内容来 * 膨胀 * GraphicsPath)
注意:此代码假设您的目标是.NET 6+并启用了nullable。如果不是这种情况,只需将using块中的所有object?声明更改为objectusing

public partial class SomeForm : Form {

    private List<Marker> markers = new();
    private bool dragShapeStarted = false;
    private Point mouseTrackLocation = Point.Empty;
    private Marker? selectedMarker = null;

    public SomeForm() {
        InitializeComponent();
        markers.AddRange(new[]{
            new Marker(new RectangleF(50, 125, 100, 2), Color.Transparent, Color.Green),
            new Marker(new RectangleF(50, 200, 100, 2), Color.Transparent, Color.Red),
            new Marker(new RectangleF(50, 250, 100, 2), Color.Transparent, Color.Orange),
        });
    }

    private void somePictureBox_MouseDown(object? sender, MouseEventArgs e) {
        if (e.Button == MouseButtons.Left) {
            selectedMarker = markers.FirstOrDefault(m => m.IsMouseOver(e.Location));
            // Mouse Down on a shape & selectedMarker not null => pre-emptive positive result
            if (selectedMarker != null) dragShapeStarted = true;
            mouseTrackLocation = e.Location;
        }
    }

    private void somePictureBox_MouseMove(object? sender, MouseEventArgs e) {
        if (!(sender is PictureBox pBox)) return;

        pBox.Cursor = selectedMarker is null ? Cursors.Default : Cursors.HSplit;
        // We need to move the selected shape as quick as possible: see MouseDown
        if (selectedMarker != null && dragShapeStarted) {
            selectedMarker.Move(new PointF(0, e.Location.Y - mouseTrackLocation.Y));
            mouseTrackLocation = e.Location;
            pBox.Invalidate();
        }
        // Enables curson change while the Mouse Pointer is moved
        selectedMarker = markers.FirstOrDefault(m => m.IsMouseOver(e.Location));
    }

    private void somePictureBox_MouseUp(object? sender, MouseEventArgs e) {
        dragShapeStarted = false;
        selectedMarker = null;
    }

    private void somePictureBox_Paint(object? sender, PaintEventArgs e) {
        markers.ForEach(m => m.Draw(e.Graphics));
    }
}

Marker类和IShape接口:

public interface IShape {
    RectangleF Shape { get; }
    GraphicsPath Path { get; }
    void Move(PointF position);
    void Draw(Graphics graphics);
    bool IsMouseOver(PointF mousePosition);
}

public class Marker : IShape, IDisposable {
    private bool disposed = false;
    private GraphicsPath path = new();
    public Marker(RectangleF shape, Color borderColor, Color fillColor) {
        BorderColor = borderColor;
        FillColor = fillColor;
        path.AddRectangle(shape);
        Path = path;
    }

    public RectangleF Shape => path.GetBounds();
    public GraphicsPath Path { get; }
    public Color BorderColor { get; set; }
    public Color FillColor { get; set; }
    public bool IsMouseOver(PointF mousePosition) => path.IsVisible(mousePosition);

    public void Move(PointF position) {
        // Translates by an offset, not absolute position
        using var mx = new Matrix(1, 0, 0, 1, position.X, position.Y);
        path.Transform(mx);
    }

    public void Draw(Graphics canvas) {
        using var brush = new SolidBrush(FillColor);
        using var pen = new Pen(BorderColor);
        canvas.FillPath(brush, path);
        canvas.DrawPath(pen, path);
    }

    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing) {
        if (!disposed) {
            path?.Dispose();
            disposed = true;
        }
    }
}

它是这样工作的:

相关问题