我正在研究'用例 - 图表形式',用户可以在其中选择元素和模式
只是一个简单的表格。它工作正常,为每个actor元素和每个用例元素创建一个类。在创建之后,两者都被添加到列表中。
但不知怎的,我只是无法弄清楚如何选择一个已创建的元素,并在用它做一些事情之后。
我做的课程:
class Actor
{
private static int _id;
private Panel _panel;
public string Name { get; private set; }
public int X { get; private set; }
public int Y { get; private set; }
public Actor(Panel panel, string name, int x, int y)
{
_id++;
_panel = panel;
Name = name;
X = x;
Y = y;
}
public void DrawActor()
{
// draw Actor
var graphics = _panel.CreateGraphics();
var pen = new Pen(Color.Black, 2);
graphics.DrawEllipse(pen, X - 10, Y - 30, 20, 20);
graphics.DrawLine(pen, X, Y - 10, X, Y + 20);
graphics.DrawLine(pen, X - 15, Y, X + 15, Y);
graphics.DrawLine(pen, X, Y + 20, X - 15, Y + 35);
graphics.DrawLine(pen, X, Y + 20, X + 15, Y + 35);
// rectangle around actor
graphics.DrawRectangle(pen, (X - 20), (Y - 30), 40, 80);
// setup font
var stringFont = new Font("Arial", 10);
// measure string
var textWith = graphics.MeasureString(Name, stringFont).Width;
// label
var label = new Label();
var actorText = (_id < 10 ? "0" : "") + _id.ToString() + "-" + Name;
label.Text = actorText;
label.Location = new Point(X - (Convert.ToInt32(textWith)/2), Y + 40);
label.AutoSize = true;
label.BorderStyle = BorderStyle.FixedSingle;
_panel.Controls.Add(label);
}
class UseCase
{
private static int _id;
private Panel _panel;
private string _name;
private int _x;
private int _y;
public UseCase(Panel panel, string name, int x, int y)
{
_id++;
_panel = panel;
_name = name;
_x = x;
_y = y;
}
public void DrawUseCase()
{
var graphics = _panel.CreateGraphics();
var pen = new Pen(Color.Black, 2);
graphics.DrawEllipse(pen, _x , _y , 120, 50);
// setup font
var stringFont = new Font("Arial", 10);
// measure string
var textWith = graphics.MeasureString(_name, stringFont).Width;
// label
var label = new Label();
var useCaseText = (_id < 10 ? "0" : "") + _id.ToString() + "-" + _name;
label.Text = useCaseText;
label.Location = new Point(_x - (Convert.ToInt32(textWith) / 2) + 60, _y + 20);
label.AutoSize = true;
label.BorderStyle = BorderStyle.FixedSingle;
_panel.Controls.Add(label);
}
}
Github存储库: https://github.com/JimVercoelen/use-case-helper
谢谢
答案 0 :(得分:3)
您的代码有几个问题,一旦您学会如何在winforms中正确正确,所有问题都会消失!
有许多帖子描述了它,但您需要了解的是,您确实有这两个选项:
将绘制到控件的表面上。这就是你所做的,但你做错了。
将绘制到控件中显示的Bitmap
,例如Picturbox
&#39; s Image
或{{1 } {&#39; s Panel
。
选项二最适合慢慢加起来并且不需要一直纠正的图形。
选项一最适合交互式图形,用户可以移动很多东西或更改或删除它们。
您还可以通过在BackgroundImage
中缓存绘制的图形来混合选项。
由于您开始绘制到曲面上,让我们看看您应该如何正确地进行绘制:
黄金法则:所有绘图都需要在对照的Bitmap
事件中完成,或者从那里开始,只使用Paint
事件&#39; {{ 1}}对象!
相反,您使用Paint
创建了e.Graphics
对象。这几乎总是错误。
上述规则的一个结果是Graphics
事件需要能够绘制到目前为止用户创建的所有对象。因此,您需要拥有类级别列表来保存必要的数据:control.CreateGraphics
和Paint
。然后它可以做一个
List<ActorClass>
等
是的,这完全重绘一切看起来像是浪费但它不会成为一个问题,直到你需要绘制数百个对象。
但如果你不这样做,你画的东西都不存在。
通过运行现有代码并执行List<UseCaseClass>
序列来测试。噗,所有的图画都没了..
现在回到原来的问题:如何选择例如演员?
这真的很简单,因为你可以迭代foreach(ActorClass actor in ActorList) actor.drawActor(e.Graphics)
事件中的Minimize/Maximize
(不要使用ActorList
事件,因为它缺少必要的参数):
MouseClick
这是一个简单的实现;您可能希望针对重叠对象的情况对其进行优化..
现在你可以做一些事情,比如改变矩形的颜色或在Click
变量中添加对象的引用。
每当您对要绘制的事物列表进行任何更改时,例如添加或删除对象或移动它或更改任何(可见)属性,都应通过调用{{foreach (ActorClass actor in ActorList)
if (actor.rectangle.Contains e.Location)
{
// do stuff
break;
}
事件触发更新。 1}}。
顺便说一下:您在标题中询问了currentActor
,但在代码中仅使用了Paint
。建议使用Invalidate
,因为它是 doublebuffered ,并且还结合了两个位图,以便您同时使用缓存PictureBox
和{{1}也许是一篇好文章..
据我所知,到目前为止您的代码缺少必要的类。当你编写它们时,添加一个Draw例程和对你添加的Panel
的引用,或者只是使用PictureBox
自己绘制文本..
<强>更新强>
在查看您的项目之后,这里会进行最小化更改以使绘图工作:
Image
从不尝试缓存BackgroundImage
对象!
Label
同样的;将真正的DrawString
对象传递给绘图例程!
// private Graphics graphics; // delete!!
我们不是直接调用例程,而是触发Graphics
事件,然后可以将一个好的private void pl_Diagram_Paint(object sender, PaintEventArgs e)
{
pen = new Pen(Color.Black, 1);
DrawElements(e.Graphics); // pass out the 'good' object
//graphics = pl_Diagram.CreateGraphics(); // delete!
}
对象传递给它。
Graphics
我们收到Graphics对象并将其传递给..
// actor
if (rb_Actor.Checked)
{
if (e.X <= 150)
{
var actor = new Actor(name, e.X, e.Y);
_actors.Add(actor);
pl_Diagram.Invalidate(); // trigger the paint event
//DrawElements();
}
}
// use case
if (rb_Use_Cases.Checked)
{
var useCase = new UseCase(name, e.X, e.Y);
_useCases.Add(useCase);
pl_Diagram.Invalidate(); // trigger the paint event
//DrawElements();
}
和
Paint
经过这些改动后,绘图仍然存在。
仍建议您使用Graphics
替换public void DrawElements(Graphics graphics)
{
foreach (var actor in _actors)
{
DrawActor(graphics, actor);
}
foreach (var useCase in _useCases)
{
DrawUseCase(graphics, useCase);
}
}
,以避免在重绘过程中出现闪烁现象。 (或者用双缓冲的Panel子类替换。)