【ArcGIS Pro二次开发】(45):手搓一个工具执行进度框

news2024/12/29 13:25:40

我在之前做的工具中,UI这部分基本没怎么深入,都是直接用的现成的控件。

其中有一个问题比较突出,就是没有工具执行的进度框提示。曾经也用过系统自带的信息提示框和进度条,但太简陋,确实不好用。于是就想抄一个进度框来用,自然而然想到了ArcGIS中地理工具执行时显示的进度框:

这里做一个简单版的,够用就行(其实是目前只会这些)。


一、要实现的功能

进度框无法单独使用,这里结合之前做的一个【面要素拓扑】一起使用。

如上图所示,选择一个面要素,右键点击,在弹出的列表中点击【面要素拓扑】按钮,即可对所选要素进行处理,同时弹出一个进度提示框,实时显示目前的进程和用时。

可以看出,已经和ArcGIS中地理工具的进度框有几分相似。

其实,显示用时这一点不仅对用户有帮助,对开发、测试同样是很有用的,有利于不断优化你的代码,提高代码执行效率。毕竟一个简单的功能老是显示耗时几分钟,你也很难受。


二、实现流程

1、控件选择

首先,需要确定进度框用什么来做,可以用Form,但最终还是选择了ArcGIS ProWindow控件,毕竟已经给我们集成了更多基础性功能,用起来应该更方便。

新建一个ArcGIS ProWindow,主要的控件就2个,【ProgressBar】进度条和【RichTextBox】富文本。

【ProgressBar】用来显示当前执行进度,【RichTextBox】用来显示提示信息,包括正常流程信息和错误信息。这个使用【RichTextBox】而不是更常用的【TextBox】是考虑到显示内容需要不同字体和颜色,才能显示更丰富的文本内容,【TextBox】是无法做到的。

至于打开窗口的方法,其实【ArcGIS ProWindow】已经给我们写好了,正常创建【ArcGIS ProWindow】控件的时候,就会一起创建一个【Show*****.cs】,里面就有打开窗口的代码:

        private ProcessWindow _processwindow = null;

        protected override void OnClick()
        {
            if (_processwindow != null)
                return;
            _processwindow = new ProcessWindow();
            _processwindow.Owner = FrameworkApplication.Current.MainWindow;
            _processwindow.Closed += (o, e) => { _processwindow = null; };
            _processwindow.Show();
        }

把这部分代码抄到工具执行代码段里就行了。

2、【ArcGIS ProWindow】方法

因为上面的信息都是在【ArcGIS ProWindow】控件里显示的,所以方法都得写在ProcessWindow.xaml.cs里:

这里主要需要定义3个方法:【更新进度条、添加信息文本和添加耗时文本】。

1)更新进度条

        // 变更进度条的进度【100%】
        public void AddProcess(int percent)
        {
            System.Windows.Application.Current.Dispatcher.Invoke(() =>
            {
                pb.Value += percent;
            });
        }

这个比较简单,只要修改进度条控件的Value值即可。不过需要注意的是,这里操作都是在UI线程上执行,不能放在主线程里,所以需要在【Dispatcher.Invoke】下执行。

2)添加信息文本

添加信息文本需要考虑到文本的颜色和字体,所以除了文本,还添加了2个颜色和字体2个参数,并且设置了默认值,大部分情况下其实用默认值就行,有需要才修改参数:

        // 添加信息框文字
        public void AddMessage(string add_text, SolidColorBrush solidColorBrush = null)
        {
            System.Windows.Application.Current.Dispatcher.Invoke(() =>
            {
                if (solidColorBrush == null)
                {
                    solidColorBrush = Brushes.Black;
                }
                // 创建一个新的TextRange对象,范围为新添加的文字
                TextRange newRange = new TextRange(tb_message.Document.ContentEnd, tb_message.Document.ContentEnd)
                {
                    Text = add_text
                };
                // 设置新添加文字的颜色
                newRange.ApplyPropertyValue(TextElement.ForegroundProperty, solidColorBrush);
                // 设置新添加文字的样式
                newRange.ApplyPropertyValue(TextElement.FontStyleProperty, FontStyles.Normal);
            });
        }

3)添加耗时文本

