欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C# Winform画图

程序员文章站 2022-06-25 10:02:52
...

实验二:用winform实现画图

实验目的

构造属于你的专属画图程序,可参考系统自带的绘图板


环境

  1. 操作系统: Windows 10 X64
  2. IDE: visual studio 2017
  3. 语言:C#

界面布局及控件使用

  • 整个页面 :Panel
  • 文件菜单 :MenuStrip
  • 主页,查看菜单 :TabControl
  • 绘图板 :PictureBox
  • 控制绘图板大小 :PictureBox
  • 工具、图形按钮 :Button
  • 粗细 :Label
  • 实线虚线 :Label
  • 填充按钮 :Label
  • 功能模块分区 :Panel
  • 功能模块分区的名字 :Label
  • 颜色板 :自定义控件名为 userControl1
  • 左下角的实时坐标 :StatusStrip
  • 按钮的文本提示 : ToolTip

界面展示

C# Winform画图


Point1–画布画板

画布相当于一张纸,我们使用两张纸,一张originalimage用于保留最终绘图并贴在画板上;一张interimage用于保存中间绘图痕迹。
比如画一个矩形

  1. 画图前先将中间画布初始化为原始画布(去掉绘图痕迹)
  2. 将矩形画在在中间画布
  3. 在鼠标释放时将中间画布复制给原始画布
  4. 将原始画布贴到画板上

Point2–颜色板的实现

新建及使用
  1. 新建项目->选择visual C# ->Windows 桌面 ->Windows窗体控件库
  2. 完成编辑后,在项目文件中找到 bin文件下的后缀为.dll的文件拖拽进工具箱即可。
完成效果:

C# Winform画图

使用的控件:
  • 颜色按钮:Button
  • 编辑颜色按钮:ColorDialog
  • 颜色1,2面板:Panel
功能实现:
  1. 选择颜色,判断改变颜色1还是颜色2

      private void button_Click(object sender, EventArgs e)
    {
        Button currentButton = (Button)sender;
        currentLabel.BackColor = currentButton.BackColor; 
        if(currentLabel==label1)
        {
            label1.BackColor = currentButton.BackColor;
            color1 = currentButton.BackColor;
        }
        else
        {
            label7.BackColor = currentButton.BackColor;
            color2 = currentButton.BackColor;
        }
    }
    
  2. 颜色1颜色2切换
    方法:设置一个currentlabel指向当前颜色label

       private void color1_Click(object sender, EventArgs e)
     {
             currentLabel = label1;
         label3.BackColor = Color.PowderBlue;
         label4.BackColor = Color.Transparent;
     }
    
     private void color2_Click(object sender, EventArgs e)
     {
         currentLabel = label7;
         label4.BackColor = Color.PowderBlue;
         label3.BackColor = Color.Transparent;
     }
    
  3. colordialog 调用颜色对话框,并将颜色添加到可用按钮中
    重点:colorDialog1.ShowDialog()

     private void makecolor_Click(object sender, EventArgs e)
     {
    
         if (colorDialog1.ShowDialog() == DialogResult.OK)
         {
             Color mycolor = colorDialog1.Color;
    
             for (int i = 0; i < haveUse; i++)
             {
                 if (allButton[i].BackColor == mycolor)//与第i个重复,则从第i+1个到num-1个都向前移动一格
                 {
                     for (int k = i; k < NUM - 1; k++)
                     {
                         allButton[k].BackColor = allButton[k + 1].BackColor;
                     }
                     haveUse--;
                     break;
                 }
             }
    
             if (haveUse == NUM)//已经满了,前移一格
             {
                 for (int i = 0; i < NUM - 1; i++)
                 {
                     allButton[i] = allButton[i + 1];
                 }
                 allButton[NUM - 1].BackColor = mycolor;
                 haveUse++;
             }
             else//还没满
             {
                 allButton[haveUse].BackColor = mycolor;
                 allButton[haveUse].Enabled = true;
                 haveUse++;
             }
         }
     }
    

Point3–绘制图形

