C# WPF上位机开发(增强版绘图软件)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        前面我们写过一个绘图软件,不过那个比较简单,主要就是用鼠标模拟pen进行绘图。实际应用中,另外一种使用比较多的场景,就是绘制直线、长方形和圆形。不管是流程图,还是传感器仿真,或者是图形数据动态显示等等,绘图部分本身还是有着重要的实际用途。因此,这里有必要告诉大家,实际的canvas绘图是什么样的。

        这里的增强版,主要也是指的直线绘图、长方形绘图和圆形绘图。当然如果要做得好的话,一般还需要同步考虑一下keyboard事件,这部分也很重要。

1、软件设计

        关于软件设计,目前是这么考虑的。可以创建一个菜单,里面有三个子菜单,这三个子菜单分别是直线、长方形和圆形。我们选择了一种图形,那么其他的图形就自动被放弃。后续在canvas上面绘图的时候,就用对应子菜单的形式进行绘图即可。

2、界面设计

        相对代码,界面设计还是比较简单的。整个界面主要就两个部分,一部分是菜单,一部分是canvas。做好了这个,基本的界面就准备好了。

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp"
        mc:Ignorable="d"
        Title="Canvas" Height="450" Width="600">
    <Grid>
        <Menu Name="shapesMenu">
            <MenuItem Header="Shapes">
                <MenuItem Name="menuItemLine" Header="Line" IsCheckable="True" IsChecked="false" Checked="MenuItemLine_Checked"/>
                <MenuItem Name="menuItemRectangle" Header="Rectangle" IsCheckable="True" IsChecked="False" Checked="MenuItemRectangle_Checked"/>
                <MenuItem Name="menuItemCircle" Header="Circle" IsCheckable="True" IsChecked="False" Checked="MenuItemCircle_Checked"/>
            </MenuItem>
        </Menu>
        <Canvas Name="drawingCanvas" Background="WhiteSmoke" MouseDown="Canvas_MouseDown" MouseMove="Canvas_MouseMove" MouseUp="Canvas_MouseUp" Margin="0,20,0,10"/>
    </Grid>
</Window>

3、代码设计

        由于是绘图,所以整个绘图的操作其实分成了三个阶段,分别是鼠标左键按下、鼠标移动、鼠标松开三个步骤。如果是鼠标按键刚刚按下,一般只需要记录一下当前的坐标即可。接着在鼠标移动的时候,开始绘制图形。等到最终鼠标左键弹起的时候,绘图结束,所有的shape记录到List当中。

        当然除了绘图之外,另外一部分比较重要的就是菜单的响应,这里建议不同的菜单设置不同的响应函数。虽然麻烦了一点,但是可以保证不出错。

