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

Dec 17, 2016 am 09:49 AM

以前の記事で GDI+ を使用して描画する方法を紹介し、スクリーンショットの例を作成しました。この記事では、Windows の描画に似たツールを作成する方法を紹介します。強力なツールを作成する 描画ツールを作成するには、GDI を習得するだけでは不十分です。現時点では、比較的単純な描画ツールしか作成できません。欠陥がある場合はご相談ください。

まずは最終的な効果を見てみましょう:

c# GDI+简单绘图

主な機能: 直線、長方形、消しゴム、円を描く、色の切り替え、画像を開く、画像を保存する、画像をクリアする、キャンバス サイズを手動で調整する。ソフトウェアが最初に起動すると、空白のキャンバスが表示されます。キャンバスに直接描画することも、メニューの「開く」から画像をインポートして、その画像に描画することもできます。

プラットフォーム:VS2005 WINFORM

コードが多すぎるため、ここでは制作手順を簡単に紹介し、プロジェクトのダウンロードを提供します。

1.インターフェース全体をレイアウトします。
2. 描画ツールの機能を実装します
3. カラーピッキングの機能を実装します ここでは前回書いたカスタムコントロールを直接使用します。
4. メニュー機能を実装します
5. キャンバスサイズを手動で調整する機能を実装します
6. テスト

描画ツールの機能を実装します
コードをより一貫性のあるものにするために、いくつかのデザインパターンを使用しました。あまり上手ではないので、コードはまだちょっと汚いですが、ふふ!描画ツールに関するこれらすべての機能ブロックは、DrawTools クラスに記述されます。次に、メイン フォームでは、特定の描画コードをあまり必要とせずに、このクラスを呼び出すだけで描画が完了します。このクラスの描画ツールで提供される主なツールは、鉛筆、消しゴム、直線、長方形、円、塗りつぶし長方形、塗りつぶし円です。これらの関数ブロックのコードは、これまでの記事をよく読んでいれば理解できるはずです。
ここで注意すべき点は次のとおりです:
1. 描画プロセスの不要な痕跡が記録されないようにするにはどうすればよいですか?
この問題については 3 番目の記事で言及されていますので、まずその記事を読んでください。コードを読みやすくするために、2 つの Image 変数を設定しました。finishImg は描画プロセスのトレースを保存するために使用され、originalImg は完了した描画プロセスと初期の背景画像を保存するために使用されます。
2. このクラスはメインフォームとどのように通信しますか?
もちろん、これらのファンクションブロックをメインフォームに直接記述すれば、そのような問題は発生しません。ただし、ツール コードのみに問題がある場合は、コードが非常にわかりにくくなり、プロジェクト全体を変更する必要があります。ここでは、メイン フォームがプロパティに値を割り当てることでアートボード、キャンバス、カラーに関する情報をツール クラスに渡し、対応するツール メソッドを呼び出すことでこれらのツールを使用できるようにメソッドとプロパティを定義します。
3. 主要な属性
これらのツールが適切に動作するためには、ターゲットのアートボード (つまり、ピクチャーボックス)、描画カラー、および元のキャンバスを彼に渡す必要があります。

メニュー機能を実装するには

c# GDI+简单绘图

ここでファイル操作を少し理解する必要がありますが、関連する情報を確認できます。

主な困難は、「開く」メニュー項目の実装です
変更後に開いた画像を再保存したい場合は、開いた後にファイルを閉じる必要があります。そうしないと、ファイルが開いているため、元のファイルが上書きされません。これにより、コンパイル中に「GDI General Error」がポップアップ表示されます。したがって、インターネット上の他の友人のやり方によれば、まず開いている画像を GDI+ 経由で別のキャンバスに描画し、その後、開いている画像と画像の描画に使用した描画ボードをすぐに閉じます。

 private void openPic_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();//实例化文件打开对话框
            ofd.Filter = "JPG|*.jpg|Bmp|*.bmp|所有文件|*.*";//设置对话框打开文件的括展名
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                Bitmap bmpformfile = new Bitmap(ofd.FileName);//获取打开的文件
                panel2.AutoScrollPosition = new Point(0,0);//将滚动条复位
                pbImg.Size = bmpformfile.Size;//调整绘图区大小为图片大小

                reSize.Location = new Point(bmpformfile.Width, bmpformfile.Height);//reSize为我用来实现手动调节画布大小用的
                //因为我们初始时的空白画布大小有限,"打开"操作可能引起画板大小改变,所以要将画板重新传入工具类
                dt.DrawTools_Graphics = pbImg.CreateGraphics();

                Bitmap bmp = new Bitmap(pbImg.Width, pbImg.Height);
                Graphics g = Graphics.FromImage(bmp);
                g.FillRectangle(new SolidBrush(pbImg.BackColor), new Rectangle(0, 0, pbImg.Width, pbImg.Height));//不使用这句话,那么这个bmp的背景就是透明的
                g.DrawImage(bmpformfile, 0, 0,bmpformfile.Width,bmpformfile.Height);//将图片画到画板上
                g.Dispose();//释放画板所占资源
                //不直接使用pbImg.Image = Image.FormFile(ofd.FileName)是因为这样会让图片一直处于打开状态,也就无法保存修改后的图片
                bmpformfile.Dispose();//释放图片所占资源
                g = pbImg.CreateGraphics();
                g.DrawImage(bmp, 0, 0);
                g.Dispose();
                dt.OrginalImg = bmp;
                bmp.Dispose();
                sFileName = ofd.FileName;//储存打开的图片文件的详细路径,用来稍后能覆盖这个文件
                ofd.Dispose();

            }
        }
