在列表中拖放矩形

Drag and drop rectangles in list

我用 c# 制作了一个简单的应用程序,它可以让我绘制一个矩形,然后用鼠标移动它。现在我想绘制多个矩形我也将它们添加到列表中,这也有效,但我希望能够单独移动每个矩形。这是错误的。我只能移动我创建的第一个矩形。如果我尝试移动另一个矩形,第一个矩形会传送到我的鼠标,但只有当我单击第二个矩形时,如果我单击其他任何地方,它会因空指针而崩溃(我知道如何解决这个问题,但这不是问题)无法弄清楚为什么我不能移动第二个矩形

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace TekenTest
{
    public partial class Form1 : Form
    {
        bool isMouseDown;
        List<Item> _Items;
        Item i;

        public Form1()
        {
            InitializeComponent();
            _Items = new List<Item>(); 
            isMouseDown = false;
        }

        private void tekenVel_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            foreach (Item i in this._Items)
            {
                i.drawItem(g);
            }
        }

        private void tekenVel_MouseDown(object sender, MouseEventArgs e)
        {
           this.i = _Items.Find(Item => ((i.X <= e.X && (i.WIDTH + i.X) >= e.X) &&
                                         (i.Y <= e.Y && (i.HEIGTH + i.Y) >= e.Y)));

            i.note = Color.Azure;
            isMouseDown = true;
        }

        private void tekenVel_MouseMove(object sender, MouseEventArgs e)
        {
            if (isMouseDown == true)
            {
                i.X = e.X;
                i.Y = e.Y;
                Refresh();
            }
        }

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

        private void itemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.i = new Item();
            this._Items.Add(i);
            this.Refresh();
        }
    }
}

Object class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TekenTest
{
    class Object
    {
        public int X
        {
            get;
            set;
        }

        public int Y
        {
            get;
            set;
        }

        public int HEIGTH
        {
            get;
            set;
        }

        public int WIDTH
        {
            get;
            set;
        }

        public Object()
        {

        }
    }
}

Item class

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TekenTest 
{
    class Item : Object
    {
        public Rectangle rect;
        public String text;
        public Font font;
        public Brush textb;
        public Color note;

        public Item()
        {
            this.X = 200;
            this.Y = 200;
            this.WIDTH = 200;
            this.HEIGTH = 200;
            font = new Font("Arial", 12, FontStyle.Bold, GraphicsUnit.Point);
            text = "Ik ben tekst";
            note = Color.Yellow;
            textb = Brushes.Black;
        }

        public void drawItem(Graphics g)
        {
            this.rect = new Rectangle(X, Y, WIDTH, HEIGTH);
           // g.DrawRectangle(new)
            g.FillRectangle(new SolidBrush(note), rect);
            g.DrawString(text, font, textb, rect);
        }
    }
}

我建议采用不同的方法。我不会将 Item 设为 class 变量或 属性。每个控件都有一个 属性 类型对象的命名标签。它可以用于任何目的。我通常会做的是在创建时将项目设置为表示控件的标签。然后在移动触发器中,我将处理从标签 属性 中提取项目,从对象中转换它,然后直接通过值对其进行操作。

private void itemToolStripMenuItem_Click(object sender, EventArgs e)
{
    var i = ((Control)sender.Tag) as Item;

    this.i = new Item();
    this._Items.Add(i);

    // you dynamically create a control and set the Tag property
    someControl.Tag = i;

    this.Refresh();
}


private void tekenVel_MouseDown(object sender, MouseEventArgs e)
{
    var i = ((Control)sender.Tag) as Item;
    if(i!=null)
    {
        i.note = Color.Azure;
        isMouseDown = true;
    }
}

private void tekenVel_MouseMove(object sender, MouseEventArgs e)
{
    if (isMouseDown == true)
    {
            i.X = e.X;
            i.Y = e.Y;
            Refresh();
    }
}

您的问题可能是 find 方法未找到该实例,而您正试图操作一个空对象。这样,它始终适用于特定对象,您不必搜索它。它清理了代码并且运行起来更加流畅。

编辑 另外,我建议将您的 class 从 Object 重命名为其他名称。只是为了不与 .NET 对象根类型混淆

问题可能是因为在 foreach 循环中的函数 tekenVel_Paint 中,您使用的 Item 名称与实例变量 i 相同。像这里一样将其更改为其他:

    private void tekenVel_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;

        foreach (Item obj in _Items)
        {
            obj.drawItem(g);
        }
    }

tekenVel_MouseDown 中的类似问题。您还应该在函数 Find.

的条件语句中更改名称
    private void tekenVel_MouseDown(object sender, MouseEventArgs e)
    {
       this.i = _Items.Find(item => ((item.X <= e.X && (item.WIDTH + item.X) >= e.X) &&
                                     (item.Y <= e.Y && (item.HEIGTH + item.Y) >= e.Y)));

        i.note = Color.Azure;
        isMouseDown = true;
    }

你也不需要 isMouseDown 变量。您可以使用 tekenVel_MouseMove 函数中的 MouseEventArgs e 检查鼠标按钮是否被按下。 在 MouseUp 事件中,您应该为活动项目设置常用颜色 i 并将其设置为 null。如果 i 不为空,则检查 OnMouseMove 事件,以防用户在您的控件内单击但不在任何对象内单击。

我通过更改列表搜索方法修复了问题。我现在 for each 循环不是最好的方法,所以我稍后会更改它:

        private Item selectItem(MouseEventArgs e)
    {

        IEnumerable<Item> itemQuerry =
        from it in _Items
        where it.X <= e.X && it.WIDTH + it.X >= e.X && it.Y <= e.Y && it.HEIGTH + it.Y >= e.Y
        select it;

        foreach (Item foundItem in itemQuerry)
        {
            this.mItem = foundItem;
        }

        mItem.note = Color.Azure;
        return mItem;
    }