C# Windows Forms实现绘制画板

目录

C# Windows Forms上绘制画板:

详细解释:

TempData临时数据,用来保存画笔相关的信息,如:颜色,大小,坐标等

类声明和成员变量

 构造函数

文件菜单项点击事件 

 保存菜单项点击事件

 画笔大小选择

 颜色选择

清空画布 

 鼠标事件处理

 完整代码:

总结

详细解释:

TempData临时数据,用来保存画笔相关的信息,如:颜色,大小,坐标等

public static class TempData
{
    /// <summary>
    /// 用来保存上一次坐标点
    /// </summary>
    public static Point PrevPoint { get; set; }

    /// <summary>
    /// 画笔的颜色
    /// </summary>
    public static Color PenColor { get; set; } = Color.Black;

    /// <summary>
    /// 画笔的粗细
    /// </summary>
    public static int PenWidth { get; set; } = 2;

    
}

类声明和成员变量

  • Form1 类继承自 Form,表示一个Windows表单。
  • paintStart 是一个布尔变量,用于跟踪鼠标是否按下,从而开始绘图。
  • g 是一个 Graphics 对象,用于在窗体控件上绘制图像。
  • bmp 是一个 Bitmap 对象,用作绘图的画布。
    public partial class Form1 : Form
    {
        bool paintStart = false; // 标识是否开始绘画
        Graphics g = null; // 用于绘制图形的Graphics对象
        Bitmap bmp = null; // 用于存储绘制内容的Bitmap对象

 构造函数

  • InitializeComponent 方法用于初始化窗体上的控件。
  • g 被初始化为 panel2 的 Graphics 对象。
  • bmp 被初始化为一个与 panel2 控件大小相同的 Bitmap 对象。
    public Form1()
    {
        InitializeComponent();
        g = panel2.CreateGraphics();
        bmp = new Bitmap(panel2.Width, panel2.Height);
    }

文件菜单项点击事件 

  • 打开一个文件对话框,让用户选择一个JPG图片文件。
  • 如果用户选择了文件并点击了OK,当前的 Bitmap 对象 bmp 被替换为用户选择的图片。
  • 使用 Graphics 对象 g 将新的 Bitmap 绘制到 panel2 上。
    private void 文件FToolStripMenuItem_Click(object sender, EventArgs e)
    {
        OpenFileDialog dlg = new OpenFileDialog();
        dlg.Filter = "图片(*.jpg)|*.JPG";
        if (dlg.ShowDialog() == DialogResult.OK)
        {
            bmp = new Bitmap(dlg.FileName);
            g.DrawImage(bmp, new Point(0, 0));
        }
    }

 保存菜单项点击事件

  • 打开一个保存文件对话框,让用户选择保存路径和文件名。
  • 如果用户选择了路径并点击了OK,尝试将当前的 Bitmap 对象 bmp 保存为JPG图片。
  • 如果保存过程中发生异常(例如文件被其他程序占用),显示一个错误消息。
    private void 保存SToolStripMenuItem_Click(object sender, EventArgs e)
    {
        SaveFileDialog saveFileDialog = new SaveFileDialog();
        saveFileDialog.Filter = "图片(*.jpg)|*.JPG";
        if (saveFileDialog.ShowDialog() == DialogResult.OK)
        {
            try
            {
                bmp.Save(saveFileDialog.FileName);
            }
            catch (Exception)
            {
                MessageBox.Show("保存的文件名称,已经被独占打开!重新输入新文件名!");
            }
        }
    }

 画笔大小选择

  • 这些方法设置画笔的大小,TempData.PenWidth 存储当前选择的画笔宽度。
    private void 小号画笔ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        TempData.PenWidth = 2;
    }
    
    private void 中号画笔ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        TempData.PenWidth = 6;
    }
    
    private void 大号画笔ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        TempData.PenWidth = 10;
    }

 颜色选择

  • 打开一个颜色对话框,让用户选择画笔的颜色。
  • 如果用户选择了颜色并点击了OK,将选择的颜色存储在 TempData.PenColor 中。清空画布
    private void 颜色ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        ColorDialog colorDialog = new ColorDialog();
        if (colorDialog.ShowDialog() == DialogResult.OK)
        {
            TempData.PenColor = colorDialog.Color;
        }
    }