ログイン後にコピー

画像のクリアとは、実際にはキャンバス全体を白で塗りつぶすことです

その他は比較的簡単なので、ここでは詳しく説明しません。

キャンバスサイズの手動調整を実現
ネット上ではAPIを使えという人もいますが、個人的には他のコントロールを使ったほうが簡単だと思います、少なくとも理解はできます。
アイデア:picturebox1(サイズ5*5)を配置し、メイン描画ボードの右下隅に固定し、マウスが入ったときのカーソルを矢印の形に変更し、マウスを押して移動したときのイベントを設定し、そして、picturebox1 をマウスの動きに追従させます。マウスを離したら、メイン描画ボードの右下隅の座標をpicturebox1の座標に合わせます。
コードを見てみましょう:
reSize は、ヘルプに使用するピクチャーボックス コントロールです

private bool bReSize = false;//是否改变画布大小
        private void reSize_MouseDown(object sender, MouseEventArgs e)
        {
            bReSize = true;//当鼠标按下时,说明要开始调节大小
        }

        private void reSize_MouseMove(object sender, MouseEventArgs e)
        {
            if (bReSize)
            {
                reSize.Location = new Point(reSize.Location.X + e.X, reSize.Location.Y + e.Y);

            }
        }

        private void reSize_MouseUp(object sender, MouseEventArgs e)
        {
            bReSize = false;//大小改变结束
            //调节大小可能造成画板大小超过屏幕区域,所以事先要设置autoScroll为true.
            //但是滚动条的出现反而增加了我们的难度,因为滚动条上下移动并不会自动帮我们调整图片的坐标。
            //这是因为GDI绘图的坐标系不只一个,好像有三个,没有仔细了解,一个是屏幕坐标,一个是客户区坐标,还个是文档坐标。
            //滚动条的上下移动改变的是文档的坐标,但是客户区坐标不变,而location属性就属于客户区坐标,所以我们直接计算会出现错误
            //这时我们就需要知道文档坐标与客户区坐标的偏移量,这就是AutoScrollPostion可以提供的

            pbImg.Size = new Size(reSize.Location.X - (this.panel2.AutoScrollPosition.X), reSize.Location.Y - (this.panel2.AutoScrollPosition.Y));
            dt.DrawTools_Graphics = pbImg.CreateGraphics();//因为画板的大小被改变所以必须重新赋值

            //另外画布也被改变所以也要重新赋值
            Bitmap bmp = new Bitmap(pbImg.Width, pbImg.Height);
            Graphics g = Graphics.FromImage(bmp);
            g.FillRectangle(new SolidBrush(Color.White), 0, 0, pbImg.Width, pbImg.Height);
            g.DrawImage(dt.OrginalImg, 0, 0);
            g.Dispose();
            g = pbImg.CreateGraphics();
            g.DrawImage(bmp, 0, 0);
            g.Dispose();
            dt.OrginalImg = bmp;

            bmp.Dispose();
        }
ログイン後にコピー

効果は以下に示すとおりです (白い領域の右下隅をよく見てください):

c# GDI+简单绘图

この時点で、小さな四角をドラッグして画像サイズを調整できます。

このようにして、主な問題はほぼ解決されましたが、まだ不十分な点もいくつかありますので、皆様、貴重なご意見をお待ちしております。


その他の c# GDI+ 簡単な描画 (4) 関連記事については、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衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

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

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

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

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

C言語でさまざまなシンボルを使用する方法 C言語でさまざまなシンボルを使用する方法 Apr 03, 2025 pm 04:48 PM

c言語のシンボルの使用方法は、算術、割り当て、条件、ロジック、ビット演算子などをカバーします。算術演算子は基本的な数学的操作に使用されます。割り当てと追加、下位、乗算、除算の割り当てには、条件操作に使用されます。ポインター、ファイル終了マーカー、および非数値値。

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

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

C言語のcharとwchar_tの違い C言語のcharとwchar_tの違い Apr 03, 2025 pm 03:09 PM

C言語では、charとwchar_tの主な違いは文字エンコードです。CharはASCIIを使用するか、ASCIIを拡張し、WCHAR_TはUnicodeを使用します。 Charは1〜2バイトを占め、WCHAR_Tは2〜4バイトを占有します。 charは英語のテキストに適しており、wchar_tは多言語テキストに適しています。 CHARは広くサポートされており、WCHAR_TはコンパイラとオペレーティングシステムがUnicodeをサポートするかどうかに依存します。 CHARの文字範囲は限られており、WCHAR_Tの文字範囲が大きく、特別な機能が算術演算に使用されます。

マルチスレッドと非同期C#の違い マルチスレッドと非同期C#の違い Apr 03, 2025 pm 02:57 PM

マルチスレッドと非同期の違いは、マルチスレッドが複数のスレッドを同時に実行し、現在のスレッドをブロックせずに非同期に操作を実行することです。マルチスレッドは計算集約型タスクに使用されますが、非同期はユーザーインタラクションに使用されます。マルチスレッドの利点は、コンピューティングのパフォーマンスを改善することですが、非同期の利点はUIスレッドをブロックしないことです。マルチスレッドまたは非同期を選択することは、タスクの性質に依存します。計算集約型タスクマルチスレッド、外部リソースと相互作用し、UIの応答性を非同期に使用する必要があるタスクを使用します。

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

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

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

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

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()など、さまざまな文字列操作関数を提供します。

See all articles