C#使用DataGridView模拟绘图

news2025/1/9 15:10:29

  接到一个需求,绘制一个水管线的图片,这种管线可以有12种分段方法,最后将这12种分段方法合并后在一条水管线上展示,要求:

  ⒈支持分段的属性展示;

  ⒉要求每个分段都能清晰展示,分段数在0(没有分段)~100之间,水管线长度不定;

  3、每个分段的属性都有值,可以更改,使用XML存储;

  4、不同材质管线使用不同的背景;

  5、根据不同的值,分段显示不同的颜色;

  6、支持鼠标滚动。

  因为需要快速完成,时间紧,第一时间想到使用C#的GDI+,可是在支持热点和放大与缩小时卡壳了,赶紧换了一种方法,制定一个自定义控件,在Panel上绘图,支持拖动,放大与缩小,可是总是会出现这样那样的问题,也想使用SVG,可是担心还是完不成,换成DataGridView,也算完成了,效果如下:

  经常在网上看到说在中国35岁以后就不能写代码了,感觉一个是热爱不够了,第二个可能是身体状况也不允许了。在一般企业中,也没有动力去费神像年轻时候完成一个程序,那个时候有冲劲和干劲,特别有耐心,希望得到别人的肯定与赞扬,现在50多岁了,没有动力了,想一想以前也是觉得可笑了。

  这个完成后,自定义一个控件就可以使用了。

   下面是完成的代码:

  定义:

        private static ToolTip toolTip = new ToolTip();
        // 定义一个List,用于存储点的信息
        List<float> Points = new List<float>() {0 };

        int MinColWidth=48;//定义最小分段对应的宽度
        float pipelineLength;//定义管线长度
        float RateF;//实际进行计算的比例 

  初始化:

            //初始化DataGridView
            dataGridView1.ColumnHeadersVisible = false;//隐藏标题栏          
            dataGridView1.CellBorderStyle = DataGridViewCellBorderStyle.None;//取消分割线
            //dataGridView1.ScrollBars = ScrollBars.Horizontal;
            dataGridView1.ScrollBars = ScrollBars.None;//去掉滚动条
            dataGridView1.AllowUserToAddRows = false;//不允许用户增加行
            dataGridView1.AllowUserToDeleteRows = false;//不允许用户删除行
            dataGridView1.AllowUserToResizeRows = false;//不允许用户改变行高度
            //dataGridView1.Columns.Add("Column1", "列1");
            dataGridView1.RowTemplate.Height = 32;//设置行高度
            //dataGridView1.Rows.Add();
            //dataGridView1.Rows[0].DefaultCellStyle.BackColor = Color.LightGray;
            dataGridView1.AllowUserToResizeColumns = false;//不允许用户改变栏宽度
            dataGridView1.RowHeadersVisible = false;//隐藏最前面的选择列            
            dataGridView1.Columns.Clear();//删除所有的列            
            dataGridView1.Columns.Add("Column1", "列1");//添加一列
            dataGridView1.Rows.Add();//添加一行
            dataGridView1.Rows[0].ReadOnly = true;//设置第一行为只读
            dataGridView1.Rows[0].DefaultCellStyle.BackColor = Color.LightGray;//设置行背景色           
            dataGridView1.Columns[0].Visible = false;//隐藏标题栏
                                                     
            dataGridView1.EditMode = DataGridViewEditMode.EditProgrammatically;// 设置编辑模式为EditProgrammatically
            //注册事件
            dataGridView1.CellPainting += dataGridView1_CellPainting;//单元格渲染
            dataGridView1.CellFormatting += dataGridView1_CellFormatting;
            dataGridView1.MouseEnter += dataGridView1_MouseEnter;//鼠标移入
            dataGridView1.MouseLeave += dataGridView1_MouseLeave;//鼠标离开
            dataGridView1.MouseWheel += dataGridView1_MouseWheel;//鼠标滚动
            dataGridView1.RowPrePaint+=dataGridView1_RowPrePaint;//行渲染

            //List<float> P = new List<float>() { 12, 27, 41, 73, 89, 105, 119, 126, 138, 166, 192, 208, 255, 377, 410, 439 };
            List<float> P = new List<float>() { 31, 25, 45,39, 73, 89, 115, 121 };
            UpdatePoints(P, 138);

  事件以及函数内容:

        void UpdatePoints(List<float> NewPoints,float NowDistance)
        {
            Points = NewPoints;
            pipelineLength = NowDistance;

            Points.Add(0);
            Points.Add(pipelineLength);
            Points.Sort();

            //计算实际的换算比例
            RateF = ((dataGridView1.Width - (Points.Count - 1) * 5) / pipelineLength);
            textBox1.Text += "计算比例:" + RateF.ToString() + Environment.NewLine;
            textBox1.Text += "管线长度:" + pipelineLength.ToString() + Environment.NewLine;
            textBox1.Text += "显示宽度:" + dataGridView1.Width.ToString() + Environment.NewLine;
            //得到最小的分段
            float MinSectionLength = CalculateMinDistance();
            textBox1.Text += "最小分段:" + MinSectionLength.ToString() + Environment.NewLine;
            if (MinSectionLength * RateF < MinColWidth)
            {
                //重新设定比例
                RateF = MinColWidth / MinSectionLength;
            }

            textBox1.Text += "最后比例:" + RateF.ToString() + Environment.NewLine;

            //更新DataGridView
            //设置每一列的宽度
            //foreach (int point in Points)
            for(int i=1; i<Points.Count; i++)
            {
               float ColWidth = (Points[i] - Points[i - 1]) * RateF;
                AddColumn(dataGridView1,"Section", (int)ColWidth,  Color.Brown, Color.Cyan, Points[i - 1], Points[i]);//增加分段
                if (i!=Points.Count-1)
                {
                    AddColumn(dataGridView1, "Dot", 5, Color.Brown, Color.Blue, Points[i - 1], Points[i]);//增加点
                }                
            }
        }

        // 动态增加列
        void AddColumn(DataGridView dataGridView, string StrType, int width, Color textColor, Color cellBackColor,float StartDot,float EndDot)
        {
            DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
            column.Width = width;
            //column.HeaderText = text;
            column.DefaultCellStyle.ForeColor = textColor;
            column.DefaultCellStyle.BackColor = cellBackColor;

            // 为每一列添加属性
            column.Tag = new ColumnProperty
            {
                SectionType = StrType,
                StartPoint = StartDot,
                EndPoint = EndDot,
                Distance = EndDot - StartDot
            };
            dataGridView.Columns.Add(column);
            // 获取第一行
            DataGridViewRow firstRow = dataGridView.Rows[0];

            // 设置特定列的单元格属性
            //firstRow.Cells[column.Index].Value = text;
            firstRow.Cells[column.Index].Style.BackColor = cellBackColor;
            firstRow.Cells[column.Index].Style.ForeColor = Color.Red;

            //dataGridView.Columns.Add(column);
        }

        class ColumnProperty
        {
            public int SectionIndex { get; set; }   //分段序号
            public string SectionType { get; set; } //类型
            public float StartPoint { get; set; }  //起点
            public float EndPoint { get; set; }    //终点
            public float Distance { get; set; }      //距离
            public string Rule01 { get; set; }      //
            public string Rule02 { get; set; }      //
            public string Rule03 { get; set; }      //
            public string Rule04 { get; set; }      //
            public string Rule05 { get; set; }      //
            public string Rule06 { get; set; }      //
            public string Rule07 { get; set; }      //
            public string Rule08 { get; set; }      //
            public string Rule09 { get; set; }      //
            public string Rule10 { get; set; }      //
            public string Rule11 { get; set; }      //
            public string Rule12 { get; set; }      //管理站队
            public float Pvalue { get; set; }       //失效可能性
            public float Cvalue { get; set; }       //风险
            public float Rvalue { get; set; }       //后果
        }
        
        float CalculateMinDistance()
        {
            // 实现计算功能,计算相邻两个点之间的距离,得到最小值
            List<float> segmentLengths = new List<float>();
            for (int i = 0; i < Points.Count - 1; i++)
            {
                float segmentLength = Points[i + 1] - Points[i];
                segmentLengths.Add(segmentLength);
            }
            float minSegmentLength = segmentLengths.Count > 0 ? segmentLengths.Min() : pipelineLength;
            return FloatFormat(minSegmentLength);
        }

        private float FloatFormat(float f)
        {
            return (float)Math.Round(f, 2); ;
        }

        private void dataGridView1_Scroll(object sender, ScrollEventArgs e)
        {
            // 判断是否是水平滚动
            if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll)
            {
                // 水平滚动内容
                dataGridView1.HorizontalScrollingOffset = e.NewValue;
            }
        }

        private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            //if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
            //{
            //    if (e.ColumnIndex % 2 == 0)
            //    {
            //        e.CellStyle.BackColor = Color.DarkGray;
            //    }
            //    else
            //    {
            //        e.CellStyle.BackColor = Color.LightGray;
            //    }
            //}
        }

        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            //if (e.RowIndex >= 0 && e.ColumnIndex >= 0 && e.ColumnIndex % 2 == 0)
            //{
            //    dataGridView1.Rows[e.RowIndex].DefaultCellStyle.SelectionBackColor = Color.Transparent;
            //    dataGridView1.Rows[e.RowIndex].DefaultCellStyle.SelectionForeColor = dataGridView1.DefaultCellStyle.ForeColor;
            //}
        }

        private void dataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
        {
            e.PaintParts &= ~DataGridViewPaintParts.Background;
            if (e.RowIndex >= 0)
            {
                Image image = Image.FromFile("D:/CSharp/TestTreeview/WinFormsApp2/WinFormsApp2/image/TRQpipeline.jpg"); // 替换为实际的图片路径
                Rectangle rect = new Rectangle(e.RowBounds.Left, e.RowBounds.Top, dataGridView1.Columns.GetColumnsWidth(DataGridViewElementStates.Visible) - 1, e.RowBounds.Height - 1);
                e.Graphics.DrawImage(image, rect);
            }
        }

        private void dataGridView1_MouseEnter(object sender, EventArgs e)
        {
            dataGridView1.BorderStyle = BorderStyle.FixedSingle;
            //dataGridView1.BorderColor = Color.Red;            
        }

        private void dataGridView1_MouseLeave(object sender, EventArgs e)
        {
            dataGridView1.BorderStyle = BorderStyle.None;
        }

        private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        {
            //if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
            //{
            //    // 设置单元格背景颜色
            //    e.CellStyle.BackColor = Color.Red;

            //    // 设置单元格背景色的透明度
            //    e.CellStyle.BackColor = Color.FromArgb(192, e.CellStyle.BackColor);
            //}

            if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
            {
                if (e.ColumnIndex % 2 != 0)
                {
                    // 设置偶数列单元格的前景色为半透明背景色
                    using (Brush brush = new SolidBrush(Color.FromArgb(0, Color.White)))
                    {
                        e.Graphics.FillRectangle(brush, e.CellBounds);
                    }
                }
                else
                {
                    // 设置奇数列单元格的前景色为深灰色并覆盖行背景色
                    using (Brush brush = new SolidBrush(Color.Black))
                    {
                        e.Graphics.FillRectangle(brush, e.CellBounds);
                    }
                }

                // 绘制单元格内容
                e.PaintContent(e.CellBounds);
                e.Handled = true;
            }

        }

        // 处理鼠标滚轮事件
        private void dataGridView1_MouseWheel(object sender, MouseEventArgs e)
        {
            int delta = e.Delta;
            int newOffset = dataGridView1.HorizontalScrollingOffset - delta;

            // 检查滚动范围是否超出边界
            if (newOffset < 0)
            {
                newOffset = 0; // 将滚动范围限制在最左边
            }
            else if (newOffset > GetHorizontalScrollingOffsetMax())
            {
                newOffset = GetHorizontalScrollingOffsetMax(); // 将滚动范围限制在最右边
            }

            // 设置新的水平滚动偏移量
            dataGridView1.HorizontalScrollingOffset = newOffset;
        }


        private int GetHorizontalScrollingOffsetMax()
        {
            int maxOffset = 0;
            foreach (DataGridViewColumn column in dataGridView1.Columns)
            {
                maxOffset += column.Width;
            }
            maxOffset -= dataGridView1.ClientSize.Width;
            return maxOffset;
        }

        private void dataGridView1_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0 && e.ColumnIndex % 2 != 0)
            {
                DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
                ColumnProperty properties = (ColumnProperty)row.Cells[e.ColumnIndex].OwningColumn.Tag;
                string tooltip = $"Type: {properties.SectionType}\nStart Point: {properties.StartPoint}\nEnd Point: {properties.EndPoint}";
                toolTip.SetToolTip(dataGridView1, tooltip);
            }
            else
            {
                string tooltip = "";
                toolTip.SetToolTip(dataGridView1, tooltip);
            }
        }

        private void dataGridView1_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            //判断分段属性如果是Section
            if (e.RowIndex >= 0)
            {
                DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
                ColumnProperty properties = (ColumnProperty)row.Cells[e.ColumnIndex].OwningColumn.Tag;
                if (properties.SectionType == "Section")
                {
                    MessageBox.Show(properties.StartPoint.ToString()+ "|"+properties.EndPoint.ToString());
                }
            }
        }

  功能是完成了,后面还需要完善细节,就是属性值的更新,主要是TreeView与XML内容的同步,包括自动计算。

  

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

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

