C# Windows Forms实现绘制画板

news/2024/9/17 5:32:47 标签: c#, 开发语言

目录

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 上。


http://www.niftyadmin.cn/n/5645851.html

相关文章

人工智能、机器学习与深度学习的区别及其应用

引言 在过去的十年中,人工智能(AI)从研究实验室走向了工业应用的前沿,成为推动各个行业转型的关键技术。然而,AI 并不仅仅是某一种单一的技术,它包含了多种不同的方法和工具,适用于解决从自动驾驶到医疗诊断等复杂问题。与此同时,行业内对“人工智能”、“机器学习”与…

Java的时间复杂度和空间复杂度和常见排序

目录 一丶时间复杂度 二丶空间复杂度 三丶Java常见排序 1. 冒泡排序&#xff08;Bubble Sort&#xff09; 2.插入排序&#xff08;Insertion Sort&#xff09; 3.希尔排序&#xff08;Shell Sort&#xff09; 4.选择排序&#xff08;Selection Sort&#xff09; 5.堆排序&am…

gs_dump和gs_dumpall 迁移数据库

目录 0、源端实例收集AWR1、创建目录2、gs_dump - 业务停机3、gs_dumpall - 业务停机4、拷贝文件5、目标实例导入数据 0、源端实例收集AWR https://blog.csdn.net/hezuijiudexiaobai/article/details/134220949 1、创建目录 mkdir -p /pgdata/data/opengauss-57b399d8/dump/…

vue2-elementUI-初始化启动项目-git

前置基础 资料下载-阿里云盘 vueaxioselement-uinpmvscode 初始化项目 1.创建vue2工程 1.1 vue create projectName1.2 选择 1.3 初始化 vue-cli 的核心步骤&#xff1a; Manually select features (*) Babel ( ) TypeScript ( ) Progressive Web App (PWA) Support …

C#索引器(Indexer)

索引器(Indexer)允许一个对象可以像数组一样使用下标的方式来访问. 当为类定义一个索引器时,该类的行为就会像一个虚拟数组(virtual array) 一样.可以使用数组访问运算符[]来访问该类的成员. 语法 一维索引器的语法如下: element-type this[int index] { // get 访问器 …

二进制方式部署K8s高可用集群

1 二进制方式部署K8s高可用集群 1.1 kubeadm 和二进制安装 k8s 适用场景分析 kubeadm 是官方提供的开源工具&#xff0c;是一个开源项目&#xff0c;用于快速搭建 kubernetes 集群&#xff0c;目前是比较方便和推荐使用的。kubeadm init 以及 kubeadm join 这两个命令可以快速…

Linux 大文件和大量小文件的复制策略

在Linux上复制大文件或大量小文件时&#xff0c;可以根据文件的类型、数量以及硬件配置&#xff08;如硬盘类型、CPU、内存&#xff09;选择不同的复制策略&#xff0c;以提高复制效率。以下是一些常见的策略和工具&#xff0c;可以根据具体情况使用&#xff1a; 1. 大文件复制…

【Linux】进程控制(一)

1. 进程创建 &#xff08;一&#xff09;认识fork函数 从已存在进程中创建一个新进程&#xff08;新进程为子进程&#xff0c;而原进程为父进程&#xff09; 进程调用fork&#xff0c;当控制转移到内核中的fork代码后&#xff0c;内核做&#xff1a; 分配新的内存块和内核数…