DevExpress提供了一个比较强大的图形绘制工具,可以用于绘制各种图形,如流程图、组织机构图等等,本篇随笔介绍XtraDiagram.DiagramControl的使用,以及利用代码对其属性进行控制,以及利用图形模具的自定义操作,实现一些简单流程图形的绘制和处理。

DiagramControl是类似Visio的绘图控件,以前我2006年的就接触使用Visio的二次开发,当时开始还是利用VB6 + VIsio2003进行二次开发的,后来把它改良为C# + Visio进行二次开发,DiagramControl的对象模型很类似Visio的相关对象模型,如对于工具栏的形状,称之为模具(Stencil),Visio也是称之为Stencil, DiagramControl里面的很多接口名称依旧采用Stencil进行命名,因此估计也是借鉴了很多Visio的对象设计知识,如果您对Visio二次开发感兴趣,可以参考我的随笔文章《Visio二次开发》,里面有很多相关的内容。

而如果想了解这个控件的相关知识和使用,参考官网的案例和说明应该是比较好的教程(https://docs.devexpress.com/WindowsForms/118290/controls-and-libraries/diagrams/getting-started )。

1、DiagramControl控件的使用

DiagramControl是一个界面控件,类似Visio SDK里面的DrawingControl的存在,可以通过它进行图形的绘制,各种窗口的显示和隐藏,以及跟踪各种事件的处理。

DiagramControl控件拖动到窗体中后,会自动增加一些属性窗口,上排的绘图工具中的按钮是我添加的,用来测试该控件的一些属性的控制。

1)属性窗口的显示和隐藏(折叠)

这个通过控制diagramControl1.OptionsView.PropertiesPanelVisibility 属性就可以实现对这个属性窗口的控制了。

里面显示一些系统位置和内容信息,以及一些自定义信息的窗口,后面我会介绍如何自定义处理这些模具的属性。

通过按钮处理的代码,我们可以实现对这个窗口的显示或者隐藏处理。

//切换属性窗口的显示或关闭
var status = diagramControl1.OptionsView.PropertiesPanelVisibility;
diagramControl1.OptionsView.PropertiesPanelVisibility = (status == PropertiesPanelVisibility.Visible ? PropertiesPanelVisibility.Collapsed : PropertiesPanelVisibility.Visible);

2)模具形状窗口的显示或隐藏

模具形状的窗口,它是放在一个面板里面,我们只需要通过控制该面板的显示或者隐藏就可以了,如下代码所示。

//切换模具形状窗口的显示或关闭
var status = diagramToolboxDockPanel1.Visibility;
diagramToolboxDockPanel1.Visibility = (status == DevExpress.XtraBars.Docking.DockVisibility.Visible ? DevExpress.XtraBars.Docking.DockVisibility.Hidden : DevExpress.XtraBars.Docking.DockVisibility.Visible);

或者通过控件的Toolbar属性进行控制,一样的效果。

//切换模具形状窗口的显示或关闭
var status = this.diagramControl1.OptionsView.ToolboxVisibility;
this.diagramControl1.OptionsView.ToolboxVisibility = status == ToolboxVisibility.Closed ? ToolboxVisibility.Full : ToolboxVisibility.Closed;

3)放大缩小窗口的显示或者隐藏

同样我们也可以控制放大缩小窗口的显示或者隐藏,它也是图形绘制的一个常见的窗口。我们只需要判断或者设置diagramControl1.OptionsView.ShowPanAndZoomPanel 属性就可以了,如下代码所示。

//切换放大缩小窗口的显示或关闭
var status = diagramControl1.OptionsView.ShowPanAndZoomPanel;
diagramControl1.OptionsView.ShowPanAndZoomPanel = !status;

4)其他属性的处理

另外,我们可以通过控制一些属性,实现对标尺、网格、只读视图等模式进行控制。

//是否显示标尺
this.diagramControl1.OptionsView.ShowRulers = this.chkRuler.Checked;
//是否显示网格
this.diagramControl1.OptionsView.ShowGrid = this.chkGrid.Checked;
//是否只读视图
this.diagramControl1.OptionsProtection.IsReadOnly = this.chkReadOnly.Checked;

2、绘图的处理事件

在绘制图形的时候,一般来说我们可能需要切换点选模式或者连接线模式,因此可以通过它的属性ActiveTool进行设置。在点选模式下,可以对图形进行拖动、放大缩小、旋转等处理,连接线模式下,则会加亮连接点,便于自动绘制连接线。