耗时信息需要计算,在工具开始执行的时候在保存一下开始时间【time_base】,然后将其作为输入参数参与计算。将新的当前时间减去【time_base】即为耗时,然后作为为文字信息写入文本框,文本颜色设为灰色,文本字体设为斜体,这部分就直接固定,不再给参数。

        // 添加信息框文字_时间
        public void AddTime(DateTime time_base)
        {
            System.Windows.Application.Current.Dispatcher.Invoke(() =>
            {
                DateTime time_now = DateTime.Now;
                TimeSpan time_span = time_now - time_base;
                string time_total = time_span.ToString()[..time_span.ToString().LastIndexOf(".")];
                string add_text = "………………用时" + time_total + "\r";

                // 创建一个新的TextRange对象,范围为新添加的文字
                TextRange newRange = new TextRange(tb_message.Document.ContentEnd, tb_message.Document.ContentEnd)
                {
                    Text = add_text
                };
                // 设置新添加文字的颜色为灰色
                newRange.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Gray);
                // 设置新添加文字的样式为斜体
                newRange.ApplyPropertyValue(TextElement.FontStyleProperty, FontStyles.Italic);
            });
        }

4)组合方法

上述三个主要方法写完,其实还可以更进一步,因为正常情况下,在某一个节点,通常都不是只调用一个方法,而是多个一起调用,比如在添加文本信息的时候,同时更新进度条和上一个步骤的耗时。所以这里可以做一个方法的组合,调用的时候就可以只调用这个方法:

        // 综合显示进度【AddTime+AddMessage+AddProcess】
        public void AddProcessMessage(int percent, DateTime time_base, string add_text, SolidColorBrush solidColorBrush = null)
        {
            AddProcess(percent);
            AddTime(time_base);
            AddMessage(add_text, solidColorBrush);
        }

        // 综合显示进度【AddMessage+AddProcess】
        public void AddProcessMessage(int percent, string add_text, SolidColorBrush solidColorBrush = null)
        {
            AddProcess(percent);
            AddMessage(add_text, solidColorBrush);
        }
3、在主程序中调用【ArcGIS ProWindow】方法

