如何使用Windows表单创建和连接自定义用户按钮/控件与线条

19

我正在尝试创建一些自定义按钮或用户控件,如所示的GUI。功能应该如下:

图形或配置是通过图形方式创建的。

控件可以从工具栏拖动或通过右键单击/下拉菜单插入。

通过从一个控件拖动到另一个控件,它们应该通过线连接起来。

切换应将视图从带有选项的控件转换为简单视图

GUI视图-带有选项的控件: GUI view controls with options

GUI视图-最小化: enter image description here

在Windows表单中,我可以使用哪些功能来创建连接线?

如果它们是使用绘制线条的功能创建的,如何确保控件与线对齐?..

我正在使用Visual Studio 2010 Express进行C#编程。


不同颜色的线条表示不同的关系。它们可能可以通过CTRL +拖动来创建? - Eirik
抱歉..我想我把它们看作相关的,问题更多是:我如何实现“所有这些”..感谢有关UserControl的提示-我会研究一下。它们可以切换以允许最小化版本吗?... - Eirik
2
兄弟,你正在为自己设置很多痛苦。你为什么要在winforms中做这个?你考虑过使用任何当前(<10年),更快,更可扩展,基于向量的XAML窗口UI技术吗?我可以在20分钟内使用WPF创建它。 - Federico Berasategui
好的。这是否有意义?或者我应该尝试在WPF中创建整个GA的前端?目前GUI看起来像这样链接,而所讨论的房间配置将位于其中的一个选项卡部分... - Eirik
1
如果你问我,我会很明确地告诉每个人,WinForms 是完全无用的,它不支持任何东西,并且无论项目的规模或所需功能如何,它都不是一个选项。看看我在3小时内制作的这个示例。链接 - Federico Berasategui
显示剩余5条评论
2个回答

33

好的。这是我为类似需求创建的示例的轻微修改

我的意图是表明,对于任何需要严肃用户界面的人来说,winforms已不再是一个选项。原始示例是在3小时内创建的。

您可能会惊讶地发现,包含所有这些项目(节点和连接器)的容器实际上是ListBox

值得注意的事情:

  • "NodeXX"文本包含在Thumb控件中,该控件使得点击和拖动成为可能。
  • 连接器也可以被选中,并在选中时显示漂亮的动画。
  • 左侧面板允许编辑当前选定对象的值。
  • UI的功能与组成它的数据完全解耦。因此,所有这些节点和连接器都是简单的类,具有简单的intdouble属性,可以从DB或其他任何数据源加载/保存。
  • 如果您不喜欢绘制节点和连接器的单击序列方式,则可以完全根据您的需求进行适应。
  • WPF规则。

编辑:

第二个版本,这次更接近您的原始截图:

enter image description here

enter image description here

  • 我将SnapSpot 的概念加入了其中。 这些是您在节点周围看到的小红色半圆形,实际上是Connector绑定的位置。
  • 我还更改了Connector DataTemplate,使用基于QuadraticBezierSegment的模板

Connector.Start.Location,
Connector.MidPoint, and 
Connector.End.Location 

这使得曲线可以用作连接器,而不仅仅是直线。

  • 当你选择(点击)一个Connector时,会出现一个小红色正方形的Thumb(在截图中可见),它允许你移动曲线的MidPoint
  • 当鼠标悬停在左侧面板下的“Mid Point”文本框上时,您也可以通过滚动鼠标滚轮来操作该值。
  • “Collapse All” CheckBox允许在完整框和小框之间切换,如截图所示。
  • SnapSpot在0到1之间具有OffsetX OffsetY,对应于它们相对于父Node的位置。这些不限于4个,实际上每个Node都可能有任意数量的SnapSpot
  • ComboBoxesButtons没有功能,但只需要在Node类中创建相关属性和Commands,并将其绑定到那里。

编辑2:

使用更好的版本更新的下载链接。

编辑10/16/2014:由于很多人似乎对此感兴趣,我将源代码上传到了GitHub上。