重点:绘制图形的函数

        //使用Graphics对象实现
         switch (type)
        {
            case "nonerh"://无填充菱形
                {
                    PointF[] pointFs = { new PointF(leftX + width / 2, leftY), new PointF(leftX, leftY + height / 2), new PointF(leftX + width / 2, leftY + height), new PointF(leftX + width, leftY + height / 2) };
                    interGraphics.DrawPolygon(mypen, pointFs);
                    break;
                }
            case "solidrh"://纯色菱形
                {
                    PointF[] pointFs = { new PointF(leftX + width / 2, leftY), new PointF(leftX, leftY + height / 2), new PointF(leftX + width / 2, leftY + height), new PointF(leftX + width, leftY + height / 2) };
                    interGraphics.FillPolygon(new SolidBrush(backcolor), pointFs);
                    interGraphics.DrawPolygon(mypen, pointFs);

                    break;
                }
            case "hatchrh"://圆点填充
                {
                    PointF[] pointFs = { new PointF(leftX + width / 2, leftY), new PointF(leftX, leftY + height / 2), new PointF(leftX + width / 2, leftY + height), new PointF(leftX + width, leftY + height / 2) };
                    interGraphics.FillPolygon(new HatchBrush(HatchStyle.LargeConfetti, backcolor, Color.White), pointFs);
                    interGraphics.DrawPolygon(mypen, pointFs);

                    break;
                }

            case "nonetriangle"://无填充等腰三角形
                {
                    PointF[] pointfs = { new PointF((startPoint.X + currentPoint.X) / 2, startPoint.Y), new PointF(startPoint.X, currentPoint.Y), currentPoint };
                    interGraphics.DrawPolygon(mypen, pointfs);
                    break;
                }
            case "solidtriangle"://纯色填充等腰三角形
                {
                    PointF[] pointfs = { new PointF((startPoint.X + currentPoint.X) / 2, startPoint.Y), new PointF(startPoint.X, currentPoint.Y), currentPoint };
                    interGraphics.FillPolygon(new SolidBrush(backcolor), pointfs);
                    interGraphics.DrawPolygon(mypen, pointfs);

                    break;
                }
            case "hatchtriangle"://圆点填充等腰三角形
                {
                    PointF[] pointfs = { new PointF((startPoint.X + currentPoint.X) / 2, startPoint.Y), new PointF(startPoint.X, currentPoint.Y), currentPoint };
                    interGraphics.FillPolygon(new HatchBrush(HatchStyle.LargeConfetti, backcolor, Color.White), pointfs);
                    interGraphics.DrawPolygon(mypen, pointfs);

                    break;
                }
            case "nonetriangle2"://无填充直角三角形
                {
                    PointF[] pointfs = { startPoint, new PointF(startPoint.X, currentPoint.Y), currentPoint };
                    interGraphics.DrawPolygon(mypen, pointfs);
                    break;
                }
            case "solidtriangle2"://纯色填充直角三角形
                {
                    PointF[] pointfs = { startPoint, new PointF(startPoint.X, currentPoint.Y), currentPoint };
                    interGraphics.FillPolygon(new SolidBrush(backcolor), pointfs);
                    interGraphics.DrawPolygon(mypen, pointfs);

                    break;
                }
            case "hatchtriangle2"://圆点填充直角三角形
                {
                    PointF[] pointfs = {startPoint, new PointF(startPoint.X, currentPoint.Y), currentPoint };
                    interGraphics.FillPolygon(new HatchBrush(HatchStyle.LargeConfetti, backcolor, Color.White), pointfs);
                    interGraphics.DrawPolygon(mypen, pointfs);

                    break;
                }
            case "noneline"://直线
                interGraphics.DrawLine(mypen, startPoint, currentPoint);
                break;
            case "nonerectangle"://无填充矩形
                interGraphics.DrawRectangle(mypen, leftX, leftY, width, height);
                break;
            case "noneellipse"://无填充椭圆
                {               
                    interGraphics.DrawEllipse(mypen, leftX, leftY, width, height);
                    break;
                }
            case "nonearc"://弧线
                {                   
                    if (width != 0 && height != 0)
                        interGraphics.DrawArc(mypen, leftX, leftY, width, height, 0, 180);
                    break;
                }
            case "nonepie"://无填充饼形
                {
                   
                    if (width != 0 && height != 0)
                        interGraphics.DrawPie(mypen, leftX, leftY, width, height, 0, 180);
                    break;
                }
            case "solidrectangle"://纯色填充矩形
                {
                    
                    interGraphics.FillRectangle(new SolidBrush(backcolor), leftX, leftY, width, height);
                    interGraphics.DrawRectangle(mypen, leftX, leftY, width, height);
                    break;
                }
            case "solidellipse"://纯色填充椭圆
                {
                    interGraphics.FillEllipse(new SolidBrush(backcolor), leftX, leftY, width, height);
                    interGraphics.DrawEllipse(mypen, leftX, leftY, width, height);
                    break;
                }
            case "solidpie"://纯色填充饼形
                {
                    if (width != 0 && height != 0)
                    {
                        interGraphics.FillPie(new SolidBrush(backcolor), leftX, leftY, width, height, 0, 180);
                        interGraphics.DrawPie(mypen, leftX, leftY, width, height, 0, 180);
                    }
                    break;
                }
            case "hatchrectangle"://圆点填充矩形
                {
                    interGraphics.FillRectangle(new HatchBrush(HatchStyle.LargeConfetti,backcolor,Color.White), leftX, leftY, width, height);
                    interGraphics.DrawRectangle(mypen, leftX, leftY, width, height);
                    break;
                }
            case "hatchellipse"://圆点填充椭圆
                {
                    interGraphics.FillEllipse(new HatchBrush(HatchStyle.LargeConfetti,backcolor,Color.White), leftX, leftY, width, height);
                    interGraphics.DrawEllipse(mypen, leftX, leftY, width, height);
                    break;

                }
            case "hatchpie"://圆点填充饼形
                {
                    if (width != 0 && height != 0)
                    {
                        interGraphics.FillPie(new HatchBrush(HatchStyle.LargeConfetti, backcolor,Color.White), leftX, leftY, width, height, 0, 180);

                        interGraphics.DrawPie(mypen, leftX, leftY, width, height, 0, 180);
                    }
                    break;
                }
        }