4、详细的代码内容

        最后为了方便学习和交流,这里给出完整的c#代码,中间关于图形绘制的内容多了一点,菜单部分的内容其实还是比较简单的。

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        private Point startPoint;
        private bool isDrawing = false;
        private Shape currentShape;
        private List<Shape> shapes = new List<Shape>();


        // init MainWindow
        public MainWindow()
        {
            InitializeComponent();
        }

        // mouse down function
        private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            startPoint = e.GetPosition(drawingCanvas);
            isDrawing = true;
        }

        // mouse move function
        private void Canvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDrawing)
            {
                Point endPoint = e.GetPosition(drawingCanvas);

                if (currentShape == null)
                {
                    // Determine the shape type based on the selected menu item
                    if (menuItemLine.IsChecked)
                    {
                        currentShape = new Line { Stroke = Brushes.Blue, StrokeThickness = 2 };
                    }
                    else if (menuItemRectangle.IsChecked)
                    {
                        currentShape = new Rectangle { Stroke = Brushes.Red, StrokeThickness = 2, Fill = Brushes.Transparent };
                    }
                    else if(menuItemCircle.IsChecked)
                    {
                        currentShape = new Ellipse { Stroke = Brushes.Green, StrokeThickness = 2, Fill = Brushes.Transparent };
                    }
                    else
                    {
                        currentShape = null;
                        return;
                    }

                    drawingCanvas.Children.Add(currentShape);
                }

                // Update the coordinates of the shape
                if (currentShape is Line line)
                {
                    line.X1 = startPoint.X;
                    line.Y1 = startPoint.Y;
                    line.X2 = endPoint.X;
                    line.Y2 = endPoint.Y;
                }
                else if (currentShape is Rectangle rectangle)
                {
                    double width = endPoint.X - startPoint.X;
                    double height = endPoint.Y - startPoint.Y;

                    rectangle.Width = width > 0 ? width : -width;
                    rectangle.Height = height > 0 ? height : -height;

                    // record first x
                    if(startPoint.X < endPoint.X)
                        Canvas.SetLeft(rectangle, startPoint.X);
                    else
                        Canvas.SetLeft(rectangle, endPoint.X);

                    // record first y
                    if(startPoint.Y < endPoint.Y)
                        Canvas.SetTop(rectangle, startPoint.Y);
                    else
                        Canvas.SetTop(rectangle, endPoint.Y);
                }
                else if(currentShape is Ellipse ecllipse)
                {
                    double width = endPoint.X - startPoint.X;
                    double height = endPoint.Y - startPoint.Y;

                    ecllipse.Width = width > 0 ? width : -width;
                    ecllipse.Height = height > 0 ? height : -height;

                    // judge ecllipse width and height
                    if(ecllipse.Width > ecllipse.Height)
                    {
                        ecllipse.Height = ecllipse.Width;
                    }
                    else
                    {
                        ecllipse.Width = ecllipse.Height;
                    }

                    // record first x
                    if (startPoint.X < endPoint.X)
                        Canvas.SetLeft(ecllipse, startPoint.X);
                    else
                        Canvas.SetLeft(ecllipse, endPoint.X);

                    // record first y
                    if (startPoint.Y < endPoint.Y)
                        Canvas.SetTop(ecllipse, startPoint.Y);
                    else
                        Canvas.SetTop(ecllipse, endPoint.Y);
                }
                else
                {
                    return;
                }
            }
        }

        // mouse up function
        private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            isDrawing = false;

            if (null != currentShape)
            {
                shapes.Add(currentShape);
                currentShape = null;
            }
        }

        // sub menu function
        private void MenuItemLine_Checked(object sender, RoutedEventArgs e)
        {
            menuItemLine.IsChecked = true;
            menuItemRectangle.IsChecked = false;
            menuItemCircle.IsChecked = false;
        }

        // sub menu function
        private void MenuItemRectangle_Checked(object sender, RoutedEventArgs e)
        {
            menuItemLine.IsChecked = false;
            menuItemRectangle.IsChecked = true;
            menuItemCircle.IsChecked = false;
        }

        // sub menu function
        private void MenuItemCircle_Checked(object sender, RoutedEventArgs e)
        {
            menuItemLine.IsChecked = false;
            menuItemRectangle.IsChecked = false;
            menuItemCircle.IsChecked = true;
        }
    }
}

5、结束彩蛋部分

        另外建议大家可以多使用类似chatgpt的工具来学习c# wpf,这样你给它提示关键字,通过不断的交流,最终一定可以实现你想要的效果。这比单纯的搜索引擎学习效率要高得多。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL笔记-第18章_MySQL8其它新特性

视频链接&#xff1a;【MySQL数据库入门到大牛&#xff0c;mysql安装到优化&#xff0c;百科全书级&#xff0c;全网天花板】 文章目录 第18章_MySQL8其它新特性1. MySQL8新特性概述1.1 MySQL8.0 新增特性1.2 MySQL8.0移除的旧特性 2. 新特性1&#xff1a;窗口函数2.1 使用窗口…

最新鸿蒙HarmonyOS4.0开发登陆的界面1

下载deveco-studio 说明一下&#xff0c;本人只是学习中&#xff0c;现在只是拿着vue及uniapp的经验在一点一点的折腾&#xff0c;不过现在看来&#xff0c;鸿蒙入门并不是很难。也许是自己没有深入下去。 https://developer.harmonyos.com/cn/develop/deveco-studio#download…

谈谈常用的分布式ID的设计方案?

典型回答 首先&#xff0c;我们需要明确通常的分布式ID定义&#xff0c;基本的要求包括&#xff1a; 全局唯一&#xff0c;区别于单点系统的唯一&#xff0c;全局是要求分布式系统内唯一。 有序性&#xff0c;通常都需要保证生成的ID是有序递增的。例如&#xff0c;在数据库存…

循环神经网络-RNN记忆能力实验 [HBU]

目录 一、循环神经网络 二、循环神经网络的记忆能力实验 三、数据集构建 数据集的构建函数 加载数据并进行数据划分 构造Dataset类 四、模型构建 嵌入层 SRN层 五、模型训练 训练指定长度的数字预测模型 多组训练 损失曲线展示 六、模型评价 参考《神经网络与深度…

SpringCloud系列(一)| SpringCloud简介

上个系列中&#xff0c;我们已经介绍完了SpringBoot的用法&#xff0c;简单概述 springBoot Spring X, 就是对于Spring和其他技术的融合 进行了简化开发&#xff0c;所以x可以代表任何技术&#xff0c;比如 mybtis, mybatisPlus, redis.... 对于集成这些常用框架&#xff0c;…

SpringBoot之请求的详细解析

1. 请求 在本章节呢&#xff0c;我们主要讲解&#xff0c;如何接收页面传递过来的请求数据。 1.1 Postman 之前我们课程中有提到当前最为主流的开发模式&#xff1a;前后端分离 在这种模式下&#xff0c;前端技术人员基于"接口文档"&#xff0c;开发前端程序&…

