C# Winform画图
实验二:用winform实现画图
实验目的
构造属于你的专属画图程序,可参考系统自带的绘图板
环境
- 操作系统: Windows 10 X64
- IDE: visual studio 2017
- 语言:C#
界面布局及控件使用
- 整个页面 :Panel
- 文件菜单 :MenuStrip
- 主页,查看菜单 :TabControl
- 绘图板 :PictureBox
- 控制绘图板大小 :PictureBox
- 工具、图形按钮 :Button
- 粗细 :Label
- 实线虚线 :Label
- 填充按钮 :Label
- 功能模块分区 :Panel
- 功能模块分区的名字 :Label
- 颜色板 :自定义控件名为 userControl1
- 左下角的实时坐标 :StatusStrip
- 按钮的文本提示 : ToolTip
界面展示
Point1–画布画板
画布相当于一张纸,我们使用两张纸,一张originalimage用于保留最终绘图并贴在画板上;一张interimage用于保存中间绘图痕迹。
比如画一个矩形
- 画图前先将中间画布初始化为原始画布(去掉绘图痕迹)
- 将矩形画在在中间画布
- 在鼠标释放时将中间画布复制给原始画布
- 将原始画布贴到画板上
Point2–颜色板的实现
新建及使用
- 新建项目->选择visual C# ->Windows 桌面 ->Windows窗体控件库
- 完成编辑后,在项目文件中找到 bin文件下的后缀为.dll的文件拖拽进工具箱即可。
完成效果:
使用的控件:
- 颜色按钮:Button
- 编辑颜色按钮:ColorDialog
- 颜色1,2面板:Panel
功能实现:
-
选择颜色,判断改变颜色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; } }
-
颜色1颜色2切换
方法:设置一个currentlabel指向当前颜色labelprivate 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; }
-
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,点击绘图板,当绘图板里没有文本框时,显示文本框;有文本框时,移除文本框并将文本框的文字绘到绘图板上
重点:
-
动态添加控件:panel10.Controls.Add(mytb);(panel0为父容器)
-
动态删除控件:panel10.Controls.Remove(control);
-
绘制文字: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–新建文件、保存文件
新建文件之前要判断是否保存文件
用到的方法:
-
消息提示框:MessageBox.Show(“是否要保存文件”, “系统提示”, MessageBoxButtons.YesNoCancel);
-
保存、另存为、新建文件:如下代码
-
新建时要初始化绘画板
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);
}