C# GDI+ 簡単な描画 (3)

Dec 17, 2016 am 09:45 AM

最初の 2 つの記事では基本的に描画の基礎知識を紹介しました。そこで、前の 2 つの記事で学んだことを使用していくつかの例を示します。
まずは簡単なことをやってみましょう - QQ のスクリーンショットを真似てみましょう。実際、これに関する情報はすでにインターネット上にありますが、記事を完全にするために、まだ説明する必要があると感じています。
まず効果を見てみましょう:

C# GDI+ 簡単な描画 (3)


次に、これがどのように行われるかを見てみましょう。

アイデア: チャット フォームにスクリーンショット ボタンがあります。ボタンをクリックすると、プログラムが表示されます。画面全体を表示する 新しい全画面フォームに描画してから、このフォームを表示します。 全画面フォームなので、メニューバーやツールバーなどが非表示になっており、デスクトップのスクリーンショットのように見えます。私たち、そしてこの新しいフォーム上に四角形を描き、最後に四角形の内容を保存し、元のチャット フォームに表示します。C# GDI+ 簡単な描画 (3) 手順:

A. 新しいフォームを作成します。 「Catch」という名前を付けて、このフォームの FormBorderStyle を None に、WindowState を Maximized に設定します。

B. コードを編集します:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

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. Catch フォームを作成した後、スクリーンショット ボタン (チャット フォーム上にあります) に次のイベントを追加します:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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();//重新显示窗体

               }

           }

 

       }

ログイン後にコピー

このようにして、スクリーンショット機能が完成します。

初心者にとって最初に描いた絵を消すのは難しい問題だと思います。何も対策が講じられない場合、マウスを動かし続ける限り長方形が描画されるため、さらに N 個の長方形が存在し、最後の 1 つだけが必要になることがわかります。

この問題を解決するには、大きく分けて2つの方法があります:

1. 2番目の図形を描くとき、​​まず最後に描いた図形を背景色と同じ色で再描画します。ただし、これは背景色が単色の場合に使用する必要があることがよくあります。

2. 描画ボードに直接グラフィックを描画するのではなく、元の描画ボードに画像を保存するために画像 A を使用します。次に、絵 A と同じ絵 B を新規作成し、その絵 B に描きたい図形を描き、その後、絵ボードに絵 B を描きます。このように、画像 A は変更されていません。なので、2回目に描くときも、絵Aと同じ絵を新たに作って描きました。その場合、最後のグラフィックスは保持されません。問題は解決された。

次回は、Windowsのスケッチパッドを模倣したプログラムの作り方を紹介します。



もっと見る C# GDI+ 簡単な描画 (3) 関連記事は、PHP 中国語 Web サイトに注目してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

.NETディープダイブ:非同期プログラミング、LINQ、およびEFコアのマスター .NETディープダイブ:非同期プログラミング、LINQ、およびEFコアのマスター Mar 31, 2025 pm 04:07 PM

.NET非同期プログラミング、LINQおよびEFCOREのコアコンセプトは次のとおりです。1。非同期プログラミングは、非同期を通じてアプリケーションの応答性を改善し、待ち望んでいます。 2。LINQは、統一された構文を介してデータクエリを簡素化します。 3.EFCOREは、ORMを介してデータベース操作を簡素化します。

Advanced C#.NET:並行性、並列性、およびマルチスレッド説明が説明されています Advanced C#.NET:並行性、並列性、およびマルチスレッド説明が説明されています Apr 03, 2025 am 12:01 AM

C#.NETは、同時、並列、およびマルチスレッドプログラミングのための強力なツールを提供します。 1)スレッドクラスを使用してスレッドを作成および管理します。2)タスククラスは、スレッドプールを使用してリソース利用を改善するために、より高度な抽象化を提供します。

C文字列におけるcharの役割は何ですか C文字列におけるcharの役割は何ですか Apr 03, 2025 pm 03:15 PM

Cでは、文字列でCharタイプが使用されます。1。単一の文字を保存します。 2。配列を使用して文字列を表し、ヌルターミネーターで終了します。 3。文字列操作関数を介して動作します。 4.キーボードから文字列を読み取りまたは出力します。

C言語で特殊文字を処理する方法 C言語で特殊文字を処理する方法 Apr 03, 2025 pm 03:18 PM

C言語では、以下などのエスケープシーケンスを通じて特殊文字が処理されます。\ nはラインブレークを表します。 \ tはタブ文字を意味します。 ESACEシーケンスまたは文字定数を使用して、Char C = '\ n'などの特殊文字を表します。バックスラッシュは2回逃げる必要があることに注意してください。さまざまなプラットフォームとコンパイラが異なるエスケープシーケンスを持っている場合があります。ドキュメントを参照してください。

C言語でchar配列の使用方法 C言語でchar配列の使用方法 Apr 03, 2025 pm 03:24 PM

Char Arrayは文字シーケンスをC言語で保存し、char array_name [size]として宣言されます。アクセス要素はサブスクリプト演算子に渡され、要素は文字列のエンドポイントを表すnullターミネーター「\ 0」で終了します。 C言語は、strlen()、strcpy()、strcat()、strcmp()など、さまざまな文字列操作関数を提供します。

Cスイッチステートメントでデフォルトに起因するエラーを避けてください Cスイッチステートメントでデフォルトに起因するエラーを避けてください Apr 03, 2025 pm 03:45 PM

Cスイッチステートメントでデフォルトに起因するエラーを回避するための戦略:定数の代わりに列挙を使用し、ケースステートメントの値を列挙の有効なメンバーに制限します。最後のケースステートメントでフォールスルーを使用して、プログラムが以下のコードを引き続き実行できるようにします。フォールスルーなしのスイッチステートメントの場合、エラー処理のためのデフォルトステートメントを常に追加するか、デフォルトの動作を提供します。

C言語でCharを変換する方法 C言語でCharを変換する方法 Apr 03, 2025 pm 03:21 PM

C言語では、charタイプの変換は、キャスト:キャスト文字を使用することにより、別のタイプに直接変換できます。自動タイプ変換:あるタイプのデータが別のタイプの値に対応できる場合、コンパイラは自動的に変換します。

C言語合計の機能は何ですか? C言語合計の機能は何ですか? Apr 03, 2025 pm 02:21 PM

C言語に組み込みの合計機能はないため、自分で書く必要があります。合計は、配列を通過して要素を蓄積することで達成できます。ループバージョン:合計は、ループとアレイの長さを使用して計算されます。ポインターバージョン:ポインターを使用してアレイ要素を指し示し、効率的な合計が自己概要ポインターを通じて達成されます。アレイバージョンを動的に割り当てます:[アレイ]を動的に割り当ててメモリを自分で管理し、メモリの漏れを防ぐために割り当てられたメモリが解放されます。

See all articles