电流测量原理

由于直接测量电流信号是很难的&#xff0c;但是测试电压信号比较容易&#xff0c;因此通常都是先将电流信号转换为电压信号&#xff0c;将电压信号进行调理后送至 CPU&#xff0c;CPU 通过 AD 转换得到一个码值&#xff0c;软件读出该码值&#xff0c;先根据主控的硬件设计参数…

【送书活动】探究AIGC、AGI、GPT和人工智能大模型

文章目录 前言01 《ChatGPT 驱动软件开发》推荐语 02 《ChatGPT原理与实战》推荐语 03 《神经网络与深度学习》推荐语 04 《AIGC重塑教育》推荐语 05 《通用人工智能》推荐语 后记赠书活动 前言 人工智能技术在过去几年中发展迅猛&#xff0c;得益于大数据、云计算、深度学习等…

爬虫 scrapy (十一)

目录 一、scrapy shell 1.什么是scrapy shell&#xff1f; 2.安装 ipython 3.使用scrapy shell 二、当当网案例 1.在items.py中定义数据结构 2.在dang.py中解析数据 3.使用pipeline保存 4.多条管道的使用 5.多页下载 参考 一、scrapy shell 1.什么是scrapy shell&am…

设计模式(2)--对象创建(3)--工厂方法

1. 意图 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。 工厂方法使一个类的实例化延迟到其子类。 2. 四种角色 抽象产品、具体产品、抽象构造者、具体构造者 3. 优点 3.1 仅处理抽象产品(Product)接口 3.2 给子类一个钩子(hook)以提供对象的扩展版本(父…

C/C++ 快乐数: 编写一个算法来判断一个数n是不是快乐数

题目&#xff1a; 编写一个算法来判断一个数n是不是快乐数。 快乐数的定义&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。 如果这个过…

面试必备的Linux常用命令

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 Linux常用命令 1、文件及内容2、网络3、进程服务4、…

C++寻找特殊年号 2023年3月C++一级 电子学会中小学生软件编程C++等级考试一级真题答案解析

目录 C/C寻找特殊年号 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C寻找特殊年号 2023年3月 C编程等级考试一级编程题 一、题目要求 1、编程实现 年号中的每个数之和为20的年号是特殊年号。例如: 2…

计算机操作系统-第十四天

目录 前言 线程 线程机制带来的变化 线程的属性 前言 在还没有引入进程的概念时&#xff0c;系统中的各个程序只能串行执行&#xff0c;即不能边听音乐边QQ聊天&#xff0c;在引入了进程的概念后&#xff0c;就可以实现边听音乐边QQ聊天。 但是我们在使用QQ时除了聊天还会进…

Python实现多种图像去噪方法

Python实现多种图像去噪方法&#xff1a;中值滤波&#xff0c;均值滤波&#xff0c;高通滤波&#xff0c;低通滤波&#xff0c;高斯滤波&#xff0c;同态滤波 图像和视频逐渐成为人们生活中信息获取的重要来源。人们准确地获取信源发出的图像和视频信息需要保证在传输过程中的…

性能优化 vue2/vue3 通过CDN 减少项目启动时间

其实更多可以通过压缩图片等文件大小 也会让项目运行快一些 以及尽量使用异步或者懒加载 使用CDN可以避免在项目中使用npm导入Vue的依赖项&#xff0c;从而减少项目启动时的加载时间 使用方法如下 <!-- Vue 2 --> <script src"https://cdn.jsdelivr.net/npm/vue…

[Linux] Tomcat

一、Tomcat相关知识 1.1 Tomcat的简介 Tomcat 是 Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器&#xff0c;是 Apache 软件基金会的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。 …

防职业掉坑必看,电商设计主要做什么?

今年双十一刚结束&#xff0c;各电商平台不公布总销售额的新闻就上了热搜。外行人乍一看可能觉得消费意愿下降&#xff0c;消费水平降级&#xff0c;电商行业不景气&#xff0c;但实际上电商领域在国内突飞猛进了10几年后&#xff0c;仍然还有很大的上升空间。很多人说&#xf…

shiro入门demo(二)授权

在前面认证的基础上&#xff0c;认证通过后一般还有个授权的操作。授权根据业务需求有两种维度&#xff0c;基于角色的授权和基于资源的授权。 一、授权-基于角色授权&#xff1a; shiro中授权实现方式&#xff1a;有三种 1、编程式 Subject subject SecurityUtils.getSubje…

电路中的repeater是什么?

最近在看interlaken协议&#xff0c;有一个单词&#xff0c;repeater&#xff0c;不知道是什么含义&#xff0c;查了一下发现它的功能是提高数据的完整性&#xff0c;要么是修复时钟&#xff0c;要么是提高信号裕量等。总之是让信号变好的一个东西。 具体可以参见TI的说明。 【…