相关文章

一天吃透JVM面试八股文

内容摘自我的学习网站&#xff1a;topjavaer.cn 什么是JVM&#xff1f; JVM&#xff0c;全称Java Virtual Machine&#xff08;Java虚拟机&#xff09;&#xff0c;是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回…

C++11(1)——新增用法零碎总结

目录 1. C11简介 2. 统一的列表初始化 2.1 &#xff5b;&#xff5d;初始化 2.2 std::initializer_list std::initializer_list是什么类型&#xff1a; std::initializer_list使用场景&#xff1a; 让模拟实现的vector也支持{}初始化和赋值 1. C11简介 在2003年C标准委员会…

【雕爷学编程】Arduino动手做(163)---大尺寸8x8LED方格屏模块2

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

学无止境·MySQL⑧(Redis)

Redis和Mongodb练习 Redis1、安装redis2、string类型数据的命令操作&#xff1a;设置键值&#xff1a;读取键值数值类型自增1数值类型自减1查看值的长度 3、list类型数据的命令操作对列表city插入元素&#xff1a;Shanghai Suzhou Hangzhou将列表city里的头部的元素移除将name列…

AI炒股:用Claude来分析A股2023年中报业绩预告

Claude是和ChatGPT类似的AI大模型&#xff0c;据测试 AI 的水平能力接近 GPT-4&#xff0c;支持高达 100K token 的上下文。Claude只需要到官方网站注册账号后就可以直接免费使用。不过&#xff0c;目前智能美国和英国的 IP 可以注册和使用。 Claude支持上传文档功能&#xff…