1
三个小时?!我真的不明白这怎么能成为支持WPF的论据。在Paint事件处理程序中编写绘制两点之间Bezier曲线的代码只需要不到一个小时。也许我没有仔细阅读问题,但看起来这就是所需的全部内容。我应该把我的地址发给哪里以收到退款支票呢?:-p - Cody Gray
2
@CodyGray,你有打开带有示例的压缩文件吗?请运行它,然后告诉我你能否在WinForms中更快地完成相同的任务。如果你能做到,我会把我的整个薪水都给你(不过并不是很多)。 - Federico Berasategui
1
@HighCore 不错的项目。我也喜欢你的其他项目。非常酷的东西。:o) - DHN
4
这是为什么WPF > WinForms的一个很好的例子。太棒了 @HighCore! - René
1
很遗憾,上面的链接已经失效了。请问您能否再次上传它? - Rolfi
显示剩余14条评论

0

我猜这是一个图形类型的问题。节点是房间,边是连接房间的线。你可以引入另一个类(比如连接类),描述节点如何连接到边。例如,你的走廊连接到卧室,不一定要使用直线。Graphics.DrawBezier可以绘制曲线,但需要一个点数组。这就是连接类发挥作用的地方。一些代码可能会有所帮助...

   class Room
   {
     public Room(String name, Point location);
     public void Draw(Graphics g);
   }

   class Connection
   {
     public void Add(Point ptConnection);
     public void Add(Point[] ptConnection);

     // Draw will draw a straight line if only two points or will draw a bezier curve
     public void Draw(Graphics g);
   }

   class House // basically a graph
   {
     public void Add(Room room);
     public void AddRoomConnection(Room r1, Room r2, Connection connector);

     // draw, draw each room, then draw connections.
     public void Draw(Graphics g);
   }

   void Main()
   {
      House myHouse = new House();
      Room hall = new Room("Hall", new Point(120,10);
      Room bedroom1 = new Room("Bedroom1", Point(0, 80));
      Connection cnHallBedroom = new Connection();
      cn.Add(new Point());  // add two points to draw a line, 3 or more points to draw a curve.
      myHouse.AddRoomConnection(hall, bedroom1, cnHallBedroom);
   }

这是基本的方法,也许不是最好的,但可能作为一个起点。


嗨,卡尔。谢谢你的代码。它有点像图形类型或空间语法。我将它实现为一个类,该类将自己作为子项列表保存,并且到其他节点的连接也在列表中。如果存在子项,递归函数会遍历子项。效果很好。现在,我正在寻找一种方法来以图形方式表示这些图形或者以图形方式创建它们。如何将这些控件拖动到画布上并在它们之间创建/拖动线条连接? - Eirik
1
嗨,Erik,我只是猜测,如果我错了,请原谅。
  1. 有一个包含可以使用的房间的侧边栏。
  2. 允许用户先单击第一个房间,然后单击第二个房间,这是您可以设置连接参数的地方。
  3. 如果用户单击一个房间和第二个房间,则创建一个单一的航点(绘制一条直线)。
  4. 可能允许用户单击连接以添加其他航点。 这将绘制贝塞尔曲线。
- user2225284
谢谢你猜测Karl :)..我想让房间被拖到画布上,自由移动,然后通过拖动它们之间的线连接。这也可以通过在其他地方拖动线条来重新排列。例如Lucidcharts的工作方式,请看这里(www.lucidchart.com)。因此,通过首先单击一个房间,然后单击下一个房间等来创建图表是很困难的。它可以用于创建初始图表,但无法重新排列它。房间也可以只是一个控件,其标题为可编辑的TextInput?.. - Eirik
通常我很擅长猜测 :-) 是的,我会将房间作为单个用户控件来创建,您可以指定一个名称。当然,您也可以为不同的房间子类化用户控件。我认为在此处的关键是创建新的房间并将其添加到“房屋类”中。如何连接它们完全取决于用户,可以使用单行、贝塞尔曲线等方式。这就是连接类的作用。两点之间是一条直线,多于两点则是曲线。正如我所说,这是一种基本方法。 - user2225284

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接