最初の 2 つの記事では基本的に描画の基礎知識を紹介しました。そこで、前の 2 つの記事で学んだことを使用していくつかの例を示します。
まずは簡単なことをやってみましょう - QQ のスクリーンショットを真似てみましょう。実際、これに関する情報はすでにインターネット上にありますが、記事を完全にするために、まだ説明する必要があると感じています。
まず効果を見てみましょう:
アイデア: チャット フォームにスクリーンショット ボタンがあります。ボタンをクリックすると、プログラムが表示されます。画面全体を表示する 新しい全画面フォームに描画してから、このフォームを表示します。 全画面フォームなので、メニューバーやツールバーなどが非表示になっており、デスクトップのスクリーンショットのように見えます。私たち、そしてこの新しいフォーム上に四角形を描き、最後に四角形の内容を保存し、元のチャット フォームに表示します。 手順:
A. 新しいフォームを作成します。 「Catch」という名前を付けて、このフォームの FormBorderStyle を None に、WindowState を Maximized に設定します。 B. コードを編集します:
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(); } } } } }
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();//重新显示窗体 } } }
この問題を解決するには、大きく分けて2つの方法があります:
1. 2番目の図形を描くとき、まず最後に描いた図形を背景色と同じ色で再描画します。ただし、これは背景色が単色の場合に使用する必要があることがよくあります。 2. 描画ボードに直接グラフィックを描画するのではなく、元の描画ボードに画像を保存するために画像 A を使用します。次に、絵 A と同じ絵 B を新規作成し、その絵 B に描きたい図形を描き、その後、絵ボードに絵 B を描きます。このように、画像 A は変更されていません。なので、2回目に描くときも、絵Aと同じ絵を新たに作って描きました。その場合、最後のグラフィックスは保持されません。問題は解決された。
次回は、Windowsのスケッチパッドを模倣したプログラムの作り方を紹介します。