欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入c# GDI+簡(jiǎn)單繪圖的具體操作步驟(四)

 更新時(shí)間:2013年05月20日 15:51:42   作者:  
本篇文章是向大家介紹了如何做一個(gè)類似windows畫(huà)圖工具的具體方法,需要的朋友參考下
前幾篇我已經(jīng)向大家介紹了如何使用GDI+來(lái)繪圖,并做了一個(gè)截圖的實(shí)例,這篇我向大家介紹下如何來(lái)做一個(gè)類似windows畫(huà)圖的工具.
個(gè)人認(rèn)為如果想做一個(gè)功能強(qiáng)大的繪圖工具,那么單純掌握GDI還遠(yuǎn)遠(yuǎn)不夠,我的目前也只能做一個(gè)比較簡(jiǎn)單的繪圖工具了.不足之處,歡迎大家討論!
先來(lái)看一下最終效果吧:

主要實(shí)現(xiàn)功能:畫(huà)直線,矩形,橡皮,圓形,切換顏色,打開(kāi)圖片,保存圖片,清除圖片,手動(dòng)調(diào)節(jié)畫(huà)布大小;軟件剛啟動(dòng)時(shí),為一張空白畫(huà)布,我們可以直接在畫(huà)布上繪畫(huà),也可以通過(guò)菜單中的“打開(kāi)”,導(dǎo)入一張圖片,然后我們就可以在這張圖片上進(jìn)行繪制。
平臺(tái):VS2005 WINFORM
由于代碼過(guò)多,在這里只簡(jiǎn)要介紹下制作步驟,提供大家工程下載.
1.對(duì)整個(gè)界面進(jìn)行布局.
2.實(shí)現(xiàn)繪圖工具的功能
3.實(shí)現(xiàn)顏色拾取的功能,這里我們直接拿上次寫的自定義控件來(lái)用.
4.實(shí)現(xiàn)菜單功能
5.實(shí)現(xiàn)手動(dòng)調(diào)節(jié)畫(huà)布大小的功能
6.測(cè)試
實(shí)現(xiàn)繪圖工具的功能
為了讓代碼藕合度小點(diǎn),稍許用了些設(shè)計(jì)模式,因?yàn)椴皇呛軙?huì),所以代碼還是有點(diǎn)亂亂的,嘿嘿!關(guān)于繪圖工具的這些功能塊全部寫在了DrawTools這個(gè)類里.那么在主窗體中,只需要調(diào)用這個(gè)類來(lái)完成繪制就行了,而不需要過(guò)多的涉及到具體的繪圖代碼。繪圖工具這個(gè)類提供的主要工具就是:鉛筆、橡皮、直線、矩形、圓形、實(shí)心矩形、實(shí)心圓形。關(guān)于這些功能塊的代碼,并不難,只要大家對(duì)認(rèn)真看過(guò)前幾篇內(nèi)容,那應(yīng)該都看得懂。
這里要注意以下幾點(diǎn):
1.如何防止記錄不必要的繪圖過(guò)程中的痕跡?
這個(gè)問(wèn)題在第三篇中有提到過(guò),大家不妨先去看看那一篇。為了讓代碼看起來(lái)可讀性高點(diǎn),我設(shè)置了兩個(gè)Image變量,finishingImg用來(lái)保存繪圖過(guò)程中的痕跡,orginalImg用來(lái)保存已完成的繪圖過(guò)程和初始時(shí)的背景圖片。
2.這個(gè)類如何與主窗體進(jìn)行通信?
當(dāng)然如果直接將這些功能塊寫在主窗體中自然沒(méi)有這個(gè)問(wèn)題。但是那樣代碼會(huì)顯得很混雜,如果只是工具代碼出現(xiàn)問(wèn)題就需要改整個(gè)項(xiàng)目。我在這里通過(guò)定義方法和屬性,讓主窗體通過(guò)給屬性賦值將畫(huà)板畫(huà)布以及顏色什么的信息傳給這個(gè)工具類,然后通過(guò)調(diào)用相應(yīng)的工具方法來(lái)使用這些工具。
3.關(guān)鍵屬性
要想讓這些工具能正常使用,必須傳遞給他以下幾樣?xùn)|西:目標(biāo)畫(huà)板(也就是picturebox),繪圖顏色,原始畫(huà)布。
實(shí)現(xiàn)菜單功能
  