Point4–铅笔

方法:使用DrawLine画线方法 从startpoint 到 currentpoint

    public void Pencile(MouseEventArgs e)//铅笔
    {
        PointF currentPoint = new PointF(e.X-10, e.Y+8);
        Graphics interGraphics = Graphics.FromImage(interImg);
        interGraphics.DrawLine(mypen, startPoint,currentPoint);
        originalImg = (Image)interImg.Clone();
        targetGraphics.DrawImage(originalImg,0,0);
        startPoint = currentPoint;
        
    }

Point5–橡皮

方法:相当于用纯色矩形覆盖,用DrwaRectangle方法

      public void Eraser(MouseEventArgs e)//橡皮擦
    {
        PointF currentPoint = new PointF(e.X, e.Y);
        Graphics interGraphics = Graphics.FromImage(interImg);
        interGraphics.FillRectangle(new SolidBrush(backcolor), startPoint.X-5,startPoint.Y-5,16,10);
        originalImg = (Image)interImg.Clone();
        targetGraphics.DrawImage(originalImg, 0, 0);
        startPoint = currentPoint;
    }

Point6–粗细、线条、填充

粗细:设置pen的Width属性

线条:设置pen的DashStyle属性。实现为Solid,虚线为Dot

填充:无填充:使用pen画;纯色填充:先用SolidBrush笔刷画,再用pen画上边;圆点填充:先用HatchBrush笔刷(设置属性HatchStyle.LargeConfetti)画,再用pen画上边


Point7–文本框

