The first two articles have basically introduced you to the basic knowledge of drawing. So, I will use what we learned in the previous two articles to make a few examples.
Let’s do a simple one first - imitating QQ screenshots. In fact, there is already information about this on the Internet, but for the sake of the completeness of the article, I still feel it is necessary to explain it.
Let’s take a look at the effect first:
Next let’s see how this is done.
Idea: There is a screenshot button on the chat form. After clicking the button, the program will display the entire screen Draw it on a new full-screen form, and then display this form. Because it is a full-screen form, and the menu bar, toolbar, etc. are hidden, it looks like a screenshot of the desktop to us, and then in this new Draw a rectangle on the form, and finally save the content in the rectangle and display it in the original chat form.
Steps:
A. Create a new form. Name it Catch. Then set the FormBorderStyle of this form to None and WindowState to Maximized.
B. We edit the code:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace Client { public partial class Catch : Form { public Catch() { InitializeComponent(); } 用户变量 //窗体初始化操作 private void Catch_Load(object sender, EventArgs e) { this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true); this.UpdateStyles(); //以上两句是为了设置控件样式为双缓冲,这可以有效减少图片闪烁的问题,关于这个大家可以自己去搜索下 originBmp = new Bitmap(this.BackgroundImage);//BackgroundImage为全屏图片,我们另用变量来保存全屏图片 } //鼠标右键点击结束截图 private void Catch_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { this.DialogResult = DialogResult.OK; this.Close(); } } //鼠标左键按下时动作 private void Catch_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { if (!CatchStart) {//如果捕捉没有开始 CatchStart = true; DownPoint = new Point(e.X, e.Y);//保存鼠标按下坐标 } } } private void Catch_MouseMove(object sender, MouseEventArgs e) { if (CatchStart) {//如果捕捉开始 Bitmap destBmp = (Bitmap)originBmp.Clone();//新建一个图片对象,并让它与原始图片相同 Point newPoint = new Point(DownPoint.X, DownPoint.Y);//获取鼠标的坐标 Graphics g = Graphics.FromImage(destBmp);//在刚才新建的图片上新建一个画板 Pen p = new Pen(Color.Blue,1); int width = Math.Abs(e.X - DownPoint.X), height = Math.Abs(e.Y - DownPoint.Y);//获取矩形的长和宽 if (e.X < DownPoint.X) { newPoint.X = e.X; } if (e.Y < DownPoint.Y) { newPoint.Y = e.Y; } CatchRect = new Rectangle(newPoint,new Size(width,height));//保存矩形 g.DrawRectangle(p,CatchRect);//将矩形画在这个画板上 g.Dispose();//释放目前的这个画板 p.Dispose(); Graphics g1 = this.CreateGraphics();//重新新建一个Graphics类 //如果之前那个画板不释放,而直接g=this.CreateGraphics()这样的话无法释放掉第一次创建的g,因为只是把地址转到新的g了.如同string一样 g1 = this.CreateGraphics();//在整个全屏窗体上新建画板 g1.DrawImage(destBmp,new Point(0,0));//将刚才所画的图片画到这个窗体上 //这个也可以属于二次缓冲技术,如果直接将矩形画在窗体上,会造成图片抖动并且会有无数个矩形. g1.Dispose(); destBmp.Dispose();//要及时释放,不然内存将会被大量消耗 } } private void Catch_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { if (CatchStart) { CatchStart = false; CatchFinished = true; } } } //鼠标双击事件,如果鼠标位于矩形内,则将矩形内的图片保存到剪贴板中 private void Catch_MouseDoubleClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left&&CatchFinished) { if (CatchRect.Contains(new Point(e.X, e.Y))) { Bitmap CatchedBmp = new Bitmap(CatchRect.Width, CatchRect.Height);//新建一个于矩形等大的空白图片 Graphics g = Graphics.FromImage(CatchedBmp); g.DrawImage(originBmp, new Rectangle(0, 0, CatchRect.Width, CatchRect.Height), CatchRect, GraphicsUnit.Pixel); //把orginBmp中的指定部分按照指定大小画在画板上 Clipboard.SetImage(CatchedBmp);//将图片保存到剪贴板 g.Dispose(); CatchFinished = false; this.BackgroundImage = originBmp; CatchedBmp.Dispose(); this.DialogResult = DialogResult.OK; this.Close(); } } } } }
C. After creating the Catch form, we add the following event to the screenshot button (located on the chat form):
private void bCatch_Click(object sender, EventArgs e) { if (bCatch_HideCurrent.Checked) { this.Hide();//隐藏当前窗体 Thread.Sleep(50);//让线程睡眠一段时间,窗体消失需要一点时间 Catch CatchForm = new Catch(); Bitmap CatchBmp = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);//新建一个和屏幕大小相同的图片 Graphics g = Graphics.FromImage(CatchBmp); g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height));//保存全屏图片 CatchForm.BackgroundImage = CatchBmp;//将Catch窗体的背景设为全屏时的图片 if (CatchForm.ShowDialog() == DialogResult.OK) {//如果Catch窗体结束,就将剪贴板中的图片放到信息发送框中 IDataObject iData = Clipboard.GetDataObject(); DataFormats.Format myFormat = DataFormats.GetFormat(DataFormats.Bitmap); if (iData.GetDataPresent(DataFormats.Bitmap)) { richtextbox1.Paste(myFormat); Clipboard.Clear();//清除剪贴板中的对象 } this.Show();//重新显示窗体 } } }
In this way, our screenshot function is completed.
I think it is a difficult problem for beginners to erase the first picture they draw. If no measures are taken, you will find that as long as you move the mouse, a rectangle will be drawn, so that there will be N more rectangles, and we only want the last one.
There are generally two ways to solve this problem:
1. When drawing the second figure, we first redraw the last drawn figure with the same color as the background color. But this often needs to be used when the background color is a solid color.
2. We do not draw the graphics directly on the drawing board. We use a picture A to save the picture on the original drawing board. Then create a new picture B that is the same as picture A, draw the graphics we want to draw on the picture B, and then draw the picture B on the drawing board. In this way, picture A has not been changed. So when we drew the second time, we still created a new picture that was the same as picture A and drew it. Then the last graphics will not be retained. The problem is solved.
Next time, I will introduce to you how to make a program that imitates Windows Sketchpad.
More C# GDI+ simple drawing (3) For related articles, please pay attention to the PHP Chinese website!