如果想自己設(shè)計(jì)一個(gè)個(gè)性獨(dú)特的ico圖片,然后讓它成為如"我的電腦","回收站"這樣的圖標(biāo)該怎么做?就只有用一些專門的畫圖工具。因?yàn)閣indows的的畫圖程序無法創(chuàng)建ico文件。于是本人利用.net和gdi+就編寫了一個(gè)這樣的畫圖工具。雖然現(xiàn)在有很多文章都介紹了gdi+技術(shù),但都只是純粹的gdi+的簡單應(yīng)用的介紹,至少我還沒有看見一篇利用gdi+開發(fā)一個(gè)完整軟件或程序片段的文章。
這個(gè)程序?qū)崿F(xiàn)了以下的功能:將bmp、jpg、jpeg、gif、.png、.tiff文件轉(zhuǎn)化成ico文件,可以對轉(zhuǎn)化后的文件進(jìn)行編輯;創(chuàng)建并編輯一個(gè)新的ico文件;對已有的ico文件進(jìn)行編輯。所有被編輯的文件都保存為ico文件,可以在任何可使用ico文件的地方使用它們。
我先說明一下什么是gdi+。gdi+ 是gdi(windows 早期版本提供的圖形設(shè)備接口)的后續(xù)版本,是microsoft windows xp操作系統(tǒng)即后續(xù)版本的圖形顯示技術(shù)。它已經(jīng)集成到了.net開發(fā)環(huán)境中,所以不管你的os是什么版本,只要安裝了.net框架,就有了gdi+(注意:是.net框架,而不是.net開發(fā)環(huán)境,所以win98中也可以使用gdi+)。當(dāng)然它也提供了傳統(tǒng)的api,可以由.net或非.net開發(fā)工具調(diào)用它。由于他和gdi的使用有很大的差別,所以要使用gdi+就必須從頭學(xué)。gdi+要比gdi簡單得多。
現(xiàn)在就來看一下如何實(shí)現(xiàn)這個(gè)軟件:先添加picturebox,0penfiledialog,savefiledialog,colordialog,domainupdown,label控件;然后添加兩個(gè)菜單即它們的子菜單,添加的菜單如下"文件"菜單包括"新建","打開","保存","退出","功能"菜單包括"直線","選擇顏色"代碼如下,在代碼后給出程序說明:
public class form1
inherits system.windows.forms.form
public imagepen, newbit, changiamge, mpen 'movepen,moveb,,grh,filenames,endpen
dim xd, yd, xu, yu, pk, ps
private sub menuitem9_click(byval sender as system.object,
byval e as system.eventargs) 'handles menuitem9.click
'新建一個(gè)ico文件,即"新建"菜單
picturebox1.image = nothing
dim bitnew as new system.drawing.bitmap(32, 32,
drawing.imaging.pixelformat.format32bppargb)'建立一個(gè)bitmap對象,以便在它上面畫圖
dim x, y
for x = 0 to 31
for y = 0 to 31
bitnew.setpixel(x, y, color.transparent)'將bitmap的背景設(shè)置為透明
next
next
newbit = bitnew
menuitem3.enabled = false'"選擇顏色"菜單不可用
menuitem2.enabled = true'"直線"菜單可用
end sub
private sub menuitem6_click(byval sender as system.object,
byval e as system.eventargs)' handles menuitem6.click
'打開圖片文件即"打開"菜單"
openfiledialog1.filter = "ico文件(*.ico)|*.ico|圖像文件
(*.bmp;*.jpg;*.jpeg;*.gif;*.png;*.tiff)|*.bmp;*.jpg;*.jpeg;*.gif;*.png;*.tiff"
openfiledialog1.filterindex = 2
openfiledialog1.showdialog()
openfiledialog1.filename = ""
end sub
private sub menuitem8_click(byval sender as system.object,
byval e as system.eventargs) 'handles menuitem8.click
me.close()'退出
end sub
private sub menuitem7_click(byval sender as system.object,
byval e as system.eventargs)
'handles menuitem7.click
'保存文件,即"保存"對話筐
picturebox1.cursor = system.windows.forms.cursors.default
savefiledialog1.filter = "ico文件(*.ico)|*.ico"'設(shè)置要保存的文件后綴
savefiledialog1.showdialog()
if savefiledialog1.filename <> "" then
if not savefiledialog1.showdialog.cancel then
dim bmp as new system.drawing.bitmap(picturebox1.image,
32,32)'從picturebox1.image初始化bitmap,設(shè)置保存為圖片的大小,標(biāo)準(zhǔn)ico圖由
32*32和16*16兩種格式組成,此處為32*32,你也可以設(shè)置為16*16
dim ico as system.drawing.icon = ico.fromhandle(bmp.gethicon())
'用bitmap的句柄,初始化icon,他是專門處理ico文件的類
dim file as new system.io.filestream(savefiledialog1.filename(),
io.filemode.create)'創(chuàng)建文件流
ico.save(file)'保存為ico文件
file.close()'關(guān)閉流
end if
end if
end sub
public sub menuitem2_click(byval sender as system.object,
byval e as system.eventargs)
'handles menuitem2.click
'是用直線在新建的ico中畫圖
picturebox1.cursor =system.windows.forms.cursors.cross
'在picturebox1中鼠標(biāo)的樣式
colordialog1.showdialog()
dim pen as new pen(colordialog1.color, domainupdown1.text())'創(chuàng)建畫筆
imagepen = pen
end sub
private sub picturebox1_mousedown(byval sender as system.object,
byval e as system.windows.forms.mouseeventargs)
'handles picturebox1.mousedown
'當(dāng)按下鼠標(biāo)左鍵時(shí)獲取直線的起點(diǎn)
if e.button = mousebuttons.left then
xd = e.x / 8 : yd = e.y / 8
end if
end sub
private sub picturebox1_mouseup(byval sender as system.object,
byval e as system.windows.forms.mouseeventargs)
'handles picturebox1.mouseup
'畫出直線
if picturebox1.cursor is system.windows.forms.cursors.cross and ps <> 1 then
xu = e.x : yu = e.y
me.k(1, imagepen, yu / 8, xu / 8, xd, yd)
else
if openfiledialog1.filterindex = 1 then
xu = e.x : yu = e.y
me.k(2, mpen, yu / 8, xu / 8, xd, yd)
end if
end if
end sub
public sub k(byval k as integer, byval drawtool as object,
byval x as integer, byval y as integer, byval xs as integer,
byval ys as integer)
if k = 1 then
picturebox1.sizemode = pictureboxsizemode.stretchimage'自動(dòng)容納圖片
picturebox1.image = newbit
dim graphic as graphics
graphic = graphic.fromimage(me.picturebox1.image)'在picturebox1上畫圖
graphic.smoothingmode = drawing.drawing2d.smoothingmode.antialias'鋸齒削邊
graphic.drawline(drawtool, y, x, xs, ys)'畫線
end if
if k = 2 then
picturebox1.sizemode = pictureboxsizemode.stretchimage
picturebox1.image = changiamge
dim graphic as graphics
graphic = graphic.fromimage(me.picturebox1.image)
graphic.smoothingmode = drawing.drawing2d.smoothingmode.antialias
graphic.drawline(drawtool, y, x, xs, ys)
end if
end sub
private sub menuitem3_click(byval sender as system.object,
byval e as system.eventargs)
'handles menuitem3.click
'對打開的ico文件用直線畫圖
colordialog1.showdialog()
dim m3pen as new pen(colordialog1.color, domainupdown1.text())'建立畫筆
mpen = m3pen
end sub
private sub openfiledialog1_fileok(byval sender as object, byval e as
system.componentmodel.canceleventargs)
'handles openfiledialog1.fileok
'打開文件
if openfiledialog1.filterindex = 1 then
dim m3pen as new pen(color.black, domainupdown1.text())
mpen = m3pen
menuitem2.enabled = false
menuitem3.enabled = true
else
menuitem3.enabled = false
menuitem2.enabled = false
end if
if openfiledialog1.filename <> "" then
picturebox1.cursor = system.windows.forms.cursors.default
dim images as new system.drawing.bitmap(openfiledialog1.filename)
changiamge = images
picturebox1.sizemode = pictureboxsizemode.stretchimage
picturebox1.image = images
me.text = openfiledialog1.filename
end if
end sub
private sub form1_load(byval sender as object, byval e as system.eventargs)
'handles mybase.load
'由于剛運(yùn)行次程序時(shí),沒有打開的ico文件和新建立的ico對象所以不可以創(chuàng)建畫圖工具對象
menuitem3.enabled = false
menuitem2.enabled = false
end sub
end class
程序說明:
1. 如何新建ico文件:先初始化bitmap,然后在"功能"-》"直線"菜單代碼中創(chuàng)建畫筆,就可以開始畫了。此時(shí)只是創(chuàng)建的一個(gè)bitmap對象,是我們在picturebox中畫。畫完后將bitmap對象保存到文件,就完成了新建ico的文件。
2.如何打開已有的ico文件,并修改后保存它:判斷打開的文件是否是ico,如果不是就只顯示他,如果是就顯示并且初始化一個(gè)畫筆,通過"功能"-》"選擇顏色"來改變畫出直線的顏色和寬度,然后保存,就完成了對原來ico文件的修改。
3.保存文件和對非ico文件轉(zhuǎn)化為ico文件:通過打開文件,將非ico文件顯示在picturebox中,在用picturebox.image初始化bitmap對象,此句的實(shí)際作用是將當(dāng)前的picturebox.image內(nèi)容附給bitmap。用bitmap的句柄初始icon對象(處理ico文件的對象),作用是將非ico文件轉(zhuǎn)化為ico文件,建立文件流對象,在其中指定新文件名,和訪問方法(文件流是save方法的參數(shù))使用icon對象的save保存,最后關(guān)閉文件流。
4.如何畫:當(dāng)完成1或2后,就可以開始畫圖,畫圖是由sub k過程,mouse-down,mouse-up來實(shí)現(xiàn)的。此時(shí)調(diào)用mouse-down獲得直線的起點(diǎn),在mouse-up中獲得直線終點(diǎn),接著在mouse-up 中調(diào)用sub k過中程綁定bitmap對象到picturebox的image屬性,他的作用類似于有了一張可以畫畫的紙,并在sub k中用graphic.fromimage(me.picturebox1.image)語句創(chuàng)建graphics對象,表示是在picturebox1.image的bitmap對象中畫,而不是在picturebox1上畫,他們的區(qū)別在于前者是可以保存畫畫結(jié)果的,后者不可以。k的值表示是在新建的ico文件中畫還是修改以有的ico文件(k=2是表示修改已有的ico文件)
5.一些語句說明:dim pen …是指用鋼筆來畫,object.rawline(….)表示畫直線,
6.文件格式的轉(zhuǎn)換問題:你可以使用image對象的save的方法來轉(zhuǎn)換圖象的格式,但是我發(fā)現(xiàn)雖然他提供了icon格式,但轉(zhuǎn)化后不是ico文件,而是png文件。從網(wǎng)上的資料顯示這是.net的本身問題。順便提一下image對象無構(gòu)造函數(shù),他雖然標(biāo)為必須繼承才可使用,但實(shí)際上不行,如要使用它要用他的fromfile或fromstream方法來構(gòu)造它。
7.關(guān)于k的問題:當(dāng)你看懂這篇文章后你一定會(huì)提出為什么在每條分支中的picturebox1.sizemode = pictureboxsizemode.stretchimage,picturebox1.image = changiamge這兩句代碼不可以與它后面的代碼分開放在其他地方,如k=1時(shí)放在"新建"菜單中的代碼部分,k=2是放在mouseup中的else后的if語句中!其實(shí)這兩句就是我在編寫這個(gè)程序時(shí)遇到的最大的難題,我用了兩個(gè)小時(shí)才的出這兩句代碼要放在了現(xiàn)在的位置。最后看資料并與朋友探討后得出3個(gè)結(jié)論:
1. .net本身問題。
2.如果分開使picturebox1.image對象丟失(picturebox1.image返回的是bitmap對象),無法綁定到graphics。
3. picturebox1.image對象在sub k中不可見。雖然我不知道那個(gè)結(jié)論是對的,但我將它寫了出來,僅供參考。
對于程序中的0penfiledialog,savefiledialog,colordialog,domainupdown,文件流的使用請見msdn。這5個(gè)只是為了輔助這個(gè)程序而使用的,如果要在這里講清楚那這片文章就太長了,而且這些的使用很簡單。我在程序中使用的畫圖工具是鋼筆,畫出的圖形是直線,這隊(duì)ico文件已經(jīng)夠有了,如果你想使用其他工具,畫其他圖形,只要修改"功能"中的子菜單,和sub k代碼就夠了。
運(yùn)行如圖:
更換后的"我的電腦"圖標(biāo)