使用TextBox,点击绘图板,当绘图板里没有文本框时,显示文本框;有文本框时,移除文本框并将文本框的文字绘到绘图板上
重点:

  1. 动态添加控件:panel10.Controls.Add(mytb);(panel0为父容器)

  2. 动态删除控件:panel10.Controls.Remove(control);

  3. 绘制文字:interGraphics.DrawString(str, font, brush,pointF);
    font为字体样式,brush为字体填充笔刷,pointF为字体在父容器中的相对位置。

         if (drawtype == "text")
         {
             if (Extentionclass.FindControl(panel10, "mytb") == null)//第一次按下
             {
                 TextBox mytb = new TextBox();
                 mytb.Name = "mytb";
                 mytb.Location = new Point(e.X, e.Y+pictureBox1.Location.Y);//位置
                 mytb.BorderStyle = BorderStyle.FixedSingle;
                 panel10.Controls.Add(mytb);
                 //     panel10.Controls.SetChildIndex(mytb, 100);
                 mytb.BringToFront();
             }
             else
             {
                 Control control = Extentionclass.FindControl(panel10, "mytb");
                 string str =control.Text;
                 Font font = new Font("宋体", 9);
                 Brush brush = new SolidBrush(userControl11.Color1);
                 PointF pointF = new PointF(control.Location.X, control.Location.Y - pictureBox1.Location.Y);
                 panel10.Controls.Remove(control);
                 Graphics interGraphics = Graphics.FromImage(tool.InterImage);
                          
                 
                 interGraphics.DrawString(str, font, brush,pointF);
                 graphics.DrawImage(tool.InterImage, 0, 0);
             }
         }
    

Point8–新建文件、保存文件

新建文件之前要判断是否保存文件
用到的方法:

  1. 消息提示框:MessageBox.Show(“是否要保存文件”, “系统提示”, MessageBoxButtons.YesNoCancel);

  2. 保存、另存为、新建文件:如下代码

  3. 新建时要初始化绘画板

       private void 新建ToolStripMenuItem_Click(object sender, EventArgs e)
     {
        //是否保存
         DialogResult dialogResult = MessageBox.Show("是否要保存文件", "系统提示", MessageBoxButtons.YesNoCancel);
         if (dialogResult==DialogResult.Yes)//选择先保存
         {
             if (sFilename != null)//可以直接保存
             {
                 if (MessageBox.Show("是否要保存文件?", "系统提示", MessageBoxButtons.YesNo) == DialogResult.Yes)//选择yes保存
                 {
                     tool.OriginalImage.Save(sFilename);
                 }
             }
             else
             {
                 SaveFileDialog saveFile = new SaveFileDialog();
                 //            saveFile.FileName = "";
                 saveFile.Filter = "JPG|*.jpg;*.jpeg;*.jpe;*.jfif|GIF|*.gif|PNG|*.png|TIF|*.tif;*.tiff|ICO|*.ico|所有文件|*.*";
                 if (saveFile.ShowDialog() == DialogResult.OK)//文件夹显示成功
                 {
                     sFilename = saveFile.FileName;
                     tool.OriginalImage.Save(sFilename);
                 }
             }
         }
         else if(dialogResult==DialogResult.Cancel)//取消则什么都不做直接返回
         {
             return;
         }
         //
    
         //新建
         Bitmap  bmap= new Bitmap(pictureBox1.Size.Width, pictureBox1.Size.Height);
         Graphics g = Graphics.FromImage(bmap);
         g.FillRectangle(new SolidBrush(Color.White), 0, 0, bmap.Width, bmap.Height);
         g.Dispose();
         tool.targetGraphics.DrawImage(bmap,0,0);
         tool.OriginalImage = bmap;
         bmap.Dispose();
     }
    

Point9–打开文件