這里就需要我們對(duì)文件的操作有一點(diǎn)了解,大家可以去查一下相關(guān)資料。
難點(diǎn)主要就是“打開(kāi)”這個(gè)菜單項(xiàng)的實(shí)現(xiàn)
我們要實(shí)現(xiàn)將打開(kāi)后的圖片在修改后重新保存就必須讓文件在打開(kāi)后就能關(guān)閉,否則就會(huì)因?yàn)槲募蜷_(kāi)而無(wú)法覆蓋原文件。就會(huì)導(dǎo)致編譯時(shí)彈出“GDI  一般性錯(cuò)誤”。所以根據(jù)網(wǎng)上其它朋友的做法就是先將打開(kāi)的圖片通過(guò)GDI+將圖片畫(huà)到另一個(gè)畫(huà)布上,然后及時(shí)關(guān)閉打開(kāi)的圖片和用來(lái)繪制該圖片的畫(huà)板。
復(fù)制代碼 代碼如下:

private void openPic_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();//實(shí)例化文件打開(kāi)對(duì)話框
            ofd.Filter = "JPG|*.jpg|Bmp|*.bmp|所有文件|*.*";//設(shè)置對(duì)話框打開(kāi)文件的括展名
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                Bitmap bmpformfile = new Bitmap(ofd.FileName);//獲取打開(kāi)的文件
                panel2.AutoScrollPosition = new Point(0,0);//將滾動(dòng)條復(fù)位
                pbImg.Size = bmpformfile.Size;//調(diào)整繪圖區(qū)大小為圖片大小
                reSize.Location = new Point(bmpformfile.Width, bmpformfile.Height);//reSize為我用來(lái)實(shí)現(xiàn)手動(dòng)調(diào)節(jié)畫(huà)布大小用的
                //因?yàn)槲覀兂跏紩r(shí)的空白畫(huà)布大小有限,"打開(kāi)"操作可能引起畫(huà)板大小改變,所以要將畫(huà)板重新傳入工具類
                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));//不使用這句話,那么這個(gè)bmp的背景就是透明的
                g.DrawImage(bmpformfile, 0, 0,bmpformfile.Width,bmpformfile.Height);//將圖片畫(huà)到畫(huà)板上
                g.Dispose();//釋放畫(huà)板所占資源
                //不直接使用pbImg.Image = Image.FormFile(ofd.FileName)是因?yàn)檫@樣會(huì)讓圖片一直處于打開(kāi)狀態(tài),也就無(wú)法保存修改后的圖片
                bmpformfile.Dispose();//釋放圖片所占資源
                g = pbImg.CreateGraphics();
                g.DrawImage(bmp, 0, 0);
                g.Dispose();
                dt.OrginalImg = bmp;
                bmp.Dispose();
                sFileName = ofd.FileName;//儲(chǔ)存打開(kāi)的圖片文件的詳細(xì)路徑,用來(lái)稍后能覆蓋這個(gè)文件
                ofd.Dispose();
            }
        }

清除圖像其實(shí)就是用白色填充整個(gè)畫(huà)布
其它的都比較簡(jiǎn)單,這就不具體講了。
實(shí)現(xiàn)手動(dòng)調(diào)節(jié)畫(huà)布大小
網(wǎng)上有人說(shuō)使用API,但是個(gè)人覺(jué)得還是使用其它控件幫忙比較簡(jiǎn)單,至少我們還看得懂。
思路:放置一個(gè)picturebox1(尺寸為5*5),將它固定在主畫(huà)板的右下角,然后改變鼠標(biāo)進(jìn)入時(shí)的Cursor為箭頭形狀,設(shè)置鼠標(biāo)按下移動(dòng)時(shí)的事件,讓該picturebox1 跟隨鼠標(biāo)移動(dòng)。當(dāng)鼠標(biāo)松開(kāi)時(shí),將主畫(huà)板的右下角坐標(biāo)調(diào)整為picturebox1的坐標(biāo)。
下面來(lái)看下代碼:
其中的reSize就是我們用來(lái)幫忙的picturebox控件 
復(fù)制代碼 代碼如下:

private bool bReSize = false;//是否改變畫(huà)布大小
        private void reSize_MouseDown(object sender, MouseEventArgs e)
        {
            bReSize = true;//當(dāng)鼠標(biāo)按下時(shí),說(shuō)明要開(kāi)始調(diào)節(jié)大小
        }
        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;//大小改變結(jié)束
            //調(diào)節(jié)大小可能造成畫(huà)板大小超過(guò)屏幕區(qū)域,所以事先要設(shè)置autoScroll為true.
            //但是滾動(dòng)條的出現(xiàn)反而增加了我們的難度,因?yàn)闈L動(dòng)條上下移動(dòng)并不會(huì)自動(dòng)幫我們調(diào)整圖片的坐標(biāo)。
            //這是因?yàn)镚DI繪圖的坐標(biāo)系不只一個(gè),好像有三個(gè),沒(méi)有仔細(xì)了解,一個(gè)是屏幕坐標(biāo),一個(gè)是客戶區(qū)坐標(biāo),還個(gè)是文檔坐標(biāo)。
            //滾動(dòng)條的上下移動(dòng)改變的是文檔的坐標(biāo),但是客戶區(qū)坐標(biāo)不變,而location屬性就屬于客戶區(qū)坐標(biāo),所以我們直接計(jì)算會(huì)出現(xiàn)錯(cuò)誤
            //這時(shí)我們就需要知道文檔坐標(biāo)與客戶區(qū)坐標(biāo)的偏移量,這就是AutoScrollPostion可以提供的
            pbImg.Size = new Size(reSize.Location.X - (this.panel2.AutoScrollPosition.X), reSize.Location.Y - (this.panel2.AutoScrollPosition.Y));
            dt.DrawTools_Graphics = pbImg.CreateGraphics();//因?yàn)楫?huà)板的大小被改變所以必須重新賦值
            //另外畫(huà)布也被改變所以也要重新賦值
            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();
        }

效果如下圖(仔細(xì)看白色區(qū)域的右下角):
  
此時(shí)就可以通過(guò)拖動(dòng)那個(gè)小方塊來(lái)調(diào)節(jié)圖片大小了。
這樣,主要的問(wèn)題差不多已經(jīng)解決了,但還是有不足這處,歡迎大家提出寶貴的意見(jiàn)。

相關(guān)文章

  • Unity實(shí)現(xiàn)見(jiàn)縫插針小游戲

    Unity實(shí)現(xiàn)見(jiàn)縫插針小游戲

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)見(jiàn)縫插針小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • unity3d調(diào)用手機(jī)或電腦攝像頭

    unity3d調(diào)用手機(jī)或電腦攝像頭

    這個(gè)是在網(wǎng)上看到的,經(jīng)測(cè)試可以在電腦上運(yùn)行,確實(shí)調(diào)用了本地?cái)z像頭。有需要的小伙伴可以參考下。
    2015-03-03
  • C#訪問(wèn)命令行的兩種方法

    C#訪問(wèn)命令行的兩種方法

    這篇文章主要介紹了C#訪問(wèn)命令行的兩種方法,實(shí)例分析了C#操作命令行的兩種常用技巧,需要的朋友可以參考下
    2015-06-06
  • C#使用DLLImport調(diào)用外部DLL的方法

    C#使用DLLImport調(diào)用外部DLL的方法

    這篇文章介紹了C#使用DLLImport調(diào)用外部DLL的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • c#中如何去除字符串左邊的0

    c#中如何去除字符串左邊的0

    這篇文章主要介紹了c#中如何去除字符串左邊的0問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • WPF仿三星手機(jī)充電界面實(shí)現(xiàn)代碼

    WPF仿三星手機(jī)充電界面實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了WPF仿三星手機(jī)充電界面實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • C#使用DoddleReport快速生成報(bào)表

    C#使用DoddleReport快速生成報(bào)表

    這篇文章介紹了C#使用DoddleReport快速生成報(bào)表的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • C# 多態(tài)性的深入理解

    C# 多態(tài)性的深入理解

    本篇文章是對(duì)C#中的多態(tài)性進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • c# 實(shí)現(xiàn)發(fā)送郵件到指定郵箱

    c# 實(shí)現(xiàn)發(fā)送郵件到指定郵箱

    這篇文章主要介紹了c# 如何實(shí)現(xiàn)發(fā)送郵件到指定郵箱,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • c# 獲取計(jì)算機(jī)硬件信息的示例代碼

    c# 獲取計(jì)算機(jī)硬件信息的示例代碼

    這篇文章主要介紹了c# 獲取計(jì)算機(jī)硬件信息的示例代碼,幫助大家更好的理解和學(xué)習(xí)c#,感興趣的朋友可以了解下
    2020-10-10

最新評(píng)論