清空画布 

  • 显示一个确认对话框,询问用户是否确定要清空画布。
  • 如果用户点击“Yes”,清空 panel2 的内容,重新创建一个空白的 Bitmap 对象,并将其绘制到 panel2 上。
    private void 清空ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        DialogResult dr = MessageBox.Show("你确定要清空吗?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
        if (dr == DialogResult.Yes)
        {
            g.Clear(Color.White);
            bmp = new Bitmap(panel2.Width, panel2.Height);
            g.DrawImage(bmp, new Point(0, 0));
        }
    }

 鼠标事件处理

  • MouseDown: 当用户在 panel2 上按下鼠标左键时,设置 paintStart 为 true 并记录当前鼠标位置。
  • MouseMove: 当用户在 panel2 上移动鼠标时,如果 paintStart 为 true,则根据选择的工具(画笔或橡皮擦)绘制线条或擦除区域。
  • MouseUp: 当用户在 panel2 上释放鼠标左键时,设置 paintStart 为 false,停止绘图。
    private void panel2_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            paintStart = true;
            TempData.PrevPoint = new Point(e.X, e.Y);
        }
    }
    
    private void panel2_MouseMove(object sender, MouseEventArgs e)
    {
        Graphics g2 = Graphics.FromImage(bmp);
        Pen pen = new Pen(TempData.PenColor, TempData.PenWidth);
        Point pt2 = new Point(e.X, e.Y);
        if (rbPen.Checked && paintStart)
        {
            g2.DrawLine(pen, TempData.PrevPoint, pt2);
            TempData.PrevPoint = pt2;
            g.DrawImage(bmp, 0, 0);
        }
        else if (rbEraser.Checked && paintStart)
        {
            g2.FillRectangle(new SolidBrush(panel2.BackColor), e.X, e.Y, TempData.PenWidth + 50, TempData.PenWidth + 50);
            g.DrawImage(bmp, 0, 0);
        }
    }
    
    private void panel2_MouseUp(object sender, MouseEventArgs e)
    {
        paintStart = false;
    }

 完整代码:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace _2.画板
{
    public partial class Form1 : Form
    {
        // 标识,表示是否开始绘画
        bool paintStart = false;
        // 画板1(用panel2创建的,主要用来显示图)
        Graphics g = null;
        // 保存的图片  BitMap位图(.bmp), Image图片(.jpg,.jpeg,.png)
        Bitmap bmp = null;

        public Form1()
        {
            InitializeComponent();
            // 创建画板实例
            g = panel2.CreateGraphics();
            // 创建图片实例,设置宽高
            bmp = new Bitmap(panel2.Width, panel2.Height);
        }

        private void 文件FToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "图片(*.jpg)|*.JPG"; // 图片(*.jpg)|*.JPG|所有文件(*.*)|*.*
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                bmp = new Bitmap(dlg.FileName);
                g.DrawImage(bmp, new Point(0, 0));//重新绘制画板
            }
        }

        private void 保存SToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "图片(*.jpg)|*.JPG";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    bmp.Save(saveFileDialog.FileName);
                }
                catch (Exception)
                {
                    MessageBox.Show("保存的文件名称,已经被独占打开!重新输入新文件名!");
                }
            }
        }

        private void 小号画笔ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TempData.PenWidth = 2;
        }

        private void 中号画笔ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TempData.PenWidth = 6;
        }

        private void 大号画笔ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TempData.PenWidth = 10;
        }

        private void 颜色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ColorDialog colorDialog = new ColorDialog();
            if (colorDialog.ShowDialog() == DialogResult.OK)
            {
                TempData.PenColor = colorDialog.Color;
            }
        }

        private void 清空ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult dr = MessageBox.Show("你确定要清空吗?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (dr == DialogResult.Yes)
            {
                g.Clear(Color.White); // 清空画板1
                bmp = new Bitmap(panel2.Width, panel2.Height); // 重新创建bmp实例,清空图片内容
                g.DrawImage(bmp, new Point(0, 0)); //用清空后的图片重新绘制画板1
            }
        }

        private void panel2_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                paintStart = true;

                // MouseEventArgs类型的实例中,拥有坐标系统
                // EventArgs
                TempData.PrevPoint = new Point(e.X, e.Y);
            }
        }

        private void panel2_MouseMove(object sender, MouseEventArgs e)
        {
            // 用空白图片bmp当成画板的底板,重新生成一个画板2,画板2上画的图其实是画在bmp。
            // 为什么要创建两个画板:画板1为了画图并显示。画板2为了保存绘制的图片,橡皮擦。
            // 两个画板上的图保持一致。
            Graphics g2 = Graphics.FromImage(bmp);

            Pen pen = new Pen(TempData.PenColor, TempData.PenWidth);
            Point pt2 = new Point(e.X, e.Y);
            if (rbPen.Checked && paintStart)
            {
                g2.DrawLine(pen, TempData.PrevPoint, pt2);
                TempData.PrevPoint = pt2;
                g.DrawImage(bmp, 0, 0); // 把bmp上的图,重新再绘制到画板1上展示出来。
            }
            else if (rbEraser.Checked && paintStart)
            {
                g2.FillRectangle(new SolidBrush(panel2.BackColor), e.X, e.Y, TempData.PenWidth + 50, TempData.PenWidth + 50);
                g.DrawImage(bmp, 0, 0);  // 为了同步g和g2两个画板。
            }
        }

        private void panel2_MouseUp(object sender, MouseEventArgs e)
        {
            paintStart = false;
        }
    }
}