打开之前要提示是否保存文件

        OpenFileDialog openFile = new OpenFileDialog();
        openFile.FileName = "";
        openFile.Filter = "JPG|*.jpg;*.jpeg;*.jpe;*.jfif|GIF|*.gif|PNG|*.png|TIF|*.tif;*.tiff|ICO|*.ico|所有文件|*.*";
        if (openFile.ShowDialog() == DialogResult.OK)//文件夹显示ok(成功)
        {
            if(openFile.FileName!="")
            {

               //插入是否保存代码

               Bitmap bitmap = new Bitmap(openFile.FileName);//从指定的文件初始化bitmap
                pictureBox1.Size = bitmap.Size;//调整绘图区大小为图片大小
                pictureBox3.Location = new Point(pictureBox1.Width, pictureBox1.Height + pictureBox1.Location.Y);
                //改变那个小角角的大小
                Bitmap bm = new Bitmap(pictureBox1.Width, pictureBox1.Height);
                Graphics g = Graphics.FromImage(bm);
                g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height));
                g.DrawImage(bitmap, 0, 0);
                g.Dispose();

                tool.targetGraphics = pictureBox1.CreateGraphics();
                tool.targetGraphics.DrawImage(bm, 0, 0);
                tool.OriginalImage = bm;
                bitmap.Dispose();
                bm.Dispose();
                sFilename = openFile.FileName;
                openFile.Dispose();
          
            }
        }
    }

Point10–清除

方法:绘制一个和画板一样大小的白色矩形,注意要更新原始画布和中间画布

    private void 清除ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        Bitmap newpic = new Bitmap(pictureBox1.Width,  pictureBox1.Height);
        Graphics g = Graphics.FromImage(newpic);
        g.FillRectangle(new SolidBrush(Color.White), 0, 0,pictureBox1.Width, pictureBox1.Height);
        g.Dispose();
        g = pictureBox1.CreateGraphics();
        g.DrawImage(newpic, 0, 0);
        g.Dispose();
        tool.OriginalImage = newpic;
    }

Point11–退出

点击Form右上角的关闭角标时调用Form1_FormClosing方法
点击菜单项的关闭选项时用this.close()
关闭前要提示是否保存


Point12–改变画板大小

改变画板大小通过画板右下角的一个小pictruebox(pb)实现。移动pb改变pb的位置,根据pb的相对于父容器的位置(即location)及画板的location得到画板的大小,改变画板大小后要改变初始画布和中间画布的大小,并将画布重新贴在画板上才能显示图案。

      private bool isResize = false;

    private void pictureBox3_MouseDown(object sender, MouseEventArgs e)
    {
        isResize = true;
    }

    private void pictureBox3_MouseMove(object sender, MouseEventArgs e)
    {
        if (isResize)
        {
            pictureBox3.Location = new Point(pictureBox3.Location.X + e.X, pictureBox3.Location.Y + e.Y);
        }
    }

    private void pictureBox3_MouseUp(object sender, MouseEventArgs e)
    {
        isResize = false;
        pictureBox1.Size = new Size(pictureBox3.Location.X-pictureBox1.Location.X, pictureBox3.Location.Y-pictureBox1.Location.Y);//改变大小

        tool.targetGraphics = pictureBox1.CreateGraphics();//再次设置
        Bitmap newBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
        Graphics tempGraphic = Graphics.FromImage(newBitmap);
        tempGraphic.FillRectangle(new SolidBrush(Color.White), 0, 0, pictureBox1.Width, pictureBox1.Height);//创建一张新的临时画纸
        tempGraphic.DrawImage(tool.OriginalImage, 0, 0);//将original画在上面
        tempGraphic.Dispose();

     //   graphics = pictureBox1.CreateGraphics();
        //tempGraphic =pictureBox1.CreateGraphics();
        //tempGraphic.DrawImage(newBitmap, 0, 0);
        //tempGraphic.Dispose();
      //  tool.targetGraphics.DrawImage(newBitmap, 0, 0);//--为什么不能重绘绘图板
        tool.OriginalImage = newBitmap;
        newBitmap.Dispose();

    }

知识点1——关于按钮图片的方法

右击解决方案里的项目->进入属性->找到左侧的资源->将图像导入其中->找到按钮的image属性导入图片

知识点2——设置坐标图标

进入该项目的项目文件夹->进入bin文件夹->进入debug文件夹->在debug文件夹中创建一个文件夹存放.ico或者.cur图片
相应代码如下:

pictureBox1.Cursor = new Cursor(Application.StartupPath + @"\img\pen.ico");

知识点3——绘图板重绘

在改变绘图板的大小,或者绘图板被覆盖之后要调用重绘绘图板方法才能显示图像

      private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        g.DrawImage(tool.OriginalImage, 0, 0);
    }