计算机网络基础第三章

一、数据链路层功能概述 1.1 数据链路层基本概念 结点&#xff1a;主机、路由器 链路&#xff1a;网络中两个结点之间的物理通道&#xff0c;链路的传输介质主要有双绞线、光纤和微波。分为有线链路、无线链路 数据链路&#xff1a;网络中两个结点之间的逻辑通道&#xff0c;…

C++ 异常

文章目录 一. C语言的错误处理二. C的异常三. 异常的抛出与捕获1. 异常的抛出与匹配机制2. 在函数调用链中异常栈展开匹配原则3. 异常安全 四. 多态在异常中的应用五. C标准库的异常体系六. 异常规范七. 异常的优缺点结束语 一. C语言的错误处理 在C语言中&#xff0c;我们常见…

IDEA快捷键及模版配置

一、快捷键 1、常用的快捷键 删除当前行, 默认是 ctrl Y 自己配置 ctrl d (搜delete)复制当前行, 自己配置 ctrl alt 向下光标 (搜duplicate)补全代码 alt /添加注释和取消注释 ctrl / 【第一次是添加注释&#xff0c;第二次是取消注释】导入该行需要的类 先配置 auto …

S3C2440点亮LED(裸机开发)

文章目录 前言一、环境介绍一、GPIO介绍二、点亮开发板的LED1.预备动作2.led代码 总结 前言 本期和大家主要分享的是使用S3C2440开发板点亮一个LED灯&#xff0c;可能大家拿到开发板之后做的第一件事情都是点灯&#xff0c;这是为什么呢&#xff1f;因为点灯这件事情不仅能够检…