总结

这个程序实现了一个基本的绘图工具,允许用户加载图片、保存图片、选择画笔大小和颜色,并在 panel2 控件上进行绘图。它通过处理鼠标事件来实现绘图功能,并通过 Graphics 对象在 Bitmap 上绘制,然后将 Bitmap 显示在 panel2 上。

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

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

相关文章

等待唤醒机制和阻塞队列

1. 等待唤醒机制 由于线程的随机调度&#xff0c;可能会出现“线程饿死”的问题&#xff1a;也就是一个线程加锁执行&#xff0c;然后解锁&#xff0c;其他线程抢不到&#xff0c;一直是这个线程在重复操作 void wait() 当前线程等待&#xff0c;直到被其他线程唤醒 void no…

网络安全(sql注入)

这里写目录标题 一. information_schema.tables 和 information_schema.schemata是information_schema数据库中的两张表1. information_schema.schemata2. information_schema.tables 二. 判断注入类型1. 判断数字型还是字符型注入2. 判断注入闭合是""还是 三. 判断表…

Keras深度学习中文文本分类

一.文本分类概述 文本分类旨在对文本集按照一定的分类体系或标准进行自动分类标记&#xff0c;属于一种基于分类体系的自动分类。文本分类最早可以追溯到上世纪50年代&#xff0c;那时主要通过专家定义规则来进行文本分类&#xff1b;80年代出现了利用知识工程建立的专家系统&…

电动机制造5G智能工厂工业物联数字孪生平台,推进制造业数字化转型

电动机制造5G智能工厂工业物联数字孪生平台&#xff0c;推进制造业数字化转型。5G智能工厂与物联数字孪生平台的融合应用&#xff0c;为电动机制造业的数字化转型铺设了一条高速通道。这一创新模式不仅极大地提升了生产效率&#xff0c;还深刻改变了产品的设计、生产、管理及运…

音视频入门基础:WAV专题(9)——FFmpeg源码中计算WAV音频文件每个packet的duration和duration_time的实现

音视频入门基础&#xff1a;WAV专题系列文章&#xff1a; 音视频入门基础&#xff1a;WAV专题&#xff08;1&#xff09;——使用FFmpeg命令生成WAV音频文件 音视频入门基础&#xff1a;WAV专题&#xff08;2&#xff09;——WAV格式简介 音视频入门基础&#xff1a;WAV专题…

深入理解Java虚拟机:Jvm总结-虚拟机字节码执行引擎

第八章 虚拟机字节码执行引擎 8.1 意义 不受物理条件制约地定制指令集与执行引擎的结构体系&#xff0c;能够执行那些不被硬件直接支持的指令集格式。输入的是字节码二进制流&#xff0c;处理过程是字节码解析执行的等效过程&#xff0c;输出的是执行结果 8.2 运行时栈帧结构…

一文读懂在线学习凸优化技术

一文读懂在线学习凸优化技术 在当今的数据驱动时代&#xff0c;机器学习算法已成为解决复杂问题的关键工具。在线学习凸优化作为机器学习中的一项核心技术&#xff0c;不仅在理论研究上具有重要意义&#xff0c;还在实际应用中展现出巨大的潜力。本文将深入浅出地介绍在线学习…

编程新纪元:AI如何成为你的编程伙伴

随着人工智能技术的不断进步&#xff0c;我们正步入一个编程的新纪元。在这个时代&#xff0c;AI不仅仅是一个工具&#xff0c;更是程序员的伙伴。它通过提供智能辅助、自动化编码和增强开发效率&#xff0c;正在改变我们编写和理解代码的方式。本文将探讨AI如何成为程序员的得…

精品PPT | 离散制造行业智能工厂总体解决方案

一、建设背景 离散制造业&#xff0c;包括机械制造业、汽车制造业和家电制造业等&#xff0c;其生产过程涉及多个不连续的工序&#xff0c;产品通常由多个零件装配而成。这类行业面临的挑战包括品种多、批量小、订单变化快、临时插单频繁以及外协件管理困难等问题&#xff0c;…