private void btnPointerMode_Click(object sender, EventArgs e)
{
diagramControl1.OptionsBehavior.ActiveTool = diagramControl1.OptionsBehavior.PointerTool;
} private void btnConnectorMode_Click(object sender, EventArgs e)
{
diagramControl1.OptionsBehavior.ActiveTool = diagramControl1.OptionsBehavior.ConnectorTool;
}

当然,我们也可以通过对鼠标行为的分析来进行控制,如果鼠标悬停或者放置在图形上,就自动切换模式为连接线模式,否则为点选模式,那么只需要判断鼠标的移动行为即可自动处理,如下代码所示。

        /// <summary>
/// 实现对图形自动切换到连接点模式
/// </summary>
private void diagramControl1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
return; DiagramItem item = diagramControl1.CalcHitItem(e.Location);
if (item == null)
{
diagramControl1.OptionsBehavior.ActiveTool = diagramControl1.OptionsBehavior.PointerTool;
return;
}
else if (item is DiagramConnector)
{
diagramControl1.OptionsBehavior.ActiveTool = diagramControl1.OptionsBehavior.ConnectorTool;
return;
} Rect itemBounds = new Rect(new Point(item.Position.X, item.Position.Y), new Size(item.Width, item.Height));
PointFloat documentPoint = diagramControl1.PointToDocument(new PointFloat(e.Location));
DiagramHitInfo[] hitInfo = diagramControl1.CalcHitInfo(documentPoint);
if (itemBounds.Contains(new Point(documentPoint.X, documentPoint.Y)))
{
itemBounds.Inflate(-5, -5);
if (!itemBounds.Contains(new Point(documentPoint.X, documentPoint.Y)))
{
diagramControl1.OptionsBehavior.ActiveTool = diagramControl1.OptionsBehavior.ConnectorTool;
return;
}
}
diagramControl1.OptionsBehavior.ActiveTool = diagramControl1.OptionsBehavior.PointerTool;
}

另外图形的保存xml、PNG、PDF处理和加载代码如下所示。

/// <summary>
/// 保存XML和图片文件
/// </summary>
private void SaveXml()
{
var xml = Path.Combine(Application.StartupPath, "MyFlowShapes.xml");
diagramControl1.SaveDocument(xml); var pngFile = Path.Combine(Application.StartupPath, "MyFlowShapes.png");
diagramControl1.ExportDiagram(pngFile);
}
private void btnLoadXml_Click(object sender, EventArgs e)
{
var xml = FileDialogHelper.OpenXml();
if(!string.IsNullOrEmpty(xml))
{
diagramControl1.LoadDocument(xml);
}
}

最终案例的效果如下所示。

3、注册自定义的形状

在实际的图形绘制开发中,我们可以需要创建一些指定的形状模具,那么我们弄好后一般可以存放在XML中,然后进行加载到控件上来,如下代码就是注册自定义的形状的处理。

/// <summary>
/// 注册自定义的形状。
/// 自定义图形是以XML文件形式进行保存,图形需要按照规定XML格式进行绘制
/// </summary>
private void LoadShapes2()
{
var projectName = "SmallExampleDemo.Examples.XtraDiagram";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(projectName + ".CustomContainers.xml"))
{
var stencil = DiagramStencil.Create(MyStencilId, MyStencilName, stream, shapeName => shapeName);
DiagramToolboxRegistrator.RegisterStencil(stencil);
}
diagramControl1.SelectedStencils = new StencilCollection(MyStencilId);//(MyStencilId, BasicShapes.StencilId);
}

我们只需要设置选中的图形就可以了,其他有需要的可以从More Shapes中选择即可。

我们如果需要在属性窗口中显示自定义的属性,那么我们需要一些代码开发才能实现。

我们首先需要继承一个DiagramShape的子类,然后实现自己自定义的属性定义,如下代码所示。

对自定义属性的处理,需要在事件中实现

diagramControl1.CustomGetEditableItemProperties += DiagramControl_CustomGetEditableItemProperties;

通过对它进行判断可以实现自定义属性的显示处理

