ホームページ  >  記事  >  バックエンド開発  >  C# GDI+ 簡単な描画 (4)

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

高洛峰
高洛峰オリジナル
2016-12-17 09:49:461313ブラウズ

以前の記事で 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 までご連絡ください。