2025年第八届计算机图形和虚拟国际会议(ICCGV 2025)即将召开!

2025年第八届计算机图形和虚拟国际会议&#xff08;ICCGV 2025&#xff09;将于2025年2月21-23日在中国成都举行。随着信息技术的飞速发展&#xff0c;计算机图形学与虚拟现实技术正以前所未有的速度重塑着我们的认知世界与交互体验。从沉浸式游戏到精准医疗模拟&#xff0c;从…

如何将镜像推送到docker hub

前言 这一篇应该是最近最后一篇关于docker的博客了&#xff0c;咱来个有始有终&#xff0c;将最后一步——上传镜像给他写完&#xff0c;废话不多说&#xff0c;直接进入正题。 登录 首先需要确保登录才能推送到你的仓库中去&#xff0c;在终端输入docker login,输入用户名和…

AutosarMCAL开发——基于EB Gpt驱动

目录 1.Gpt原理2.EB配置以及接口应用2.1 EB配置2.2 接口应用 3.总结 1.Gpt原理 autosar GPT模块&#xff08;General Purpose Timer&#xff0c;通用定时器&#xff09;主要用于汽车ECU中的时间测量、计数和产生定时中断。它支持单次性和周期性定时器&#xff0c;可以在达到预…

阿里云机房火灾?盘点五大机房火灾现场

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 不知道大家有没有看到今天有关阿里云的新闻&#xff0c;没错就是阿里云新加坡的网络节点出现了异常&#xff…

【828华为云征文|如何使用华为云Flexus X实例搭建私人博客:从配置到发布全指南】

文章目录 华为云Flexus X实例介绍搭建专属私人博客准备工作具体操作指南服务器环境确认宝塔软件商店操作一键部署WordPress私人博客域名解析WordPress安装初始页数据库信息配置运行安装程序配置博客信息博客管理后台&#xff08;默认为wp-login.php页面&#xff09;博客前台页面…

让AI成为打光工具人(Stable Diffusion进阶篇:Imposing Consistent Light)

前言 正巧我之前一直在学习的B站up也恢复了关于Stable Diffusion的教程&#xff0c;今天就一起来学习一下IC-Light&#xff0c;这样一项可以帮助喜欢拍照的同学们打光布景的插件。 IC-Light IC-Light的全称是Imposing Consistent Light&#xff0c;翻译过来就是给物体施加一…

Git 修改Push后的Commit Message

向远程仓库push代码之后&#xff0c;在IDEA中无法直接修改Commit Message&#xff0c;需要在终端或控制台中输入以下命令&#xff08;HEAD~1中的1表示只对最后一个提交进行修改&#xff0c;因此1可以自定义&#xff09; git rebase -i HEAD~1执行完rebase指令后&#xff0c;会…

F12抓包06-4:导出metersphere脚本

课程大纲 metersphere是一站式的开源持续测试平台&#xff0c;我们可以将浏览器请求导出为HAR文件&#xff0c;导入到metersphere&#xff0c;生成接口测试。 metersphere有2种导入入口&#xff08;方式&#xff09;&#xff0c;导入结果不同&#xff1a; 1.导入到“接口定义”…

白盒测试覆盖例题

答案&#xff1a;A D 知识点 定义 特点 语句覆盖 被测试程序中的每条语句至少测试一次 对执行逻辑覆盖很低&#xff0c;一般认为是很弱的逻辑覆盖 判定覆盖 被测试程序每个判定表达式至少落得一次“真”值和“假值” 判定覆盖比语句覆盖更强一些。判定可以是一个条件或…

DIC技术助力新能源汽车主机厂力学测试研发与整车性能提升

在新能源汽车研发过程中&#xff0c;非接触式全视场应变DIC测量方案&#xff0c;越来越受到汽车主机厂的信赖与认可。传统接触式传感器&#xff0c;在精度、灵活性和数据处理能力上存在局限。DIC技术可提供精确、高效、全视场、便捷的非接触式测量解决方案。 在汽车研发阶段&a…

Proteus 仿真设计:开启电子工程创新之门

摘要&#xff1a; 本文详细介绍了 Proteus 仿真软件在电子工程领域的广泛应用。从 Proteus 的功能特点、安装与使用方法入手&#xff0c;深入探讨了其在电路设计、单片机系统仿真、PCB 设计等方面的强大优势。通过具体的案例分析&#xff0c;展示了如何利用 Proteus 进行高效的…