TCP三次握手调优

SYN: Synchronize Sequence Numbers。同步序列号 服务端的优化 当服务器收到 SYN 报文后&#xff0c;服务器会立刻回复 SYNACK 报文&#xff0c;既确认了客户端的序列号&#xff0c;也把自己的序列号发给了对方。此时&#xff0c;服务器端出现了新连接&#xff0c;状态是 SYN…

MySQL系列之行转列,列转行

MySQL系列之行转列&#xff0c;列转行 之前业务出现了需要行转列的场景&#xff0c;记录一下 SQL中AVG、COUNT、SUM、MAX等聚合函数对NULL值的处理 Mysql Max、 Where和 Group By 三个关键字同时使用 执行顺序 MySql 行转列的玩法 &#xff0c;实战案例教学&#xff08;MAX…

Eolink Apikit,0 代码可拖拽的自动化测试神器

目录 一、从测试到可拖拽的自动化测试二、0 代码&#xff0c;图形化&#xff0c;好用到飞起通过图形化操作、拖拽的方式搭建测试流程 三、Eolink Apikit&#xff0c;一站式 API 研发协作平台1、多协议支持2、多种数据重用3、报告、分析、告警4、支持持续集成和部署 四、Apikit …

QT基础入门之文件操作

一、概述 Qt 作为一个通用开发库&#xff0c;提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象&#xff0c;这些设备具有读写字节块的能力。下面是 I/O 设备的类图&#xff1a; QIODevice&#xff1a;所有I/O设备类的父类&#xff0c;提供字节块读写的通…