void DiagramControl_CustomGetEditableItemProperties(object sender, DiagramCustomGetEditableItemPropertiesEventArgs e)
{
if (e.Item is DiagramShapeEx)
{
e.Properties.Add(TypeDescriptor.GetProperties(typeof(DiagramShapeEx))["Status"]);
e.Properties.Add(TypeDescriptor.GetProperties(typeof(DiagramShapeEx))["TypeName"]);
}
}

然后我们可以注册创建自己的模具形状集合,如下代码所示。

/// <summary>
/// 创建自定义的模具
/// </summary>
/// <returns></returns>
DiagramStencil CreateCustomDrawShapesStencil()
{
var stencilId = "CustomedFlowShape";
var stencilName = "流程图";
var shapeSizeSmall = new Size(100, 37.5);
var shapeSize = new Size(100, 75); DiagramControl.ItemTypeRegistrator.Register(typeof(DiagramShapeEx));
var stencil = new DiagramStencil(stencilId, stencilName); //流程类型
stencil.RegisterTool(new FactoryItemTool("StartEnd", () => "流程开始", diagram => {
var shape = new DiagramShapeEx(BasicFlowchartShapes.StartEnd, "流程开始");
shape.Appearance.BackColor = Color.Red;
return shape;
}, shapeSizeSmall));
stencil.RegisterTool(new FactoryItemTool("Decision", () => "流程条件", diagram => {
var shape = new DiagramShapeEx(BasicFlowchartShapes.Decision, "流程条件");
shape.Appearance.BackColor = Color.FromArgb(199, 115, 1);//Color.Red;
return shape;
}, shapeSize));

这两个流程开始,流程条件,我们直接是从 BasicFlowchartShapes 集合中借用过来,构建自己的自定义对象的,默认创建的对象是方形的。

如果我们需要动态构建其他自定义类型,我们可以指定它的颜色等样式,从而构建不同类型的图形。

//循环添加相关流程节点
var procNames = new List<string> { "审批", "归档", "阅办", "会签", "领导批示分阅"};
//定义几个初始化颜色顺序
var colors = new List<Color> { Color.DeepSkyBlue, Color.ForestGreen, Color.Violet, Color.Yellow, Color.Blue, Color.Orange, Color.Indigo, Color.Purple, Color.Black, Color.Brown, Color.Pink };
int i = 0;
foreach (string name in procNames)
{
var shapeId = string.Format("Process_{0}", i++); stencil.RegisterTool(new FactoryItemTool(shapeId, () => name, diagram =>
{
var shape = new DiagramShapeEx(name, Status.Inactive);
var index = procNames.IndexOf(name);
var color = colors[index % 10];//Color.Red;
var fontColor = (color == Color.Yellow) ? Color.Black : Color.White; //没什么作用
//shape.ThemeStyleId = GetStyle(index); //从Accent1样式开始 DiagramShapeStyleId.Styles[index];//
shape.Appearance.BackColor = color;
shape.Appearance.BorderSize = 3;
shape.Appearance.Font = new Font("宋体", 12f, FontStyle.Bold);
shape.Appearance.ForeColor = fontColor;
return shape;
}, shapeSize));
}

这样就有不同颜色的图形对象了。

根据这些我们就可以绘制出自己的各种流程图了,并且也可以根据数据库的信息,进行动态绘制展示。

利用XtraDiagram.DiagramControl进行流程图形的绘制和控制的更多相关文章

  1. Quartz2D常见图形的绘制:线条、多边形、圆

    UI高级 Quartz2D http://ios.itcast.cn  iOS学院 掌握 drawRect:方法的使用 常见图形的绘制:线条.多边形.圆 绘图状态的设置:文字颜色.线宽等 图形上下文状 ...

  2. HTML5 Canvas ( 填充图形的绘制 ) closePath, fillStyle, fill

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. 利用canvas阴影功能与双线技巧绘制轨道交通大屏项目效果

    利用canvas阴影功能与双线技巧绘制轨道交通大屏项目效果 前言 近日公司接到一个轨道系统的需求,需要将地铁线路及列车实时位置展示在大屏上.既然是大屏项目,那视觉效果当然是第一重点,咱们可以先来看看项 ...

  4. 利用 Java 操作 Jenkins API 实现对 Jenkins 的控制详解

    本文转载自利用 Java 操作 Jenkins API 实现对 Jenkins 的控制详解 导语 由于最近工作需要利用 Jenkins 远程 API 操作 Jenkins 来完成一些列操作,就抽空研究 ...

  5. 【HarmonyOS】【xml】使用xml绘制视频播放控制栏

    本文记录HarmonyOS使用xml绘制视频播放控制栏 效果图如下 代码如下 点击查看代码 <?xml version="1.0" encoding="utf-8& ...

  6. 利用Microsoft VC++6.0 的MFC 的绘图工具实现简单图形的绘制

          MFC运算功能强大,拥有完备的绘图功能.       在Windows平台上,应用程序的图形设备接口(graphics device interface,GDI)被抽象为设备上下文(Dev ...

  7. 利用CSS3 clip-path裁剪各种图形。

    'clip-path'是css3的一个强大属性,我们可以利用它来绘制各种各样的图形,当然不只是这些,接下来一起看看它的强大功能吧. 首先介绍的是clip-path里面的polygon功能,我们可以通过 ...

  8. 利用matplotlib的plot函数实现图像绘制

    模式识别的一个实验,要求画出贝叶斯决策的图.这里我是利用python中的matplotlib库实现的图线的拟合.主要对于matplotlib的使用可以参照博客:webary 如果要绘制三维图像可以参考 ...

  9. Qt之图形(绘制漂亮的圆弧)

    简述 综合前面对二维绘图的介绍,想必我们对一些基本绘图有了深入的了解,下面我们来实现一些漂亮的图形绘制. 简述 圆形 效果 源码 弧形 效果 源码 文本 效果 源码 旋转 效果 源码 圆形 经常地,我 ...

随机推荐

  1. 论文翻译:2021_Towards model compression for deep learning based speech enhancement

    论文地址:面向基于深度学习的语音增强模型压缩 论文代码:没开源,鼓励大家去向作者要呀,作者是中国人,在语音增强领域 深耕多年 引用格式:Tan K, Wang D L. Towards model c ...

  2. Java学习day12

    Set集合特点:不能包含重复的元素:没有所有的方法,不能通过普通的for循环遍历集合 哈希值是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值,同一个对象多次调用hashCode()方法 ...

  3. 2021.08.10 Euler函数总结

    2021.08.10 Euler函数总结 知识: 记 φ(n) 表示在 [1,n] 中与 n互质的数的个数. 1.p为质数,则 \[φ(p^l)=p^l-p=p^{l-1}(p-1) \] 注:每p个 ...

  4. debian 11 开启 samba 共享文件夹

    安装 apt-get install   samba 安装时,提示搜索不到 此包时 解决办法1:apt-get update  更新源 解决办法2:更改镜像源,可以采用阿里云,网易云等镜像站里提供的镜 ...

  5. jdk1.8中hashmap的扩容resize

    当hashmap第一次插入元素.元素个数达到容量阀值threshold时,都会扩容resize(),源码: (假设hashmap扩容前的node数组为旧横向node数组,扩容后的node数组为新横向n ...

  6. Bugku CTF练习题---加密---聪明的小羊

    Bugku CTF练习题---加密---聪明的小羊 flag:KEY{sad23jjdsa2} 解题步骤: 1.观察题目,发现其中的信息 2.经过题目判断,得知该题属于栅栏密码的一种,并且介绍中表明了 ...

  7. LINUX系统虚拟机环境的安装

    安装VM和Centos Step 1 去BIOS里修改设置开启虚拟化设备支持 设置BIOS: 1.开机按F2.F12.DEL.ESC等进入BIOS,一般来说可以看屏幕的左下角有提示按键进入BIOS,进 ...

  8. 3D离线地图开发

    3D离线地图介绍(3D离线采用矢量数据作为地图基础,可保持地图数据最新) 一.开发中引用3D离线地图(可独立部署通过内外IP+端口进行访问,也可拷贝js库文件到项目中通过绝对路径访问) 1).离线AP ...

  9. 中间件漏洞之Apache

    中间件之Apache漏洞 我们常见的中间件有IIS.Apache.Nginx,其中Apache中间件有什么漏洞呢? Apache 解析漏洞: 漏洞原因:该解析漏洞属于用户配置问题(mime.types ...

  10. Blazor和Vue对比学习(基础1.6):祖孙传值,联级和注入

    前面章节,我们实现了父子组件之间的数据传递.大多数时候,我们以组件形式来构建页面的区块,会涉及到组件嵌套的问题,一层套一层.这种情况,很大概率需要将祖先的数据,传递给子孙后代去使用.我们当然可以使用父 ...