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. 帝国CMS批量提取正文内容到简介

    最近接到一个帝国CMS模板改版项目,自带的数据可能是采集的,以前的简介字段内容只截取了60个字,新模板的简介60字符太少了,不美观,想让简介都截取200个字,怎么批量修改呢,文章太多了手动改肯定不行, ...

  2. Java的虚拟线程(协程)特性开启预览阶段,多线程开发的难度将大大降低

    高并发.多线程一直是Java编程中的难点,也是面试题中的要点.Java开发者也一直在尝试使用多线程来解决应用服务器的并发问题.但是多线程并不容易,为此一个新的技术出现了,这就是虚拟线程. 传统多线程的 ...

  3. 动手动脑3&课堂作业(四则运算与继承)

    先上结果 Java程序会先把所有的静态模块提取出来优先执行 四则运算主程序代码 1 import java.util.Scanner; 2 3 4 public class main { 5 publ ...

  4. 十分钟学会Golang开发gRPC服务

    gRPC是Google发起的一个开源RPC框架,使用HTTP/2传输协议,使用Protocol Buffers编码协议,相比RESTful框架的程序性能提高不少,而且当前流行的编程语言基本都已经支持. ...

  5. 使用GO语言通过Stream Load实现Doris数据导入

    Doris github地址欢迎加Star apache/incubator-doris: Apache Doris(Incubating) is an MPP-based interactive S ...

  6. 如何用C/C++实现去除字符串头和尾指定的字符

    编程时我们经常需要对字符串进行操作,其中有一项操作就是去除字符串的头(尾)指定的字符,比如空格.通常我们会使用封装好的库函数或者类函数的Trim方法来实现,如果自己动手写一个TrimHead和Trim ...

  7. 漏洞复现:MS10-046漏洞

    漏洞复现:MS10-046漏洞 实验工具1.VMware虚拟机2.Windows7系统虚拟机3.Kali 2021 系统虚拟机 1.在VMware中打开Windows7虚拟机和Kali 2021虚拟机 ...

  8. 基于DSP_CPLD_aP8942A_LM1791的语音控制

    语音驱动程序  drv_voice.c 语音服务程序  srv_voice.c 1.先运行初始化函数,主要是设置初始音量,并建立一个软件定时器来,以10ms的周期来调用语音播放函数. 1 void s ...

  9. ucore lab1 操作系统启动过程 学习笔记

    开头赞美THU给我们提供了这么棒的资源.难是真的难,好也是真的好.这种广查资料,反复推敲,反复思考从通电后第一条代码搞起来理顺一个操作系统源码的感觉是真的爽. 1. 操作系统镜像文件ucore.img ...

  10. 隐藏浏览器header中X-Powered-By: PHP信息

    在php程序中,默认会在http请求响应头中输出php版本信息.如下: HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Date: Tue ...