Sentinel流量规则模块(降级)

sentinel的常见页面的简介 流控是对外部来的大流量进行控制&#xff0c;熔断降级的视角是对内部问题进行处理。 Sentinel降级会在调用链路中某个资源出现不稳定状态时&#xff08;例如调用超时或异常比例升高&#xff09;&#xff0c;对这个资源的调用进行限制&#xff0c;…

【JDBC系列】- jdbc的概念以及与数据库的交互流程

【JDBC系列】- jdbc的概念以及与数据库的交互流程 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &#x1f31d;分享学习…

oc UITableView 列表

// // ViewController.m // OcDemoTest // // Created by Mac on 2023/7/14. //#import "ViewController.h" // 添加协议 interface ViewController ()<UITableViewDataSource> property (weak, nonatomic) IBOutlet UITableView *tableView;endimplementat…

Node中的的util.promisify()方法的介绍和基本实现

异步编程解决方案 我们知道&#xff0c;在JS中实现异步编程主要是通过以下几种方案&#xff1a; 回调函数&#xff1a;也是在ES6之前用的最多的方式&#xff0c;缺点是容易造成callback hell&#xff0c;可读性很差观察者模式&#xff1a;在NodeJS中的很多模块都继承了EventE…

二分搜索树节点删除

本小节介绍二分搜索树节点的删除之前&#xff0c;先介绍如何查找最小值和最大值&#xff0c;以及删除最小值和最大值。 以最小值为例&#xff08;最大值同理&#xff09;&#xff1a; 查找最小 key 值代码逻辑&#xff0c;往左子节点递归查找下去&#xff1a; ... // 返回以…

3.4 Bootstrap 按钮下拉菜单

文章目录 Bootstrap 按钮下拉菜单分割的按钮下拉菜单按钮下拉菜单的大小按钮上拉菜单 Bootstrap 按钮下拉菜单 本章将讲解如何使用 Bootstrap class 向按钮添加下拉菜单。如需向按钮添加下拉菜单&#xff0c;只需要简单地在在一个 .btn-group 中放置按钮和下拉菜单即可。您也可…

❤️创意网页:如何用HTML制作菜单栏?制作好看的菜单栏样式网页

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…