直接先上完整代码:

        // 定义一个进度框
        private ProcessWindow processwindow = null;
        string tool_name = "面要素拓扑检查";

        protected override async void OnClick()
        {
			try
			{
                // 打开进度框
                ProcessWindow pw = ToolManager.OpenProcessWindow(processwindow, tool_name);
                DateTime time_base = DateTime.Now;
                pw.AddMessage("开始执行" + tool_name + "工具…………" + time_base + "\r", Brushes.Green);

                var map = MapView.Active.Map;
                // 获取默认数据库
                var gdb = Project.Current.DefaultGeodatabasePath;
                // 获取工程默认文件夹位置
                var def_path = Project.Current.HomeFolderPath;
                // 获取图层
                FeatureLayer ly = MapView.Active.GetSelectedLayers().FirstOrDefault() as FeatureLayer;
                // 如果选择的不是面要素或是无选择,则返回
                if (ly.ShapeType != esriGeometryType.esriGeometryPolygon || ly == null)
                {
                    pw.AddMessage("错误!请选择一个面要素!", Brushes.Red);
                    return;
                }
                
                string db_name = "Top2Check";    // 要素数据集名
                string fc_name = "top_fc";        // 要素名
                string top_name = "Topology";       // TOP名
                string db_path = gdb + "\\" + db_name;    // 要素数据集路径
                string fc_path = db_path + "\\" + fc_name;         // 要素路径
                string top_path = db_path + "\\" + top_name;         // TOP路径

                string err_fc = @"检查结果";
                string err_field = @"错误说明";

                await QueuedTask.Run(() =>
                {
                    pw.AddProcessMessage(10, "创建检查用的数据库和拓扑");

                    //获取图层的坐标系
                    var sr = ly.GetSpatialReference();
                    //在数据库中创建要素数据集
                    Arcpy.CreateFeatureDataset(gdb, db_name, sr);
                    // 将所选要素复制到创建的要素数据集中
                    Arcpy.CopyFeatures(ly.Name, fc_path);
                    // 新建拓扑
                    Arcpy.CreateTopology(db_path, top_name);
                    // 向拓扑中添加要素
                    Arcpy.AddFeatureClassToTopology(top_path, fc_path);
                    // 添加拓扑规则【重叠】
                    Arcpy.AddRuleToTopology(top_path, "Must Not Overlap (Area)", fc_path);
                    // 添加拓扑规则【空隙】
                    Arcpy.AddRuleToTopology(top_path, "Must Not Have Gaps (Area)", fc_path);

                    pw.AddProcessMessage(20, time_base, "生成重叠错误");

                    // 验证拓扑
                    Arcpy.ValidateTopology(top_path);
                    // 输出TOP错误
                    Arcpy.ExportTopologyErrors(top_path, gdb, "TopErr");

                    pw.AddProcessMessage(20, time_base, "生成空隙错误");

                    // 生成空隙
                    ToolManager.GetCave(fc_path, gdb + @"\" + err_fc);
                    // 添加说明字段
                    Arcpy.AddField(gdb + @"\" + err_fc, err_field, "TEXT");
                    // 空隙错误说明赋值
                    Arcpy.CalculateField(gdb + @"\" + err_fc, err_field, "'存在空隙'");
                    // 合并错误
                    Arcpy.Append(gdb + @"\TopErr_poly", gdb + @"\" + err_fc);
                    // 加载错误面图层
                    ToolManager.AddFeatureLayerToMap(gdb + @"\" + err_fc);

                    pw.AddProcessMessage(20, time_base, "生成错误标记");

                    // 重叠错误说明赋值
                    FeatureLayer init_layer = map.FindLayers(err_fc)[0] as FeatureLayer;
                    using (ArcGIS.Core.Data.Table table = init_layer.GetTable())
                    {
                        using (RowCursor rowCursor = table.Search(null, false))
                        {
                            TableDefinition tableDefinition = table.GetDefinition();
                            while (rowCursor.MoveNext())
                            {
                                using (Row row = rowCursor.Current)
                                {
                                    // 获取value
                                    var va = row[err_field];
                                    // 赋值
                                    if (va is null)
                                    {
                                        row[err_field] = "存在重叠面";
                                    }
                                    row.Store();
                                }
                            }
                        }
                    }
                    // 删除多余字段
                    Arcpy.DeleteField(err_fc, "ORIG_FID");

                    pw.AddProcessMessage(20, time_base, "应用错误图层的显示符号");

                    // 复制图层符号
                    string copy_lyrx = def_path + @"\检查结果.lyrx";
                    ToolManager.CopyResourceFile(@"CCTool.Data.Layers." + @"检查结果.lyrx", copy_lyrx);
                    // 应用图层符号
                    Arcpy.ApplySymbologyFromLayer(err_fc, copy_lyrx);

                    // 删除中间要素
                    List<string> list_del = new List<string>() { "TopErr_point", "TopErr_line", "TopErr_poly" };
                    foreach (var fc in list_del)
                    {
                        Arcpy.Delect(gdb + @"\" + fc);
                    }
                    // 删除数据集和符号图层
                    Arcpy.Delect(db_path);
                    File.Delete(copy_lyrx);

                    pw.AddProcessMessage(20, time_base, "工具运行完成!!!", Brushes.Blue);
                });
            }
			catch (Exception ee)
			{
                MessageBox.Show(ee.Message + ee.StackTrace);
				throw;
			}
        }

首先按上面【控件选择】那一节中的代码,先打开提示框。

在工具刚开始执行的时候,先生成一个初始时间,并把开始执行的信息和初始时间都添加到文本框里。

// 打开进度框
ProcessWindow pw = ToolManager.OpenProcessWindow(processwindow, tool_name);
DateTime time_base = DateTime.Now;
pw.AddMessage("开始执行" + tool_name + "工具…………" + time_base + "\r", Brushes.Green);

然后在每一个你认为需要添加信息的节点,直接调用上面写好的方法即可,如:

pw.AddProcessMessage(20, time_base, "生成重叠错误");

需要注意进度条的满值是100,这个需要自己协调好。


三、工程文件分享

 最后,放上工程文件的链接:

PrcessingFrameicon-default.png?t=N5K3https://pan.baidu.com/s/12b74CXMIs9aBJaFq_QB1fg?pwd=qz8t

PS:可以直接点击...bin\Debug\net6.0-windows\下的.esriAddinX文件直接安装。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/710945.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 读文件 - readahead预读算法

顺序读场景 intmain{charc[ 4096];intin -1;in open( "news.txt", O_RDONLY);intindex 0;while(read(in, &c, 4096) 4096){printf( "index: %d,len: %ld.\n",index, strlen(c));memset(c, 0, sizeof(c));index;} 数据结构 /** Track a single fi…

CentOS7 静默方式安装 Oracle19C

CentOS7 静默方式安装 Oracle19C 操作系统&#xff1a;CentOS7 Oracle&#xff1a; 19C 安装常用工具和依赖 yum -y install vim tar net-tools wget perl python3 readline* deltarpm python-deltarpm \zip unzip bc compat-libcap1* compat-libcap* binutils compat-libstdc…

最近的感悟与总结

目录 一、判别填鸭、与被填鸭的思考讲解人&#xff1a;听者&#xff1a; 二、最近感悟&#xff1a;三、再来三道数学题吧&#xff1a;四、总结 一、判别填鸭、与被填鸭的思考 讲解人&#xff1a; 1.是否在讲解过程中增加了知识认识的维度&#xff1f;(具体是什么&#xff0c;…

08_Linux按键输入

目录 Linux下按键驱动原理 修改设备树文件 添加KEY设备节点 按键驱动程序编写 编写测试APP 运行测试 Linux下按键驱动原理 按键驱动和LED驱动原理上来讲基本都是一样的,都是操作GPIO,只不过一个是读取GPIO 的高低电平,一个是从GPIO输出高低电平。实现按键输入,在驱动程序…

nginx的安装与自启动配置

1. nginx源码下载 nginx源码下载 2. nginx编译安装 2.1 解压安装包 tar -zxvf nginx-1.24.0.tar.gz2.2 编译安装 cd nginx-1.24.0 ./configure make make install执行./configure时可能出现如下的error&#xff0c;需要安装依赖库&#xff1a; 缺少pcre库 下载pcre安装包…

链码的安装、实例化、查询、调用

目录 1、首先保证网络已经处于启动状态 2、进入CLI容器 3、检查当前节点已经加入到哪些通道中&#xff08;刚进来&#xff0c;默认是 peer0.example.com&#xff09; 链码的安装 1、检查通道名称是否设置正确 2、使用install安装链码 3、实例化链码 4、查詢链码 发起交易 …

English Learning - L3 作业打卡 Lesson7 Day52 2023.6.27 周二

English Learning - L3 作业打卡 Lesson7 Day52 2023.6.27 周二 引言&#x1f349;句1: And that is when it dawned on me that I didn’t have to be 5,5 ft. anymore.成分划分弱读连读爆破语调 &#x1f349;句2: I could be as tall as I wanted, or as short as I wanted …

【电子学会】2023年05月图形化三级 -- 躲避陨石

文章目录 躲避陨石1. 准备工作2. 功能实现3. 设计思路与实现&#xff08;1&#xff09;角色、舞台背景设置a. 角色设置b. 舞台背景设置 &#xff08;2&#xff09;脚本编写a. 角色&#xff1a;Rocketshipb. 角色&#xff1a;Ball 4. 评分标准5. 知识块 躲避陨石 飞船在陨石乱飞…

MySQL数据库第一课 ---------安装

作者前言 欢迎小可爱们前来借鉴我的gtiee秦老大大 (qin-laoda) - Gitee.com 目录 虚拟环境虚拟环境 安装虚拟机 自主安装 简易安装 ———————————————————————————————————————— 虚拟环境虚拟环境 我们现在运行代码的环境是在 PyCharm…

大型语言模型作为属性化训练数据生成器

大型语言模型作为属性化训练数据生成器&#xff0c;提出一种使用多样化属性提示的数据生成方法&#xff0c;可以生成具有多样性和属性的训练数据&#xff0c;从而提高了模型的性能和数据生成的效率。 动机&#xff1a;大型语言模型(LLM)最近被用作各种自然语言处理(NLP)任务的…

从零开始——腾讯云服务器安装运行部署教程

一、腾讯云 1、购买腾讯云服务器 现在腾讯云服务器有优惠活动&#xff08;大家可以在网上搜索各个服务器的优惠活动&#xff0c;有很多&#xff09; 活动链接&#xff1a;上云精选_云服务器秒杀_开发者上云推荐-腾讯云 (tencent.com) 这里我选2G/2核/4M/50G轻量级服务器 这…

Linux基础服务6——Apache

文章目录 一、基本了解1.1 自带工具1.2 服务配置文件1.3 访问控制法则1.4 web相关的命令1.4.1 curl命令1.4.2 httpd命令 二、安装配置2.1 安装服务2.2 访问网页2.3 虚拟主机配置2.3.1 相同ip&#xff0c;不同端口2.3.2 相同端口&#xff0c;不同ip2.3.3 域名访问 三、https3.1 …

深度剖析 Linux 伙伴系统的设计与实现

目录 伙伴系统的核心数据结构 总结&#xff1a; 到底什么是伙伴 伙伴系统的内存分配原理 伙伴系统的内存回收原理 伙伴系统的实现 从 CPU 高速缓存列表中获取内存页 伙伴系统的核心数据结构 如上图所示&#xff0c;内核会为 NUMA 节点中的每个物理内存区域 zone 分配一个…

《计算机网络--自顶向下方法》第四章--网络层:数据平面

4.1网络层概述 每台路由器的数据平面的主要作用是从其输入链路向其输出链路转发数据报&#xff1b;控制平面的主要作用是协调这些本地路由器转发动作&#xff0c;使得数据报沿着源和目的地主机之间的路由器路径进行端到端传送 路由器具有截断的协议栈&#xff0c;即没有网络层…

[RISC-V]Milk-V开发板 i2c测试oled及波形输出

I2C3 引脚图 修改i2c3复用功能 build\boards\cv180x\cv1800b_sophpi_duo_sd\u-boot\cvi_board_init.c //I2C3 pin6 7 PINMUX_CONFIG(SD1_CMD, IIC3_SCL); PINMUX_CONFIG(SD1_CLK, IIC3_SDA);扫描I2C3上的设备 [rootcvitek]~# i2cdetect -y -r 3 0 1 2 3 4 5 6 7 8 9 a b c …

大数据Doris(五十四):BACKUP数据备份原理和语法

文章目录 BACKUP数据备份原理和语法 一、BACKUP数据备份原理 1、快照及快照上传 2、元数据准备及上传 二、BACKUP数据备份语法 BACKUP数据备份原理和语法 通过Doris数据导出的各种方式我们可以将Doris中的数据进行备份&#xff0c;除了export方式之外&#xff0c;Doris 还…

高压线路零序电流方向保护程序逻辑原理(二)

二、零序电流方向保护的采样中断服务程序 零序电流方向保护与其他微机保护的采样中断服务程序相同&#xff0c;均有电压求和自检和电流求和自检及相电流差突变量起动元件DI1。零序电流方向保护的采样中断服务程序中最突出的问题是通过3U。突变量元件来实现闭锁保护&#xff0c…

使用Dependency Walker和Process Explorer排查程序缺少ucrtbase.dll等运行时库以及报0xC000007B错误问题总结

目录 1、问题描述 2、分析软件问题的常用分析工具 3、使用Dependency Walker排查启动程序时报找不到ucrtbase.dll、vcruntime140.dll等运行时库的问题 3.1、使用Dependency Walker查看exe程序的库依赖关系&#xff0c;排查找不到ucrtbase.dll、vcruntime140.dll库问题 3.2…

华为OD机试真题 Python 实现【相对开音节】【2022Q4 100分】,附详细解题思路

一、题目描述 相对开音节构成的结构为辅音元音&#xff08;aeiou&#xff09;辅音(r除外)e&#xff0c;常见的单词有life,time,woke,coke,joke,note,nose,communicate&#xff0c;use&#xff0c;gate&#xff0c;same&#xff0c;late等。 给定一个字符串&#xff0c;以空格…

关于 Camera 产品的功能分析

1、问题背景 通过最近做的一些项目&#xff0c;发现 Tuning 一款 Camera 产品前&#xff0c;要考虑到的事情有很多&#xff0c;不是简单的点亮&#xff0c;按要求调完效果就结束了。 从目前的经验来看&#xff0c;准备工作做的越充分&#xff0c;后期遇到的问题也就越少。本文…