我在c#中制作了一个简单的应用程序,它让我绘制一个矩形,而不是用鼠标移动它。现在我想绘制多个矩形我也将它们添加到列表中,这也有效,但我希望能够自己移动每个矩形。这出错了。我只能移动我创建的第一个矩形。如果我尝试移动另一个矩形,第一个矩形传送到我的鼠标,但只有当我点击第二个矩形时,如果我点击其他任何地方它会崩溃与nullpointer(我知道如何解决这个但不是问题)我是什么无法弄清楚为什么我不能移动第二个矩形
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
上课
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
上课
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);
}
}
}
答案 0 :(得分:0)
我建议采用不同的方法。我不会使Item成为类变量或属性。每个控件都有一个名为Tag类型为对象的Property。它可以用于任何目的。我通常做的是在创建时将项目设置为所表示控件的标记。然后在Move触发器中,我将处理从Tag属性中提取Item,从对象中强制转换它,然后通过值直接操作它。
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方法找不到实例,并且您正在尝试操作null对象。这样,这总是可以在特定对象上工作,而您不必搜索它。它清理代码并且运行得更顺畅。
修改强> 另外,我建议将您的类从Object重命名为其他内容。这样就不会与.NET对象根类型混淆
答案 1 :(得分:0)
问题可能是因为tekenVel_Paint
循环中的函数foreach
使用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
变量。您可以使用MouseEventArgs e
功能中的tekenVel_MouseMove
检查是否按下了鼠标按钮。
在MouseUp
活动中,您应为活动项i
设置常用颜色并将其设置为null
。如果OnMouseMove
不为null,请检查i
事件,以防用户在您的控件内部点击但不在任何对象内部。
答案 2 :(得分:0)
我修改了我的列表搜索方法。我现在每个循环都不是最好的方法,所以我稍后会改变它:
private static final float MIN_FRAME_LENGTH = 1f/60f;
private float timeSinceLastRender;
/** @param delta time since the last render call. */
public void render(float delta) {
timeSinceLastRender += delta;
if (timeSinceLastRender >= MIN_FRAME_LENGTH) {
// Do the actual rendering, pass timeSinceLastRender as delta time.
timeSinceLastRender = 0f;
}
}