wxpython 圖像編程

使用圖像編程

這一章來了解一下咱們可使用圖片來做些什麼事情.一幅圖賽過千言萬語,在wxWidgets,工具條,樹形控件,notebooks,按鈕,Html窗口和特定的繪畫代碼中,都會用到圖片.有時候它們還會在不可見的地方發揮做用,好比咱們能夠用它來建立雙緩衝區以免閃爍.這一章裏,咱們會接觸到各類各樣的圖片類,還會談到怎樣覆蓋wxWidgets提供的默認圖片和圖標。

wxWidgets中圖片相關的類

wxWidgets支持四種和位圖相關的類:wxBitmap, wxIcon, wxCursor和wxImage.

wxBitmap是一個平臺有關的類,它擁有一個可選的wxMask屬性以支持透明繪畫.在windows系統上,wxBitmap是經過設備無關位圖(DIBs)實現的,而在GTK+和X11平臺上,每一個wxBitmap則包含一個GDK的pixmap對象或者X11的pixmap對象.而在Mac平臺上,則使用的是PICT.wxBitmap能夠和wxImage進行互相轉換.linux

wxIcon用來實現各個平臺上的圖標,一個圖標指的是一個小的透明圖片,能夠用來表明不一樣的frame或者對話框窗口.在GTK+,X11和Mac平臺上,icon就是一個小的總含有wxMask的wxBitmp,而在windows平臺上,wxIcon則是封裝了HICON對象.程序員

wxCursor則是一個用來展現鼠標指針的圖像,在GTK+平臺上是用的GdkCursor,X11和Mac平臺上用的是各自的Cursor,而在windows平臺上則使用的是HCURSOR.wxCursor有一個熱點的概念(所謂熱點指的是圖片中用來精確表明指針單擊位置的那個點),也老是包含一個遮罩(mask).算法

wxImage則是四個類中惟一的一個平臺無關的實現,它支持24bit位圖以及可選的alpha通道.wxImage能夠從wxBitmap類使用wxBitmap::ConvertToImage函數轉換而來,也能夠從各類各樣的圖片文件中加載,它所支持的圖片格式也是能夠經過圖片格式處理器來擴展的.它擁有操做其圖片上某些bit的能力,所以也能夠用來對圖片進行一個基本的操做.和wxBitmap不一樣,wxImage不能夠直接被設備上下文wxDC使用,若是要在wxDC上繪圖,須要現將wxImage轉換成wxBitmap,而後就可使用wxDC的DrawBitmap函數進行繪圖了.wxImage支持設置一個掩碼顏色來實現透明的效果,也支持經過alpha通道實現很是複雜的透明效果.編程

你能夠在這些圖片類型之間進行相互轉換,儘管某些轉換操做是平臺相關的.windows

注意圖片類中大量使用引用記數器,所以對圖片類進行賦值和拷貝的操做的系統開銷是很是小的,不過這也意味着對一個圖片的更改可能會影響到別的圖片.app

全部的圖片類都使用下表列出的標準的wxBitmapType標識符來讀取或者保存圖片數據:編輯器

 

ht!|>m3.8cm|>m10.72cm<|位圖類型 wxBITMAP_TYPE_BMP Windows位圖文件 (BMP).
wxBITMAP_TYPE_BMP_RESOURCE 從windows可執行文件資源部分加載的Windows位圖.
wxBITMAP_TYPE_ICO Windows圖標文件(ICO).
wxBITMAP_TYPE_ICO_RESOURCE 從windows可執行文件資源部分加載的Windows圖標.
wxBITMAP_TYPE_CUR Windows光標文件(CUR).
wxBITMAP_TYPE_CUR_RESOURCE 從windows可執行文件資源部分加載的Windows光標.
wxBITMAP_TYPE_XBM Unix平臺上使用的XBM單色圖片.
wxBITMAP_TYPE_XBM_DATA 從C++數據中構造的XBM單色位圖.
wxBITMAP_TYPE_XPM XPM格式圖片,最好的支持跨平臺而且支持編譯到應用程序中去的格式.
wxBITMAP_TYPE_XPM_DATA 從C++數據中構造的XPM圖片.
wxBITMAP_TYPE_TIF TIFF格式位圖,在大圖片中使用比較廣泛.
wxBITMAP_TYPE_GIF GIF格式圖片,最多支持256中顏色,支持透明.
wxBITMAP_TYPE_PNG PNG位圖格式, 一個使用普遍的圖片格式,支持透明和alpha通道,沒有版權問題.
wxBITMAP_TYPE_JPEG JPEG格式位圖, 一個普遍使用的壓縮圖片格式,支持大圖片,不過它的壓縮算法是有損耗壓縮,所以不適合對圖片進行反覆加載和壓縮.
wxBITMAP_TYPE_PCX PCX圖片格式.
wxBITMAP_TYPE_PICT Mac PICT位圖.
wxBITMAP_TYPE_PICT_RESOURCE 從可執行文件資源部分加載的Mac PICT位圖.
wxBITMAP_TYPE_ICON_RESOURCE 僅在Mac OS X平臺上有效, 用來加載一個標準的圖標(好比wxICON_INFORMATION)或者一個圖標資源.
wxBITMAP_TYPE_ANI Windows動畫圖標(ANI).
wxBITMAP_TYPE_IFF IFF位圖文件.
wxBITMAP_TYPE_MACCURSOR Mac光標文件.
wxBITMAP_TYPE_MACCURSOR_RESOURCE 從可執行文件資源部分加載的Mac光標.
wxBITMAP_TYPE_ANY 讓加載圖片的代碼本身肯定圖片的格式.ide

 

使用wxBitmap編程

你可使用wxBitmap來做下面的事情:svn

 

 

  • 經過設備上下文將其畫在一個窗口上.
  • 在某些類(好比wxBitmapButton, wxStaticBitmap, and wxToolBar)中將其做爲一個圖片標籤.
  • 使用其做爲雙緩衝區(在將某個圖形繪製到屏幕上以前先繪製在一塊緩衝區上).

 

某些平臺(特別是windows平臺)上限制了系統中bitmap資源的數目,所以若是你須要使用不少的bitmap,你最好使用wxImage類來保存它們,而只在使用的時候將其轉化成bitmap.函數

在討論怎樣建立wxBitmap以前,讓咱們先來討論一下幾個主要的函數(以下表所示)

 

ht!|>m3.8cm|>m10.72cm<|wxBitmap相關函數 wxBitmap 表明一個bitmap,能夠經過指定寬度和高度,或者指定另一個bitmap,或者指定一個wxImage,XPM數據(char**), 原始數據(char[]), 或者一個指定類型的文件名的方式來建立.
ConvertToImage 轉換成一個wxImage,保留透明部分.
CopyFromIcon 從一個wxIcon建立一個wxBitmap.
Create 從圖片數據或者一個給定的大小建立一個bitmap.
GetWidth, GetHeight 返回圖片大小.
Getdepth 返回圖片顏色深度.
GetMask, SetMask 返回綁定的wxMask對象或者NULL.
GetSubBitmap 將位圖其中的某一部分建立爲一個新的位圖.
LoadFile, SaveFile 從某種支持格式的文件加載或者保存到文件裏.
Ok 若是bitmap的數據已經具有則返回True.

 

建立一個wxBitmap

能夠經過下面的幾個途徑來建立一個wxBitmap對象.

你能夠直接經過默認的構造函數建立一個不包含數據的bitmap,不過你幾乎不能用這個bitmap做任何事情,除非你調用Create或者LoadFile或者用另一個bitmap賦值以便使其擁有具體的bitmap數據.

你還能夠經過指定寬度和高度的方法建立一個位圖,這種狀況下建立的位圖將被填充以隨機的顏色,你須要在其上繪畫以便更好的使用它,下面的代碼演示了怎樣建立一個200x100的圖片而且將其的背景刷新爲白色.

 

 
// 使用當前的顏色深度建立一個200x100的位圖
wxBitmap bitmap(200, 100,  -1);
// 建立一個內存設備上下文
wxMemoryDC dc;
// 將建立的圖片和這個內存設備上下文關聯
dc.SelectObject(bitmap);
// 設置背景顏色
dc.SetBackground(*wxWHITE_BRUSH);
// 繪製位圖背景
dc.Clear();
// 解除設備上下文和位圖的關聯
dc.SelectObject(wxNullBitmap);

你也能夠從一個wxImage對象建立一個位圖,而且保留這個image對象的顏色遮罩或者alpha通道:

 

 
// 加載一幅圖像
wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG);
// 將其轉換成bitmap
wxBitmap bitmap(image);

經過CopyFromIcon函數能夠經過圖標文件建立一個bitmap:

 

 
// 加載一個圖標
wxIcon icon(wxT("image.xpm"), wxBITMAP_TYPE_XPM);
// 將其轉換成位圖
wxBitmap bitmap;
bitmap.CopyFromIcon(icon);

或者你能夠經過指定類型的方式從一個圖片文件直接加載一個位圖:

 

 
// 從文件加載
wxBitmap bitmap(wxT("picture.png", wxBITMAP_TYPE_PNG);
if (!bitmap.Ok())
{
    wxMessageBox(wxT("Sorry, could not load file."));
}

wxBitmap能夠加載全部的能夠被wxImage加載的圖片類型,使用的則是各個平臺定義的針對特定類型的加載方法.最經常使用的圖片格式好比"PNG,JPG,BMP和XPM"等在各個平臺上都支持讀取和保存操做,不過你須要確認你的wxWidgets在編譯的時候已經打開了對應的支持.

目前支持的圖形類型處理函數以下表所示:

 

|>m3.8cm|>m10.72cm<|已支持的圖像類型 wxBMPHandler 用來加載windows位圖文件.
wxPNGHandler 用來加載PNG類型的文件.這種文件支持透明背景以及alpha通道.
wxJPEGHandler 用來支持JPEG文件
wxGIFHandler 由於版權方面的緣由,僅支持GIF格式的加載.
wxPCXHandler 用來支持PCX. wxPCXHandler會本身計算圖片中顏色的數目,若是沒有超過256色,則採用8bits顏色深度,不然就採用24 bits顏色深度.
wxPNMHandler 用來支持PNM文件格式. 對於加載來講PNM格式能夠支持ASCII和raw RGB兩種格式.可是保存的時候僅支持raw RGB格式.
wxTIFFHandler 用來支持TIFF.
wxIFFHandler 用來支持IFF格式.
wxXPMHandler 用來支持XPM格式.
wxICOHandler 用來支持windows平臺圖標文件.
wxCURHandler 用來支持windows平臺光標文件.
wxANIHandler 用來支持windows平臺動畫光標文件.

在Mac OS X平臺上,還能夠經過指定wxBITMAP_TYPE_PICT_RESOURCE來加載一個PICT資源.

若是你但願在不一樣的平臺上從不一樣的位置加載圖片,你可使用wxBITMAP宏,以下所示:

 

 
#if !defined(__WXMSW__) && !defined(__WXPM__)
#include "picture.xpm"
#endif
wxBitmap bitmap(wxBITMAP(picture));

這將使得程序在windows和OS/2平臺上從資源文件中加載圖片,而在別的平臺上,則從一個picture_xpm變量中加載xpm格式的圖片,由於XPM在全部的平臺上都支持,因此這種使用方法並不常見.

 

設置一個wxMask

每一個wxBitmap對象均可以指定一個wxMask,所謂wxMask指的是一個單色圖片用來指示原圖中的透明區域.若是你要加載的圖片中包含透明區域信息(好比XPM,PNG或者GIF格式),那麼wxMask將被自動建立,另外你也能夠經過代碼建立一個wxMask而後調用SetMask函數將其和對應的wxBitmap對象相關連.你還能夠從wxBitmap對象建立一個wxMask,或者經過給一個wxBitmap對象指定一種透明顏色來建立一個wxMask對象.

下面的代碼建立了一個擁有透明色的灰階位圖mainBitmap,它的大小是32x32象素,原始圖形從imageBits數據建立,遮罩圖形從maskBits建立,遮罩中1表明不透明,0表明透明顏色.

 

 
static char imageBits[] = { 255, 255, 255, 255, 31,
  255, 255, 255, 31, 255, 255, 255, 31, 255, 255, 255,
  31, 255, 255, 255, 31, 255, 255, 255, 31, 255, 255,
  255, 31, 255, 255, 255, 31, 255, 255, 255, 25, 243,
  255, 255, 19, 249, 255, 255, 7, 252, 255, 255, 15, 254,
  255, 255, 31, 255, 255, 255, 191, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255 };
static char maskBits[] = { 240, 1, 0, 0, 240, 1,
  0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1,
  0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 255, 31, 0, 0, 255,
  31, 0, 0, 254, 15, 0, 0, 252, 7, 0, 0, 248, 3, 0, 0,
  240, 1, 0, 0, 224, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0 };
wxBitmap mainBitmap(imageBits, 32, 32);
wxBitmap maskBitmap(maskBits, 32, 32);
mainBitmap.SetMask(new wxMask(maskBitmap)); 

 

XPM圖形格式

在使用小的須要支持透明的圖片(好比工具欄上的小圖片或者notebook以及樹狀控件上的小圖片)的時候,wxWidgets的程序員一般偏心使用XPM格式,它的最大的特色是採用C/C++語言的語法,既能夠被程序動態加載,也能夠直接編譯到可執行代碼中去,下面是一個例子:

 

 
// 你也能夠用 #include "open.xpm"
static char *open_xpm[] = {
/* 列數 行數 顏色個數 每一個象素的字符個數 */
"16 15 5 1",
"  c None",
". c Black",
"X c Yellow",
"o c Gray100",
"O c #bfbf00",
/* 象素 */
"                ",
"          ...   ",
"         .   . .",
"              ..",
"  ...        ...",
" .XoX.......    ",
" .oXoXoXoXo.    ",
" .XoXoXoXoX.    ",
" .oXoX..........",
" .XoX.OOOOOOOOO.",
" .oo.OOOOOOOOO. ",
" .X.OOOOOOOOO.  ",
" ..OOOOOOOOO.   ",
" ...........    ",
"                "
};
wxBitmap bitmap(open_xpm);

正如你看到的那樣,XPM是使用字符編碼的.在圖片數據前面,有一個調色板區域,使用字符和顏色對應的方法,顏色既能夠用標準標識符表示,也能夠用16進制的RGB值表示,使用關鍵字None來表示透明區域.儘管在windows系統上,XPM並不被大多數的圖形處理工具支持,不過你仍是能夠經過一些工具把PNG格式轉換成XPM格式,好比DialogBlocks自帶的ImageBlocks工具,或者你能夠直接使用wxWidgets編寫一個你本身的轉換工具.

 

使用位圖繪畫

使用位圖繪畫的方式有兩種,你可使用內存設備上下文綁定一個位圖,而後使用wxDC::Blit函數,也能夠直接使用wxDC::DrawBitmap函數,前者容許你使用位圖的一部分進行繪製.在兩種方式下,若是這個圖片支持透明或者alpha通道,你均可以經過將最後一個參數指定爲True或者False來打開或者關閉透明支持.

這兩種方法的用法以下:

 

 
// Draw a bitmap using a wxMemoryDC
wxMemoryDC memDC;
memDC.SelectObject(bitmap);
// Draw the bitmap at 100, 100 on the destination DC
destDC.Blit(100, 100,                         // Draw at (100, 100)
    bitmap.GetWidth(), bitmap.GetHeight(),    // Draw full bitmap
    & memDC,                                  // Draw from memDC
    0, 0,                                     // Draw from bitmap origin
    wxCOPY,                                   // Logical operation
    true);                                    // Take mask into account
memDC.SelectObject(wxNullBitmap);
// Alternative method: use DrawBitmap
destDC.DrawBitmap(bitmap, 100, 100, true);

第五章,"繪畫和打印"中對使用bitmap繪畫有更詳細的描述.

 

打包位圖資源

若是你曾是一個windows平臺的程序員,你可能習慣從可執行文件的資源部分加載一幅圖片,固然在wxWidgets中也能夠這樣做,你只須要指定一個資源名稱一個資源類型wxBITMAP_TYPE_BMP_RESOURCE,不過這種做法是平臺相關的.你可能更傾向於使用另一種平臺無關的解決方案.

一個可移植的方法是,你能夠將你用到的全部數據文件,包括HTML網頁,圖片或者別的任何類型的文件壓縮在一個zip文件裏,而後你能夠用wxWidgets提供的虛擬文件系統對加載這個zip文件的其中任何一個或幾個文件,以下面的代碼所示:

 

 
// 建立一個文件系統
wxFileSystem*fileSystem = new wxFileSystem;
wxString archiveURL(wxT("myapp.bin"));
wxString filename(wxT("myimage.png"));
wxBitmapType bitmapType = wxBITMAP_TYPE_PNG;
// 建立一個URL
wxString combinedURL(archiveURL + wxString(wxT("#zip:")) + filename);
wxImage image;
wxBitmap bitmap;
// 打開壓縮包中的對應文件
wxFSFile* file = fileSystem->OpenFile(combinedURL);
if (file)
{
    wxInputStream* stream = file->GetStream();

    // Load and convert to a bitmap
    if (image.LoadFile(* stream, bitmapType))
        bitmap = wxBitmap(image);

    delete file;
}
delete fileSystem;
if (bitmap.Ok())
{
    ...
}

更多關於虛擬文件系統的信息請參考第14章:文件和流操做.

 

使用wxIcon編程

一個wxIcon表明一個小的位圖,它總有一個透明遮罩,它的用途包括:

 

 

  • 設置frame窗口或者對話框的圖標
  • 經過wxImageList類給wxTreeCtrl, wxListCtrl或者wxNotebook提供圖標 (更多信息請參考最後一章)
  • 使用wxDC::DrawIcon函數在設備上下文中繪製一個圖標

 

下表列出了圖標類的主要成員函數

 

ht!|>m3.8cm|>m10.72cm<|wxIcon相關函數 wxIcon 圖標類能夠經過指定另一個圖標類的方式,指定XPM數據(char**)的方式, 原始數據(char[])的方式,或者文件名及文件類型的方式建立.
CopyFromBitmap 從wxBitmap類建立一個圖標.
GetWidth, GetHeight 返回圖標的大小.
Getdepth 返回圖標的顏色深度.
LoadFile 從文件加載圖標.
Ok 在圖標數據已經具有的時候返回True.

 

建立一個wxIcon

wxIcon可使用XPM數據建立,或者從一個wxBitmap對象中建立,或者從文件(好比一個Xpm文件)中讀取.wxWidgets也提供了相似於前一小節提到的wxBITMAP相似的宏,用來從一個平臺相關的資源中獲取圖標.

在windows平臺上,LoadFile以及同等性質的操做可使用的文件類型包括BMP圖片和ICO文件,若是你要從其它圖片格式中建立圖標,能夠先將其讀入一個wxBitmap對象中,而後再將其轉換爲一個圖標.

而在Mac OSX和 Unix/Linux的GTK+版本中,wxIcon能夠識別的圖片類型和wxBitmap能夠識別的圖片類型是同樣的.

下面代碼演示了建立一個wxIcon對象的幾種方法:

 

 
// 方法1: 從XPM數據建立
#include "icon1.xpm"
wxIcon icon1(icon1_xpm);
// 方法2: 從一個ICO資源中建立(Window and OS/2 only)
wxIcon icon2(wxT("icon2"));
// 方法3: 從一個圖片文件中 (Windows and OS/2 only)
// 若是你的圖片包含多個圖標你能夠指定單個圖標的寬度
wxIcon icon3(wxT("icon3.ico"), wxBITMAP_TYPE_ICO, 16, 16);
// 方法4: 從位圖建立
wxIcon icon4;
wxBitmap bitmap(wxT("icon4.png"), wxBITMAP_TYPE_PNG);
icon4.CopyFromBitmap(bitmap);

 

使用wxIcon

下面的代碼演示了wxIcon的三種使用方法:設置窗口圖標,增長到一個圖片列表或者繪製在某個設備上下文上

 

 
#include "myicon.xpm"
wxIcon icon(myicon_xpm);
// 1: 設置窗口圖標
frame->SetIcon(icon);
// 2: 增長到wxImageList
wxImageList* imageList = new wxImageList(16, 16);
imageList->Add(icon);
// 3: 在(10, 10)的位置繪製
wxClientDC dc(window);
dc.DrawIcon(icon, 10, 10);

將某個圖標綁定到應用程序

將某個圖標綁定到應用程序,以便系統能夠顯示這個圖標在合適的位置使得用戶能夠經過點擊圖標的方式打開應用程序,這個工做wxWidgets是作不到的.這是極少的你須要在不一樣的平臺使用不一樣的技術的領域中的一個.

在windows平臺上,你須要在makefile中增長一個資源文件(擴展名是.rc),而且在這個資源文件中指定一個圖標區域,以下所示:

 

 
aardvarkpro ICON aardvarkpro.ico
#include "wx/msw/wx.rc"

在這裏, aardvarkpro.ico就是這個和應用程序綁定的圖標的名稱,它能夠有多種分辨率和顏色深度(典型的大小包括48x48,32x32和16x16).當windows的資源管理器須要顯示某個圖標的時候,它將使用子母順序排在第一個的那個圖標,所以你最好給肯定要做爲應用程序圖標的那個圖標的名稱前面加幾個a子母以便按照子母順序它排在前面,不然你的應用程序可能綁定的是你不指望的圖標.

在Mac系統上,你須要準備一個應用程序包,其中包含一些ICNS文件.參考第20章"讓你的程序更完美",來得到關於程序包更多的信息,其中的主要文件Info.plist文件看上去應該象下面的額樣子:

 

 
  <key>CFBundleDocumentTypes</key>
  <array>
         <dict>
               <key>CFBundleTypeExtensions</key>
               <array>
                        <string>pjd</string>
                 </array>
                 <key>CFBundleTypeIconFile</key>
                 <string>dialogblocks-doc.icns</string>
                 <key>CFBundleTypeName</key>
                 <string>pjdfile</string>
                 <key>CFBundleTypeRole</key>
                 <string>Editor</string>
           </dict>
    </array>
    <key>CFBundleIconFile</key>
    <string>dialogblocks-app.icns</string>
...

應用程序圖標和應用程序相關的文檔類型圖標是由CFBundleIconFile和CFBundleTypeIconFile屬性指定的.你能夠直接用Apple提供圖標編輯器編輯ICNS文件,不過若是你但願全部的平臺使用一樣的圖標,你最好現用PNG圖片建立各類大小的圖標,而後再將它粘貼到各個平臺上的圖標編輯器中,要確保PNG使用的透明遮罩顏色和各個工具使用的透明顏色相一致.

而在linux平臺上,Gnome桌面系統和KDE桌面系統則各自擁有本身的圖標提供體系,咱們將在第20章進行簡要的描述.

 

使用wxCursor編程

光標用來指示鼠標指針當前的位置.你能夠給某個窗口指定不一樣的光標以便提示用戶這個窗口期待某種類型的鼠標操做.和圖標同樣,光標也是一種始終帶有透明遮罩的小圖片,可使用通常的構造函數或者是平臺相關的構造函數來建立.其中的一些構造函數還須要相對於整個圖片的左上角指定一個熱點位置,當鼠標點擊的時候,熱點所在的位置將做爲鼠標點擊的位置.

下表列舉了光標相關的函數

|>m3.8cm|>m10.72cm<|wxCursor相關函數 wxCursor 光標能夠從wxImage對象,二進制數據,系統定義的光標標識符以及光標文件來建立.
Ok 若是光標數據已經具有,則返回True.

 

建立一個光標

建立光標最簡單的方法是經過系統提供的光標標識符,以下面的例子所示:

 

 
wxCursor cursor(wxCURSOR_WAIT);

下表列出了目前支持的光標標識符和它們的光標的樣子(依照平臺的不一樣會有些變化)

 

 

|l|l|p3in| 預約義的光標標識符
[]續上頁
未完待續 wxCURSOR_ARROW 標準光標.
wxCURSOR_RIGHT_ARROW 標準反向光標.
wxCURSOR_BLANK 透明光標.
wxCURSOR_BULLSEYE 近視眼.
wxCURSOR_CROSS 十字.
wxCURSOR_HAND 手.
wxCURSOR_IBEAM I字光標.
wxCURSOR_LEFT_BUTTON 按左鍵(GTK+ only).
wxCURSOR_MAGNIFIER 放大鏡.
wxCURSOR_MIDDLE_BUTTON 按中鍵(譯者注:原書圖片有誤) (GTK+ only).
wxCURSOR_NO_ENTRY 禁止通行.
wxCURSOR_PAINT_BRUSH 畫刷.
wxCURSOR_PENCIL 鉛筆.
wxCURSOR_POINT_LEFT 向左.
wxCURSOR_POINT_RIGHT 向右.
wxCURSOR_QUESTION_ARROW 帶問號的箭頭.
wxCURSOR_RIGHT_BUTTON 按右鍵(譯者注:圖片有誤) (GTK+ only).
wxCURSOR_SIZENESW 東北到西南伸縮.
wxCURSOR_SIZENS 南北伸縮.
wxCURSOR_SIZENWSE 西北到東南伸縮.
wxCURSOR_SIZEWE 東西伸縮.
wxCURSOR_SIZING 通常伸縮.
wxCURSOR_SPRAYCAN 畫刷.
wxCURSOR_WAIT 等待.
wxCURSOR_WATCH 查看.
wxCURSOR_ARROWWAIT 後臺忙.

 

你還可使用預約義光標指針wxSTANDARD_CURSOR, wxHOURGLASS_CURSOR和wxCROSS_CURSOR.

另外在windows和Mac平臺上還能夠從對應的資源文件中加載光標:

 

 
//windows平臺
wxCursor cursor(wxT("cursor_resource"), wxBITMAP_TYPE_CUR_RESOURCE,
                 hotSpotX, hotSpotY);
// Mac平臺
wxCursor cursor(wxT("cursor_resource"), wxBITMAP_TYPE_MACCUR_RESOURCE);

你還能夠經過wxImage對象建立光標,而"熱點"則要經過wxImage::SetOptionInt函數設置.之因此要設置熱點,是由於不少光標不太適合使用默認的左上角做爲熱點,好比對於十字光標來講,你可能但願將其十字交叉的地方做爲熱點.下面的代碼演示了怎樣從一個PNG文件中產生設置了熱點的光標:

 

 
// 用wxImage建立光標
wxImage image(wxT("cursor.png"), wxBITMAP_TYPE_PNG);
image.SetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X, 5);
image.SetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 5);
wxCursor cursor(image);

 

使用wxCursor

每一個窗口均可以設置一個對應的光標,這個光標在鼠標進入這個窗口的時候顯示,若是一個窗口沒有設置光標,其父窗口的光標將被顯示,若是全部的父窗口都沒有設置光標,則系統默認光標被顯示:

使用下面的代碼給窗口設置一個光標:

 

 
window->SetCursor(wxCursor(wxCURSOR_WAIT));

使用wxSetCursorEvent

在windows系統或者是Mac OS X系統上,有一些小地方咱們須要注意一下.舉個例子,若是你本身實現了一個容器類,比方說是一個分割窗口,而且給它設置了一個特殊的光標(好比說wxCURSOR_WE用來代表某個分割條是能夠被拉動的),而後你在這個分割窗口中放置了兩個子窗口,若是你沒有給這兩個子窗口設置光標的話,當光標在子窗口上移動時,它們可能會不恰當的顯示其父窗口,那個wxCURSOR_WE光標.而原本你是但願只有在鼠標移動到分割條上的時候才顯示的.

要告訴wxWidgets某個光標只應該在某種狀況下被顯示,你能夠增長一個wxSetCursorEvent事件的處理函數,這個事件在Windows和Mac平臺上,當須要設置光標的時候(一般是鼠標在窗口間移動的時候)被產生.在這個事件處理函數中能夠調用wxSetCursorEvent::SetCursor來設置一個特殊的光標.以下所示:

 

 
BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow)
    EVT_SET_CURSOR(wxSplitterWindow::OnSetCursor)
END_EVENT_TABLE()
// 指示光標只應該被設置給分割條
void wxSplitterWindow::OnSetCursor(wxSetCursorEvent& event)
{
    if ( SashHitTest(event.GetX(), event.GetY(), 0) )
    {
        // 使用默認的處理
        event.Skip();
    }
    //else:什麼也不做,換句話說,不調用Skip.則事件表不會被繼續搜索
}

在這個例子中,當鼠標指針移過度割條的時候,SashHitTest函數返回True,所以Skip函數被調用,事件表調用失敗,這和沒有定義這個事件表的效果是同樣的,致使wxWidgets象往常同樣顯示指定給窗口的光標(wxCURSOR_WE).而若是SashHitTest函數返回False,則代表光標是在子窗口上移動,這時候應該不顯示咱們指定的光標,所以咱們不調用Skip函數,讓事件表匹配成功,則事件表將不會在繼續匹配,這將使得wxWidgets認爲這個窗口沒有被指定光標,所以.在這種狀況下,即便子窗口本身沒有光標(象wxTextCtrl這種控件,通常系統會指定一個它本身的光標,不過wxWidgets對這個是不感知的),也將不會使用咱們指定給父窗口的光標.

 

使用wxImage編程

你可使用wxImage對圖形進行一些平臺無關的調整,或者將其做爲圖片加載和保存的中間步驟.圖片在wxImage中是按照每個象素使用一個分別表明紅色,綠色和藍色的字節的格式保存的,若是圖片包含alpha通道,則還會佔用額外的一個字節.

wxImage主要的函數以下:

 

ht!|>m3.8cm|>m10.72cm<|wxImage相關函數 wxImage wxImage的建立方法包括:指定寬度和高度, 從另一幅圖片建立, 使用XPM數據, 圖片元數據(char[]) 和可選的alpha通道數據,文件名及其類型,以及經過輸入流等多種方式建立.
ConvertAlphaToMask 將alpla通道(若是有的話)轉換成一個透明遮罩.
ConvertToMono 轉換成一個黑白圖片.
Copy 返回一個不使用引用記數器的徹底同樣的拷貝.
Create 建立一個指定大小的圖片,可選的參數指明是否初始化圖片數據.
Destroy 若是沒有人再使用的話,釋放內部數據.
GeTData, SetData 獲取和設置內部數據指針(unsigned char*).
GetImageCount 返回一個文件或者流中的圖片個數.
GetOption, GetOptionInt, SetOption, HasOption 獲取, 設置和測試某個選項是否設置.
GetSubImage 將圖片的一部分返回爲一個新的圖像.
GetWidth, GetHeight 返回圖片大小.
Getred, GetGreen, GetBlue, SetRGB, GetAlpha, SetAlpha 得到和指定某個象素的RGB以及Alpha通道的值.
HasMask, GetMaskRed, GetMaskGreen, GetMaskBlue, SetMaskColour 用來測試圖像是否有一個遮罩,以及遮罩顏色的RGB值或者整個顏色的值.
LoadFile, SaveFile 各類圖片格式文件的讀取和保存操做.
Mirror 在各類方向上產生鏡像,返回一個新圖片.
Ok 判斷圖片是否已初始化.
Paste 將某個圖片粘貼在這個圖片的指定位置.
Rotate, Rotate90 旋轉圖片,返回一個新圖片.
SetMaskFromImage 經過指定的圖片和透明顏色產生一個遮罩而且設置這個遮罩.
Scale, Rescale 縮放產生一個新圖片或者縮放本圖片.

 

加載和保存圖像

wxImage能夠讀取和保存各類各樣的圖片格式,而且使用圖像處理過程來增長擴展的能力.其它的圖像類(好比wxBitmap)在某個平臺不具有處理某種圖形格式的能力的時候,也一般使用的都是wxImage的圖象處理過程來加載特定格式的圖形.

本章第二小節中展現了wxWidgets支持的各類圖形處理過程.其中wxBMPHandler是默認支持的,而要支持其它的圖形格式處理,就須要使用wxImage::AddHandler函數增長對應的圖形處理過程或者使用wxInitAllImageHandlers增長全部支持的圖形處理過程.

若是你只須要特定的圖形格式支持,能夠在OnInit函數中使用相似下面的代碼:

 

 
#include "wx/image.h"
wxImage::AddHandler( new wxPNGHandler );
wxImage::AddHandler( new wxJPEGHandler );
wxImage::AddHandler( new wxGIFHandler );
wxImage::AddHandler( new wxXPMHandler );

或者,你能夠簡單的調用:

 

 
wxInitAllImageHandlers();

下面演示了幾種從文件或者流讀取圖片的方式,注意在實際使用過程當中,最好使用絕對路徑以免依賴於當前路徑的設置:

 

 
// 使用構造函數指定類型來讀取圖像
wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG);
if (image.Ok())
{
    ...
}
// 不指定圖像類型通常也能正常工做
wxImage image(wxT("image.png"));
// 使用兩步法建立圖像
wxImage image;
if (image.LoadFile(wxT("image.png")))
{
    ...
}
/* 若是一個文件包含兩副圖片Two-step loading with an 
index into a multi-image file:*/
// 下面演示選擇第2副加載
wxImage image;
int imageCount = wxImage::GetImageCount(wxT("image.tif"));
if (imageCount > 2)
    image.LoadFile(wxT("image.tif"), wxBITMAP_TYPE_TIFF, 2);
// 從文件流加載圖片
wxFileInputStream stream(wxT("image.tif"));
wxImage image;
image.LoadFile(stream, wxBITMAP_TYPE_TIF);
// 保存到一個文件
image.SaveFile(wxT("image.png")), wxBITMAP_TYPE_PNG);
// 保存到一個流
wxFileOutputStream stream(wxT("image.tif"));
image.SaveFile(stream, wxBITMAP_TYPE_TIF);

除了XPM和PCX格式之外,其它的圖片格式都將以24位顏色深度保存(譯者注:GIF格式由於版權方面的緣由不支持保存到文件),這兩種格式的圖形處理過程將會計算實際的顏色個數從而選擇相應的顏色深度.JPEG格式還擁有一個質量選項可供設置.它的值的範圍爲從0到100,0表明最低的圖片質量和最高的壓縮比,100則表明最高的圖片質量和最低的壓縮比.以下所示:

 

 
// 設置一個合理的質量壓縮比
image.SetOption(wxIMAGE_OPTION_QUALITY, 80);
image.SaveFile(wxT("picture.jpg"), wxBITMAP_TYPE_JPEG);

另外若是以XPM格式保存到流輸出中的時候,須要使用wxImage::SetOption函數設置一個名稱不然,處理函數不知道該用什麼名稱命名對應的C變量.

 

 
// 保存XPM到流格式
image.SetOption(wxIMAGE_OPTION_FILENAME, wxT("myimage"));
image.SaveFile(stream, wxBITMAP_TYPE_XPM);

注意處理函數會自動在你設置的名稱後增長"_xpm".

 

透明

有兩種方式設置一個wxImage爲透明的圖像:使用顏色遮罩或者alpha通道.一種顏色能夠被指定爲透明顏色,經過這種方法在將wxImage轉換成wxBitmap的時候能夠很容易的製做一個透明遮罩.

wxImage也支持alpha通道數據,在每個象素的RGB顏色以外來由另一個字節用來指示alpha通道的值,0表明徹底透明,255則表明徹底不透明.中間的值表明半透明.

不是全部的圖片都用有alpha通道數據的,所以在使用GetAlpha函數以前,應該使用HasAlpha函數來判斷圖像是否擁有alpha通道數據.到目前爲止,只有PNG文件或者調用SetAlpha設置了alpha通道的圖像才擁有alpha通道數據.保存一個帶有alpha通道的圖像目前還不被支持.繪製一個擁有alpha通道的方法是先將其轉換成wxBitmap而後使用wxDC::DrawBitmap或者wxDC::Blit函數.

下面的代碼演示了怎樣使用顏色掩碼建立一個透明的wxImage,它是藍色的,擁有一個透明的矩形區域:

 

 
// 建立一個有顏色掩碼的wxBitmap
// 首先,在這個wxBitmap上繪畫
wxBitmap bitmap(400, 400);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.SetBackground(*wxBLUE_BRUSH);
dc.Clear();
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle(50, 50, 200, 200);
dc.SelectObject(wxNullBitmap);
// 將其轉換成wxImage
wxImage image = bitmap.ConvertToImage();
// 設置掩碼顏色
image.SetMaskColour(255, 0, 0);

在下面的例子中,使用從一個圖片建立顏色遮罩的方式,其中image.bmp是原始圖像,而mask.bmp則是一個掩碼圖像,在後者中全部透明的部分都是黑色顯示的.

 

 
// 加載一副圖片和它的掩碼遮罩
wxImage image(wxT("image.bmp"), wxBITMAP_TYPE_BMP);
wxImage maskImage(wxT("mask.bmp"), wxBITMAP_TYPE_BMP);
// 從後者建立一個遮罩而且設置給前者.
image.SetMaskFromImage(maskImage, 0, 0, 0);

若是你加載的圖片自己含有透明顏色,你能夠檢測而且直接建立遮罩:

 

 
// 加載透明圖片
wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG);
// 獲取掩碼
if (image.HasMask())
{
    wxColour maskColour(image.GetMaskRed(),
    image.GetMaskGreen(),
    image.GetMaskBlue());
}

 

變形

wxImage支持縮放,旋轉以及鏡像等多種變形方式,下面各舉一些例子:

 

 
// 把原始圖片縮放到200x200,並保存在新的圖片裏
// 原圖保持不變.
wxImage image2 = image1.Scale(200, 200);
// 將原圖縮放到200x200
image1.Rescale(200, 200);
// 旋轉固定角度產生新圖片.
// 原圖片保持不變.
wxImage image2 = image1.Rotate(0.5);
// 順時針旋轉90度產生新圖片.
// 原圖保持不變.
wxImage image2 = image1.Rotate90(true);
// 水平鏡像產生新圖片.
// 原圖保持不變.
wxImage image2 = image1.Mirror(true);

 

顏色消減

若是你想對某個圖像的顏色進行消減,你可使用wxQuantize類的一些靜態函數,其中最有趣的函數Quantize的參數爲一個輸入圖片,一個輸出圖片,一個可選的wxPalette**指針用來存放通過消減的顏色,以及一個你但願保留的顏色個數,你也能夠傳遞一個unsigned char**變量來獲取一個8-bit顏色深度的輸出圖像.最後的一個參數style(類型)用來對返回的圖像進行一些更深刻的控制,詳情請參考wxWidgets的手冊.

下面的代碼演示了怎樣將一幅圖片的顏色消減到最多256色:

 

 
#include "wx/image.h"
#include "wx/quantize.h"
wxImage image(wxT("image.png"));
int maxColorCount = 256;
int colors = image.CountColours();
wxPalette* palette = NULL;
if (colors > maxColorCount )
{
    wxImage reducedImage;
    if (wxQuantize::Quantize(image, reducedImage,
                               & palette, maxColorCount))
    {
        colors = reducedImage.CountColours();
        image = reducedImage;
    }
}

一個wxImage能夠設置一個wxPalette,例如加載GIF文件的時候. 而後,圖片內部仍然是以RGB的方式存儲數據的,調色板僅表明圖片加載時候的顏色隱射關係.調色板的另一個用途是某些圖片處理函數用它來將圖片保存爲低顏色深度的圖片,例如windows的BMP圖片處理過程將檢測是否設置了wxBMP_8BPP_PALETTE標記,若是設置了,則將使用調色板.而若是設置了wxBMP_8BPP標記(而不是wxBMP_8BPP_PALETTE),它將使用本身的算法進行顏色消減.另外某些圖片處理過程本身也進行顏色消減,好比PCX的處理過程,除非它認爲剩餘的顏色個數已經足夠低了,不然它將對圖片的顏色進行消減.

關於調色板更多的信息請參考第5章的"調色板"小節.

 

直接操做wxImage 的元數據

你能夠直接經過GetData函數訪問wxImage的元數據以便以比GeTRed, GetBlue, GetGreen和SetRGB更快的方式對其進行操做,下面舉了一個使用這種方法將一個圖片轉換成灰度圖片的方法:

 

 
void wxImage::ConvertToGrayScale(wxImage& image)
{
    double red2Gray   = 0.297;
    double green2Gray = 0.589;
    double blue2Gray  = 0.114;
    int w = image.GetWidth(), h = image.GetHeight();
    unsigned char *data = image.GetData();
    int x,y;
    for (y = 0; y < h; y++)
        for (x = 0; x < w; x++)
        {
            long pos = (y * w + x) * 3;
            char g = (char) (data[pos]*red2Gray +
                              data[pos+1]*green2Gray +
                              data[pos+2]*blue2Gray);
            data[pos] = data[pos+1] = data[pos+2] = g;
        }
}

 

圖片列表和圖標集

有時候,使用一組圖片是很是方便的.這時候,你能夠直接在你的代碼中使用wxImageList,也能夠和wxWidgets提供的一些控件一塊兒使用wxImageList,wxNotebook,wxtreeCtrl和wxListCtrl都須要wxImageList來管理它們所須要使用的圖標.你也可以使用wxImageList中的某個單獨的圖片在設備上下文上繪畫.

建立一個wxImageList須要的參數包括單個圖片的寬度和高度,一個bool值來指定是否須要指定圖片遮罩,以及這個圖片列表的初始大小(主要是爲了內部優化代碼),而後一個一個的增長wxBitmap對象或者wxIcon對象.wxImageList不能直接使用wxImage對象,你須要先將其轉換爲wxBitmap對象.wxImageList::Add函數返回一個整數的索引用來表明這個剛增長的圖片,在Add函數成功返回之後,你就能夠釋放原始圖片了,wxImageList已經在內部建立了一個這個圖片的拷貝.

下面是建立wxImageList以及在其中增長圖片的一些例子:

 

 
// 建立一個wxImageList
wxImageList *imageList = new wxImageList(16, 16, true, 1);
// 增長一個透明的PNG文件
wxBitmap bitmap1(wxT("image.png"), wxBITMAP_TYPE_PNG);
imageList->Add(bitmap1);
// 增長一個透明的來自別的bitmap的圖片
wxBitmap bitmap2(wxT("image.bmp"), wxBITMAP_TYPE_BMP);
wxBitmap maskBitmap(wxT("mask.bmp"), wxBITMAP_TYPE_BMP);
imageList->Add(bitmap2, maskBitmap);
// 增長一個指定透明顏色的透明圖片
wxBitmap bitmap3(wxT("image.bmp"), wxBITMAP_TYPE_BMP);
imageList->Add(bitmap3, *wxRED);
// 增長一個圖標
#include "folder.xpm"
wxIcon icon(folder_xpm);
imageList->Add(icon);

你能夠直接把wxImageList中的圖片繪製在設備上下文上,經過指定wxIMAGELIST_DRAW_TRANSPARENT類型來指示繪製透明圖片,你還能夠指定的類型包括wxIMAGELIST_DRAW_NORMAL, wxIMAGELIST_DRAW_SELECTED或者wxIMAGELIST_DRAW_FOCUSED,用來表徵圖片的狀態,以下所示:

 

 
// 繪製列表中全部的圖片
wxClientDC dc(window);
size_t i;
for (i = 0; i < imageList->GetImageCount(); i++)
{
    imageList->Draw(i, dc, i*16, 0, wxIMAGELIST_DRAW_NORMAL|
                                    wxIMAGELIST_DRAW_TRANSPARENT);
}

要把圖片列表和notebook的TAB頁面綁定在一塊兒,你須要建立一個包含大小爲16x16的圖片的列表,而後調用wxNotebook::SetImageList或者wxNotebook::AssignImageList將其和某個wxNotebook綁定,這兩個函數的區別在於,前者在wxNotebook釋放的時候不釋放列表,然後者在本身被釋放的時候,會同時釋放圖片列表.指定完圖片列表之後,你就能夠給某個頁面指定圖標索引以便在頁面標籤上顯示圖標了,下面的代碼演示了這個過程:

 

 
//建立一個wxImageList
wxImageList *imageList = new wxImageList(16, 16, true, 1);
// 增長一些圖標
wxBitmap bitmap1(wxT("folder.png"), wxBITMAP_TYPE_PNG);
wxBitmap bitmap2(wxT("file.png"), wxBITMAP_TYPE_PNG);
int folderIndex = imageList->Add(bitmap1);
int fileIndex = imageList->Add(bitmap2);
// 建立一個擁有兩個頁面的notebook
wxNotebook* notebook = new wxNotebook(parent, wxID_ANY);
wxPanel* page1 = new wxPanel(notebook, wxID_ANY);
wxPanel* page2 = new wxPanel(notebook, wxID_ANY);
// 綁定圖片列表
notebook->AssignImageList(imageList);
// Add the pages, with icons
notebook->AddPage(page1, wxT("Folder options"), true, folderIndex);
notebook->AddPage(page2, wxT("File options"), false, fileIndex);

wxtreeCtrl和wxListCtrl的使用方法和上面介紹的很是類似,也包含相似的兩種綁定方法.

若是你擁有不少圖標,有時候很難經過索引來對應到具體的圖標,你可能想編寫一個類以便經過字符串來找到某個圖片索引.下面演示了基於這個目的的一個簡單的實現:

 

 
#include "wx/hashmap.h"
WX_DECLARE_STRING_HASH_MAP(int, IconNameToIndexHashMap);
// 經過名字引用圖片的類
class IconNameToIndex
{
public:
    IconNameToIndex() {}
    // 在圖片列表中增長一個已經命名的圖片
    void Add(wxImageList* list, const wxBitmap& bitmap,
        const wxString& name) {
        m_hashMap[name] = list->Add(bitmap);
    }
    // 在圖片列表中增長一個已命名的圖標
    void Add(wxImageList* list, const wxIcon& icon,
        const wxString& name) {
        m_hashMap[name] = list->Add(icon);
    }
    // 經過名稱找到索引
    int Find(const wxString& name) { return m_hashMap[name]; }
private:
    IconNameToIndexHashMap m_hashMap;
};

wxIconBundle類一樣也是一個圖片列表,不過這個類的目的是爲了將多個不一樣分辨率的圖標保存在一個類中而不是多個類中,以便系統在合適的時候根據不一樣的使用目的選擇一個特定的圖標.好比,在資源管理器中的圖標一般比在主窗口標題欄上顯示的圖標要大的多.下面的例子演示了其用法:

 

 
// 建立一個只有單個16x16圖標的圖片集
#include "file16x16.xpm"
wxIconBundle iconBundle(wxIcon(file16x16_xpm));
// 在圖片集中增長一個32x32的圖片
iconBundle.Add(wxIcon(wxT("file32x32.png"), wxBITMAP_TYPE_PNG));
// 從一個包含多個圖片的文件中建立一個圖片集
wxIconBundle iconBundle2(wxT("multi-icons.tif"), wxBITMAP_TYPE_TIF);
// 從圖片集中獲取指定大小的圖片,若是找不到則繼續尋找
// wxSYS_ICON_X, wxSYS_ICON_Y大小的圖片
wxIcon icon = iconBundle.GetIcon(wxSize(16,16));
// 將圖片集指定給某個主窗口
wxFrame* frame = new wxFrame(parent, wxID_ANY);
frame->SetIcons(iconBundle);

在windows系統上,SetIcons函數期待一個包含16x16和32x32大小的圖標的圖標集.

 

自定義wxWidgets提供的小圖片

wxArtProvider這個類容許你更改wxWidgets默認提供的那些小圖片,好比wxWidgets HTML幫助閱讀器中或者默認的Log對話框中使用的圖片.

wxWidgets提供了一個標準的wxArtProvider對象,而且體系內的一些須要使用圖標和小圖片的地方都調用了這個類的wxArtProvider::GetBitmap和wxArtProvider::GetIcon函數.

小圖片是由兩個標識符決定的:主標識符(wxArtID)和客戶區標識符(wxArtClient).其中客戶區標識符只在同一個主標識符在不一樣的窗口中須要不一樣的圖片的時候才使用,好比,wxHTML幫助窗口使用的圖標使用下面的代碼取得的:

 

 
wxBitmap bmp = wxArtProvider::GetBitmap(wxART_GO_BACK,wxART_TOOLBAR);

若是你想瀏覽全部wxWidgets提供的小圖片以及它們的標識符,你能夠編譯和運行wxWidgets自帶的samples/artprov中的例子,它的外觀以下圖所示:

 

wxWidgets提供的artprov例子

要替換wxWidgets提供的這些小圖片,你須要實現一個wxArtProvider的派生類,重載其中的CreateBitmap函數,而後在OnInit函數中調用wxArtProvider::PushProvider以便讓wxWidgets知道.下面的這個例子替換了wxHTML幫助窗口中的大部分默認的圖標:

 

 
// 新的圖標
#include "bitmaps/helpbook.xpm"
#include "bitmaps/helppage.xpm"
#include "bitmaps/helpback.xpm"
#include "bitmaps/helpdown.xpm"
#include "bitmaps/helpforward.xpm"
#include "bitmaps/helpoptions.xpm"
#include "bitmaps/helpsidepanel.xpm"
#include "bitmaps/helpup.xpm"
#include "bitmaps/helpuplevel.xpm"
#include "bitmaps/helpicon.xpm"
#include "wx/artprov.h"
class MyArtProvider : public wxArtProvider
{
protected:
    virtual wxBitmap CreateBitmap(const wxArtID& id,
                                  const wxArtClient& client,
                                  const wxSize& size);
};
// 新的CreateBitmap函數
wxBitmap MyArtProvider::CreateBitmap(const wxArtID& id,
                                     const wxArtClient& client,
                                     const wxSize& size)
{
    if (id == wxART_HELP_SIDE_PANEL)
        return wxBitmap(helpsidepanel_xpm);
    if (id == wxART_HELP_SETTINGS)
        return wxBitmap(helpoptions_xpm);
    if (id == wxART_HELP_BOOK)
        return wxBitmap(helpbook_xpm);
    if (id == wxART_HELP_FOLDER)
        return wxBitmap(helpbook_xpm);
    if (id == wxART_HELP_PAGE)
        return wxBitmap(helppage_xpm);
    if (id == wxART_GO_BACK)
        return wxBitmap(helpback_xpm);
    if (id == wxART_GO_FORWARD)
        return wxBitmap(helpforward_xpm);
    if (id == wxART_GO_UP)
        return wxBitmap(helpup_xpm);
    if (id == wxART_GO_DOWN)
        return wxBitmap(helpdown_xpm);
    if (id == wxART_GO_TO_PARENT)
        return wxBitmap(helpuplevel_xpm);
    if (id == wxART_FRAME_ICON)
        return wxBitmap(helpicon_xpm);
    if (id == wxART_HELP)
        return wxBitmap(helpicon_xpm);

    // Any wxWidgets icons not implemented here
    // will be provided by the default art provider.
    return wxNullBitmap; 
}
// 你的初始化函數
bool MyApp::OnInit()
{
    ...
    wxArtProvider::PushProvider(new MyArtProvider);
    ...
    return true;
}

 

本章小結

在這一章裏,咱們學習了怎樣使用wxWidgets中的圖片相關的類wxBitmap, wxIcon, wxCursor和wxImage,還學習了怎樣使用wxImageList和wxIconBundle,以及怎樣定義wxWidgets默認使用的小圖片.更多相關的例子請參考wxWidgets自帶的samples/image, samples/listctrl和samples/dragimag目錄中的例子.

在下一章裏,咱們將介紹一下怎樣使用剪貼板來傳輸數據以及怎樣實現拖放編程.


LaTeX Original
\chapter{使用圖像編程}
這一章來了解一下咱們可使用圖片來做些什麼事情.一幅圖賽過千言萬語,在wxWidgets,工具條,樹形控件,notebooks,按鈕,Html窗口和特定的繪畫代碼中,都會用到圖片.有時候它們還會在不可見的地方發揮做用,好比咱們能夠用它來建立雙緩衝區以免閃爍.這一章裏,咱們會接觸到各類各樣的圖片類,還會談到怎樣覆蓋wxWidgets提供的默認圖片和圖標。
\section{wxWidgets中圖片相關的類}
wxWidgets支持四種和位圖相關的類:wxBitmap, wxIcon, wxCursor和wxImage.

wxBitmap是一個平臺有關的類,它擁有一個可選的wxMask屬性以支持透明繪畫.在windows系統上,wxBitmap是經過設備無關位圖(DIBs)實現的,而在GTK+和X11平臺上,每一個wxBitmap則包含一個GDK的pixmap對象或者X11的pixmap對象.而在Mac平臺上,則使用的是PICT.wxBitmap能夠和wxImage進行互相轉換.

wxIcon用來實現各個平臺上的圖標,一個圖標指的是一個小的透明圖片,能夠用來表明不一樣的frame或者對話框窗口.在GTK+,X11和Mac平臺上,icon就是一個小的總含有wxMask的wxBitmp,而在windows平臺上,wxIcon則是封裝了HICON對象.

wxCursor則是一個用來展現鼠標指針的圖像,在GTK+平臺上是用的GdkCursor,X11和Mac平臺上用的是各自的Cursor,而在windows平臺上則使用的是HCURSOR.wxCursor有一個熱點的概念(所謂熱點指的是圖片中用來精確表明指針單擊位置的那個點),也老是包含一個遮罩(mask).

wxImage則是四個類中惟一的一個平臺無關的實現,它支持24bit位圖以及可選的alpha通道.wxImage能夠從wxBitmap類使用wxBitmap::ConvertToImage函數轉換而來,也能夠從各類各樣的圖片文件中加載,它所支持的圖片格式也是能夠經過圖片格式處理器來擴展的.它擁有操做其圖片上某些bit的能力,所以也能夠用來對圖片進行一個基本的操做.和wxBitmap不一樣,wxImage不能夠直接被設備上下文wxDC使用,若是要在wxDC上繪圖,須要現將wxImage轉換成wxBitmap,而後就可使用wxDC的DrawBitmap函數進行繪圖了.wxImage支持設置一個掩碼顏色來實現透明的效果,也支持經過alpha通道實現很是複雜的透明效果.

你能夠在這些圖片類型之間進行相互轉換,儘管某些轉換操做是平臺相關的.

注意圖片類中大量使用引用記數器,所以對圖片類進行賦值和拷貝的操做的系統開銷是很是小的,不過這也意味着對一個圖片的更改可能會影響到別的圖片.

全部的圖片類都使用下表列出的標準的wxBitmapType標識符來讀取或者保存圖片數據:

\begin{mytblex}{ht!}{|>{\setlength{\baselineskip}{15pt}}m{3.8cm}|>{\vspace*{5pt}\setlength{\baselineskip}{15pt}}m{10.72cm}<{\vspace*{3pt}}|}{位圖類型}\hline 
wxBITMAP\_TYPE\_BMP & Windows位圖文件 (BMP).\\
\hline
wxBITMAP\_TYPE\_BMP\_RESOURCE & 從windows可執行文件資源部分加載的Windows位圖.\\
\hline
wxBITMAP\_TYPE\_ICO & Windows圖標文件(ICO).\\
\hline
wxBITMAP\_TYPE\_ICO\_RESOURCE & 從windows可執行文件資源部分加載的Windows圖標.\\
\hline
wxBITMAP\_TYPE\_CUR & Windows光標文件(CUR).\\
\hline
wxBITMAP\_TYPE\_CUR\_RESOURCE & 從windows可執行文件資源部分加載的Windows光標.\\
\hline
wxBITMAP\_TYPE\_XBM & Unix平臺上使用的XBM單色圖片.\\
\hline
wxBITMAP\_TYPE\_XBM\_DATA & 從C++數據中構造的XBM單色位圖.\\
\hline
wxBITMAP\_TYPE\_XPM & XPM格式圖片,最好的支持跨平臺而且支持編譯到應用程序中去的格式.\\
\hline
wxBITMAP\_TYPE\_XPM\_DATA & 從C++數據中構造的XPM圖片.\\
\hline
wxBITMAP\_TYPE\_TIF & TIFF格式位圖,在大圖片中使用比較廣泛.\\
\hline
wxBITMAP\_TYPE\_GIF & GIF格式圖片,最多支持256中顏色,支持透明.\\
\hline
wxBITMAP\_TYPE\_PNG & PNG位圖格式, 一個使用普遍的圖片格式,支持透明和alpha通道,沒有版權問題.\\
\hline
wxBITMAP\_TYPE\_JPEG & JPEG格式位圖, 一個普遍使用的壓縮圖片格式,支持大圖片,不過它的壓縮算法是有損耗壓縮,所以不適合對圖片進行反覆加載和壓縮.\\
\hline
wxBITMAP\_TYPE\_PCX & PCX圖片格式.\\
\hline
wxBITMAP\_TYPE\_PICT & Mac PICT位圖.\\
\hline
wxBITMAP\_TYPE\_PICT\_RESOURCE & 從可執行文件資源部分加載的Mac PICT位圖.\\
\hline
wxBITMAP\_TYPE\_ICON\_RESOURCE & 僅在Mac OS X平臺上有效, 用來加載一個標準的圖標(好比wxICON\_INFORMATION)或者一個圖標資源.\\
\hline
wxBITMAP\_TYPE\_ANI & Windows動畫圖標(ANI).\\
\hline
wxBITMAP\_TYPE\_IFF & IFF位圖文件.\\
\hline
wxBITMAP\_TYPE\_MACCURSOR & Mac光標文件.\\
\hline
wxBITMAP\_TYPE\_MACCURSOR\_RESOURCE & 從可執行文件資源部分加載的Mac光標.\\
\hline
wxBITMAP\_TYPE\_ANY & 讓加載圖片的代碼本身肯定圖片的格式.\\
\hline
\end{mytblex} 

\section{使用wxBitmap編程}

你可使用wxBitmap來做下面的事情:

\begin{enumerate}
\itemsep=0pt
\item 經過設備上下文將其畫在一個窗口上.
\item 在某些類(好比wxBitmapButton, wxStaticBitmap, and wxToolBar)中將其做爲一個圖片標籤.
\item 使用其做爲雙緩衝區(在將某個圖形繪製到屏幕上以前先繪製在一塊緩衝區上).
\end{enumerate}

某些平臺(特別是windows平臺)上限制了系統中bitmap資源的數目,所以若是你須要使用不少的bitmap,你最好使用wxImage類來保存它們,而只在使用的時候將其轉化成bitmap.

在討論怎樣建立wxBitmap以前,讓咱們先來討論一下幾個主要的函數(以下表所示)

\begin{mytblex}{ht!}{|>{\setlength{\baselineskip}{15pt}}m{3.8cm}|>{\vspace*{5pt}\setlength{\baselineskip}{15pt}}m{10.72cm}<{\vspace*{3pt}}|}{wxBitmap相關函數}\hline 
wxBitmap & 表明一個bitmap,能夠經過指定寬度和高度,或者指定另一個bitmap,或者指定一個wxImage,XPM數據(char**), 原始數據(char[]), 或者一個指定類型的文件名的方式來建立.\\
\hline
ConvertToImage & 轉換成一個wxImage,保留透明部分.\\
\hline
CopyFromIcon & 從一個wxIcon建立一個wxBitmap.\\
\hline
Create & 從圖片數據或者一個給定的大小建立一個bitmap.\\
\hline
GetWidth, GetHeight & 返回圖片大小.\\
\hline
Getdepth & 返回圖片顏色深度.\\
\hline
GetMask, SetMask & 返回綁定的wxMask對象或者NULL.\\
\hline
GetSubBitmap & 將位圖其中的某一部分建立爲一個新的位圖.\\
\hline
LoadFile, SaveFile & 從某種支持格式的文件加載或者保存到文件裏.\\
\hline
Ok & 若是bitmap的數據已經具有則返回True.\\
\hline
\end{mytblex} 
   
\subsection{建立一個wxBitmap}

能夠經過下面的幾個途徑來建立一個wxBitmap對象.

你能夠直接經過默認的構造函數建立一個不包含數據的bitmap,不過你幾乎不能用這個bitmap做任何事情,除非你調用Create或者LoadFile或者用另一個bitmap賦值以便使其擁有具體的bitmap數據.

你還能夠經過指定寬度和高度的方法建立一個位圖,這種狀況下建立的位圖將被填充以隨機的顏色,你須要在其上繪畫以便更好的使用它,下面的代碼演示了怎樣建立一個200x100的圖片而且將其的背景刷新爲白色.


\begin{lstlisting} 
// 使用當前的顏色深度建立一個200x100的位圖
wxBitmap bitmap(200, 100,  -1);
// 建立一個內存設備上下文
wxMemoryDC dc;
// 將建立的圖片和這個內存設備上下文關聯
dc.SelectObject(bitmap);
// 設置背景顏色
dc.SetBackground(*wxWHITE_BRUSH);
// 繪製位圖背景
dc.Clear();
// 解除設備上下文和位圖的關聯
dc.SelectObject(wxNullBitmap);
\end{lstlisting}  

你也能夠從一個wxImage對象建立一個位圖,而且保留這個image對象的顏色遮罩或者alpha通道:


\begin{lstlisting} 
// 加載一幅圖像
wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG);
// 將其轉換成bitmap
wxBitmap bitmap(image);
\end{lstlisting} 

經過CopyFromIcon函數能夠經過圖標文件建立一個bitmap:


\begin{lstlisting} 
// 加載一個圖標
wxIcon icon(wxT("image.xpm"), wxBITMAP_TYPE_XPM);
// 將其轉換成位圖
wxBitmap bitmap;
bitmap.CopyFromIcon(icon);
\end{lstlisting} 

或者你能夠經過指定類型的方式從一個圖片文件直接加載一個位圖:


\begin{lstlisting} 
// 從文件加載
wxBitmap bitmap(wxT("picture.png", wxBITMAP_TYPE_PNG);
if (!bitmap.Ok())
{
    wxMessageBox(wxT("Sorry, could not load file."));
}
\end{lstlisting} 

wxBitmap能夠加載全部的能夠被wxImage加載的圖片類型,使用的則是各個平臺定義的針對特定類型的加載方法.最經常使用的圖片格式好比"PNG,JPG,BMP和XPM"等在各個平臺上都支持讀取和保存操做,不過你須要確認你的wxWidgets在編譯的時候已經打開了對應的支持.

目前支持的圖形類型處理函數以下表所示:

\begin{mytbl}{|>{\setlength{\baselineskip}{15pt}}m{3.8cm}|>{\vspace*{5pt}\setlength{\baselineskip}{15pt}}m{10.72cm}<{\vspace*{3pt}}|}{已支持的圖像類型}\hline 
wxBMPHandler & 用來加載windows位圖文件.\\
\hline
wxPNGHandler & 用來加載PNG類型的文件.這種文件支持透明背景以及alpha通道.\\
\hline
wxJPEGHandler & 用來支持JPEG文件\\
\hline
wxGIFHandler & 由於版權方面的緣由,僅支持GIF格式的加載.\\
\hline
wxPCXHandler & 用來支持PCX. wxPCXHandler會本身計算圖片中顏色的數目,若是沒有超過256色,則採用8bits顏色深度,不然就採用24
bits顏色深度.\\
\hline
wxPNMHandler & 用來支持PNM文件格式. 對於加載來講PNM格式能夠支持ASCII和raw RGB兩種格式.可是保存的時候僅支持raw RGB格式.\\
\hline
wxTIFFHandler & 用來支持TIFF.\\
\hline
wxIFFHandler & 用來支持IFF格式.\\
\hline
wxXPMHandler & 用來支持XPM格式.\\
\hline
wxICOHandler & 用來支持windows平臺圖標文件.\\
\hline
wxCURHandler & 用來支持windows平臺光標文件.\\
\hline
wxANIHandler & 用來支持windows平臺動畫光標文件.\\
\hline
\end{mytbl} 

在Mac OS X平臺上,還能夠經過指定wxBITMAP\_TYPE\_PICT\_RESOURCE來加載一個PICT資源.

若是你但願在不一樣的平臺上從不一樣的位置加載圖片,你可使用wxBITMAP宏,以下所示:


\begin{lstlisting} 
#if !defined(__WXMSW__) && !defined(__WXPM__)
#include "picture.xpm"
#endif
wxBitmap bitmap(wxBITMAP(picture));
\end{lstlisting} 

這將使得程序在windows和OS/2平臺上從資源文件中加載圖片,而在別的平臺上,則從一個picture\_xpm變量中加載xpm格式的圖片,由於XPM在全部的平臺上都支持,因此這種使用方法並不常見.

\subsection{設置一個wxMask}

每一個wxBitmap對象均可以指定一個wxMask,所謂wxMask指的是一個單色圖片用來指示原圖中的透明區域.若是你要加載的圖片中包含透明區域信息(好比XPM,PNG或者GIF格式),那麼wxMask將被自動建立,另外你也能夠經過代碼建立一個wxMask而後調用SetMask函數將其和對應的wxBitmap對象相關連.你還能夠從wxBitmap對象建立一個wxMask,或者經過給一個wxBitmap對象指定一種透明顏色來建立一個wxMask對象.

下面的代碼建立了一個擁有透明色的灰階位圖mainBitmap,它的大小是32x32象素,原始圖形從imageBits數據建立,遮罩圖形從maskBits建立,遮罩中1表明不透明,0表明透明顏色.


\begin{lstlisting} 
static char imageBits[] = { 255, 255, 255, 255, 31,
  255, 255, 255, 31, 255, 255, 255, 31, 255, 255, 255,
  31, 255, 255, 255, 31, 255, 255, 255, 31, 255, 255,
  255, 31, 255, 255, 255, 31, 255, 255, 255, 25, 243,
  255, 255, 19, 249, 255, 255, 7, 252, 255, 255, 15, 254,
  255, 255, 31, 255, 255, 255, 191, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255 };
static char maskBits[] = { 240, 1, 0, 0, 240, 1,
  0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 240, 1,
  0, 0, 240, 1, 0, 0, 240, 1, 0, 0, 255, 31, 0, 0, 255,
  31, 0, 0, 254, 15, 0, 0, 252, 7, 0, 0, 248, 3, 0, 0,
  240, 1, 0, 0, 224, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0 };
wxBitmap mainBitmap(imageBits, 32, 32);
wxBitmap maskBitmap(maskBits, 32, 32);
mainBitmap.SetMask(new wxMask(maskBitmap)); 
\end{lstlisting} 

\subsection{XPM圖形格式}

在使用小的須要支持透明的圖片(好比工具欄上的小圖片或者notebook以及樹狀控件上的小圖片)的時候,wxWidgets的程序員一般偏心使用XPM格式,它的最大的特色是採用C/C++語言的語法,既能夠被程序動態加載,也能夠直接編譯到可執行代碼中去,下面是一個例子:


\begin{lstlisting} 
// 你也能夠用 #include "open.xpm"
static char *open_xpm[] = {
/* 列數 行數 顏色個數 每一個象素的字符個數 */
"16 15 5 1",
"  c None",
". c Black",
"X c Yellow",
"o c Gray100",
"O c #bfbf00",
/* 象素 */
"                ",
"          ...   ",
"         .   . .",
"              ..",
"  ...        ...",
" .XoX.......    ",
" .oXoXoXoXo.    ",
" .XoXoXoXoX.    ",
" .oXoX..........",
" .XoX.OOOOOOOOO.",
" .oo.OOOOOOOOO. ",
" .X.OOOOOOOOO.  ",
" ..OOOOOOOOO.   ",
" ...........    ",
"                "
};
wxBitmap bitmap(open_xpm);
\end{lstlisting} 

正如你看到的那樣,XPM是使用字符編碼的.在圖片數據前面,有一個調色板區域,使用字符和顏色對應的方法,顏色既能夠用標準標識符表示,也能夠用16進制的RGB值表示,使用關鍵字None來表示透明區域.儘管在windows系統上,XPM並不被大多數的圖形處理工具支持,不過你仍是能夠經過一些工具把PNG格式轉換成XPM格式,好比DialogBlocks自帶的ImageBlocks工具,或者你能夠直接使用wxWidgets編寫一個你本身的轉換工具.

\subsection{使用位圖繪畫}

使用位圖繪畫的方式有兩種,你可使用內存設備上下文綁定一個位圖,而後使用wxDC::Blit函數,也能夠直接使用wxDC::DrawBitmap函數,前者容許你使用位圖的一部分進行繪製.在兩種方式下,若是這個圖片支持透明或者alpha通道,你均可以經過將最後一個參數指定爲True或者False來打開或者關閉透明支持.

這兩種方法的用法以下:

\begin{lstlisting} 
// Draw a bitmap using a wxMemoryDC
wxMemoryDC memDC;
memDC.SelectObject(bitmap);
// Draw the bitmap at 100, 100 on the destination DC
destDC.Blit(100, 100,                         // Draw at (100, 100)
    bitmap.GetWidth(), bitmap.GetHeight(),    // Draw full bitmap
    & memDC,                                  // Draw from memDC
    0, 0,                                     // Draw from bitmap origin
    wxCOPY,                                   // Logical operation
    true);                                    // Take mask into account
memDC.SelectObject(wxNullBitmap);
// Alternative method: use DrawBitmap
destDC.DrawBitmap(bitmap, 100, 100, true);
\end{lstlisting} 

第五章,"繪畫和打印"中對使用bitmap繪畫有更詳細的描述.

\subsection{打包位圖資源}

若是你曾是一個windows平臺的程序員,你可能習慣從可執行文件的資源部分加載一幅圖片,固然在wxWidgets中也能夠這樣做,你只須要指定一個資源名稱一個資源類型wxBITMAP\_TYPE\_BMP\_RESOUR\-CE,不過這種做法是平臺相關的.你可能更傾向於使用另一種平臺無關的解決方案.

一個可移植的方法是,你能夠將你用到的全部數據文件,包括HTML網頁,圖片或者別的任何類型的文件壓縮在一個zip文件裏,而後你能夠用wxWidgets提供的虛擬文件系統對加載這個zip文件的其中任何一個或幾個文件,以下面的代碼所示:


\begin{lstlisting} 
// 建立一個文件系統
wxFileSystem*fileSystem = new wxFileSystem;
wxString archiveURL(wxT("myapp.bin"));
wxString filename(wxT("myimage.png"));
wxBitmapType bitmapType = wxBITMAP_TYPE_PNG;
// 建立一個URL
wxString combinedURL(archiveURL + wxString(wxT("#zip:")) + filename);
wxImage image;
wxBitmap bitmap;
// 打開壓縮包中的對應文件
wxFSFile* file = fileSystem->OpenFile(combinedURL);
if (file)
{
    wxInputStream* stream = file->GetStream();

    // Load and convert to a bitmap
    if (image.LoadFile(* stream, bitmapType))
        bitmap = wxBitmap(image);

    delete file;
}
delete fileSystem;
if (bitmap.Ok())
{
    ...
}
\end{lstlisting} 

更多關於虛擬文件系統的信息請參考第14章:文件和流操做.

\section{使用wxIcon編程}

一個wxIcon表明一個小的位圖,它總有一個透明遮罩,它的用途包括:

\begin{itemize}
\itemsep=0pt
\item 設置frame窗口或者對話框的圖標
\item 經過wxImageList類給wxTreeCtrl, wxListCtrl或者wxNotebook提供圖標 (更多信息請參考最後一章)
\item 使用wxDC::DrawIcon函數在設備上下文中繪製一個圖標
\end{itemize}


下表列出了圖標類的主要成員函數

\begin{mytblex}{ht!}{|>{\setlength{\baselineskip}{15pt}}m{3.8cm}|>{\vspace*{5pt}\setlength{\baselineskip}{15pt}}m{10.72cm}<{\vspace*{3pt}}|}{wxIcon相關函數}\hline 
wxIcon & 圖標類能夠經過指定另一個圖標類的方式,指定XPM數據(char**)的方式, 原始數據(char[])的方式,或者文件名及文件類型的方式建立.\\
\hline
CopyFromBitmap & 從wxBitmap類建立一個圖標.\\
\hline
GetWidth, GetHeight & 返回圖標的大小.\\
\hline
Getdepth & 返回圖標的顏色深度.\\
\hline
LoadFile & 從文件加載圖標.\\
\hline
Ok & 在圖標數據已經具有的時候返回True.\\
\hline
\end{mytblex} 
   
\subsection{建立一個wxIcon}

wxIcon可使用XPM數據建立,或者從一個wxBitmap對象中建立,或者從文件(好比一個Xpm文件)中讀取.wxWidgets也提供了相似於前一小節提到的wxBITMAP相似的宏,用來從一個平臺相關的資源中獲取圖標.

在windows平臺上,LoadFile以及同等性質的操做可使用的文件類型包括BMP圖片和ICO文件,若是你要從其它圖片格式中建立圖標,能夠先將其讀入一個wxBitmap對象中,而後再將其轉換爲一個圖標.

而在Mac OSX和 Unix/Linux的GTK+版本中,wxIcon能夠識別的圖片類型和wxBitmap能夠識別的圖片類型是同樣的.

下面代碼演示了建立一個wxIcon對象的幾種方法:


\begin{lstlisting} 
// 方法1: 從XPM數據建立
#include "icon1.xpm"
wxIcon icon1(icon1_xpm);
// 方法2: 從一個ICO資源中建立(Window and OS/2 only)
wxIcon icon2(wxT("icon2"));
// 方法3: 從一個圖片文件中 (Windows and OS/2 only)
// 若是你的圖片包含多個圖標你能夠指定單個圖標的寬度
wxIcon icon3(wxT("icon3.ico"), wxBITMAP_TYPE_ICO, 16, 16);
// 方法4: 從位圖建立
wxIcon icon4;
wxBitmap bitmap(wxT("icon4.png"), wxBITMAP_TYPE_PNG);
icon4.CopyFromBitmap(bitmap);
\end{lstlisting} 
 
\subsection{使用wxIcon}

下面的代碼演示了wxIcon的三種使用方法:設置窗口圖標,增長到一個圖片列表或者繪製在某個設備上下文上


\begin{lstlisting} 
#include "myicon.xpm"
wxIcon icon(myicon_xpm);
// 1: 設置窗口圖標
frame->SetIcon(icon);
// 2: 增長到wxImageList
wxImageList* imageList = new wxImageList(16, 16);
imageList->Add(icon);
// 3: 在(10, 10)的位置繪製
wxClientDC dc(window);
dc.DrawIcon(icon, 10, 10);
\end{lstlisting} 

將某個圖標綁定到應用程序

將某個圖標綁定到應用程序,以便系統能夠顯示這個圖標在合適的位置使得用戶能夠經過點擊圖標的方式打開應用程序,這個工做wxWidgets是作不到的.這是極少的你須要在不一樣的平臺使用不一樣的技術的領域中的一個.

在windows平臺上,你須要在makefile中增長一個資源文件(擴展名是.rc),而且在這個資源文件中指定一個圖標區域,以下所示:


\begin{lstlisting} 
aardvarkpro ICON aardvarkpro.ico
#include "wx/msw/wx.rc"
\end{lstlisting} 

在這裏, aardvarkpro.ico就是這個和應用程序綁定的圖標的名稱,它能夠有多種分辨率和顏色深度(典型的大小包括48x48,32x32和16x16).當windows的資源管理器須要顯示某個圖標的時候,它將使用子母順序排在第一個的那個圖標,所以你最好給肯定要做爲應用程序圖標的那個圖標的名稱前面加幾個a子母以便按照子母順序它排在前面,不然你的應用程序可能綁定的是你不指望的圖標.

在Mac系統上,你須要準備一個應用程序包,其中包含一些ICNS文件.參考第20章"讓你的程序更完美",來得到關於程序包更多的信息,其中的主要文件Info.plist文件看上去應該象下面的額樣子:

\begin{lstlisting} 
  <key>CFBundleDocumentTypes</key>
  <array>
         <dict>
               <key>CFBundleTypeExtensions</key>
               <array>
                        <string>pjd</string>
                 </array>
                 <key>CFBundleTypeIconFile</key>
                 <string>dialogblocks-doc.icns</string>
                 <key>CFBundleTypeName</key>
                 <string>pjdfile</string>
                 <key>CFBundleTypeRole</key>
                 <string>Editor</string>
           </dict>
    </array>
    <key>CFBundleIconFile</key>
    <string>dialogblocks-app.icns</string>
...
\end{lstlisting} 

應用程序圖標和應用程序相關的文檔類型圖標是由CFBundleIconFile和CFBundleTypeIconFile屬性指定的.你能夠直接用Apple提供圖標編輯器編輯ICNS文件,不過若是你但願全部的平臺使用一樣的圖標,你最好現用PNG圖片建立各類大小的圖標,而後再將它粘貼到各個平臺上的圖標編輯器中,要確保PNG使用的透明遮罩顏色和各個工具使用的透明顏色相一致.

而在linux平臺上,Gnome桌面系統和KDE桌面系統則各自擁有本身的圖標提供體系,咱們將在第20章進行簡要的描述.

\section{使用wxCursor編程}

光標用來指示鼠標指針當前的位置.你能夠給某個窗口指定不一樣的光標以便提示用戶這個窗口期待某種類型的鼠標操做.和圖標同樣,光標也是一種始終帶有透明遮罩的小圖片,可使用通常的構造函數或者是平臺相關的構造函數來建立.其中的一些構造函數還須要相對於整個圖片的左上角指定一個熱點位置,當鼠標點擊的時候,熱點所在的位置將做爲鼠標點擊的位置.

下表列舉了光標相關的函數
\begin{mytbl}{|>{\setlength{\baselineskip}{15pt}}m{3.8cm}|>{\vspace*{5pt}\setlength{\baselineskip}{15pt}}m{10.72cm}<{\vspace*{3pt}}|}{wxCursor相關函數}\hline 
wxCursor & 光標能夠從wxImage對象,二進制數據,系統定義的光標標識符以及光標文件來建立.\\
\hline
Ok & 若是光標數據已經具有,則返回True.\\
\hline
\end{mytbl} 
   
\subsection{建立一個光標}

建立光標最簡單的方法是經過系統提供的光標標識符,以下面的例子所示:

\begin{lstlisting} 
wxCursor cursor(wxCURSOR_WAIT);
\end{lstlisting} 

下表列出了目前支持的光標標識符和它們的光標的樣子(依照平臺的不一樣會有些變化)

\begin{small}\begin{longtable}{|l|l|p{3in}|}
\caption{預約義的光標標識符}\\
\hline\endfirsthead
\caption[]{\emph{續上頁}}\\
\hline\endhead
\hline
\multicolumn{2}{r}{\emph{未完待續}}
\endfoot
\hline\endlastfoot
wxCURSOR\_ARROW & \includegraphics[scale=.6]{i10-01} &  標準光標.\\
\hline
wxCURSOR\_RIGHT\_ARROW & \includegraphics[scale=.6]{i10-06} &  標準反向光標.\\
\hline
wxCURSOR\_BLANK   &  & 透明光標.\\
\hline
wxCURSOR\_BULLSEYE & \includegraphics[scale=.6]{i10-07} &  近視眼.\\
\hline
wxCURSOR\_CROSS & \includegraphics[scale=.6]{i10-08} &  十字.\\
\hline
wxCURSOR\_HAND & \includegraphics[scale=.6]{i10-09} &  手.\\
\hline
wxCURSOR\_IBEAM & \includegraphics[scale=.6]{i10-10} &  I字光標.\\
\hline
wxCURSOR\_LEFT\_BUTTON & \includegraphics[scale=.6]{i10-11} &  按左鍵(GTK+ only).\\
\hline
wxCURSOR\_MAGNIFIER & \includegraphics[scale=.6]{i10-12} &  放大鏡.\\
\hline
wxCURSOR\_MIDDLE\_BUTTON & \includegraphics[scale=.6]{i10-10} &  按中鍵(譯者注:原書圖片有誤) (GTK+ only).\\
\hline
wxCURSOR\_NO\_ENTRY & \includegraphics[scale=.6]{i10-02} &  禁止通行.\\
\hline
wxCURSOR\_PAINT\_BRUSH & \includegraphics[scale=.6]{i10-03} &  畫刷.\\
\hline
wxCURSOR\_PENCIL & \includegraphics[scale=.6]{i10-04} &  鉛筆.\\
\hline
wxCURSOR\_POINT\_LEFT & \includegraphics[scale=.6]{i10-05} &  向左.\\
\hline
wxCURSOR\_POINT\_RIGHT & \includegraphics[scale=.6]{i10-14} &  向右.\\
\hline
wxCURSOR\_QUESTION\_ARROW & \includegraphics[scale=.6]{i10-18} &  帶問號的箭頭.\\
\hline
wxCURSOR\_RIGHT\_BUTTON & \includegraphics[scale=.6]{i10-10} &  按右鍵(譯者注:圖片有誤) (GTK+ only).\\
\hline
wxCURSOR\_SIZENESW & \includegraphics[scale=.6]{i10-20} &  東北到西南伸縮.\\
\hline
wxCURSOR\_SIZENS & \includegraphics[scale=.6]{i10-21} &  南北伸縮.\\
\hline
wxCURSOR\_SIZENWSE & \includegraphics[scale=.6]{i10-22} &  西北到東南伸縮.\\
\hline
wxCURSOR\_SIZEWE & \includegraphics[scale=.6]{i10-23} &  東西伸縮.\\
\hline
wxCURSOR\_SIZING & \includegraphics[scale=.6]{i10-24} &  通常伸縮.\\
\hline
wxCURSOR\_SPRAYCAN & \includegraphics[scale=.6]{i10-03} &  畫刷.\\
\hline
wxCURSOR\_WAIT & \includegraphics[scale=.6]{i10-15} &  等待.\\
\hline
wxCURSOR\_WATCH & \includegraphics[scale=.6]{i10-16} &  查看.\\
\hline
wxCURSOR\_ARROWWAIT & \includegraphics[scale=.6]{i10-17} &  後臺忙.\\
\hline
\end{longtable}\end{small}

你還可使用預約義光標指針wxSTANDARD\_CURSOR, wxHOURGLASS\_CURSOR和wxCROSS\_CURSOR.

另外在windows和Mac平臺上還能夠從對應的資源文件中加載光標:

\begin{lstlisting} 
//windows平臺
wxCursor cursor(wxT("cursor_resource"), wxBITMAP_TYPE_CUR_RESOURCE,
                 hotSpotX, hotSpotY);
// Mac平臺
wxCursor cursor(wxT("cursor_resource"), wxBITMAP_TYPE_MACCUR_RESOURCE);
\end{lstlisting} 

你還能夠經過wxImage對象建立光標,而"熱點"則要經過wxImage::SetOptionInt函數設置.之因此要設置熱點,是由於不少光標不太適合使用默認的左上角做爲熱點,好比對於十字光標來講,你可能但願將其十字交叉的地方做爲熱點.下面的代碼演示了怎樣從一個PNG文件中產生設置了熱點的光標:


\begin{lstlisting} 
// 用wxImage建立光標
wxImage image(wxT("cursor.png"), wxBITMAP_TYPE_PNG);
image.SetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X, 5);
image.SetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 5);
wxCursor cursor(image);
\end{lstlisting} 

\subsection{使用wxCursor}

每一個窗口均可以設置一個對應的光標,這個光標在鼠標進入這個窗口的時候顯示,若是一個窗口沒有設置光標,其父窗口的光標將被顯示,若是全部的父窗口都沒有設置光標,則系統默認光標被顯示:

使用下面的代碼給窗口設置一個光標:

\begin{lstlisting} 
window->SetCursor(wxCursor(wxCURSOR_WAIT));
\end{lstlisting} 

使用wxSetCursorEvent

在windows系統或者是Mac OS X系統上,有一些小地方咱們須要注意一下.舉個例子,若是你本身實現了一個容器類,比方說是一個分割窗口,而且給它設置了一個特殊的光標(好比說wxCURSOR\_WE用來代表某個分割條是能夠被拉動的),而後你在這個分割窗口中放置了兩個子窗口,若是你沒有給這兩個子窗口設置光標的話,當光標在子窗口上移動時,它們可能會不恰當的顯示其父窗口,那個wxCURSOR\_WE光標.而原本你是但願只有在鼠標移動到分割條上的時候才顯示的.

要告訴wxWidgets某個光標只應該在某種狀況下被顯示,你能夠增長一個wxSetCursorEvent事件的處理函數,這個事件在Windows和Mac平臺上,當須要設置光標的時候(一般是鼠標在窗口間移動的時候)被產生.在這個事件處理函數中能夠調用wxSetCursorEvent::SetCursor來設置一個特殊的光標.以下所示:


\begin{lstlisting} 
BEGIN_EVENT_TABLE(wxSplitterWindow, wxWindow)
    EVT_SET_CURSOR(wxSplitterWindow::OnSetCursor)
END_EVENT_TABLE()
// 指示光標只應該被設置給分割條
void wxSplitterWindow::OnSetCursor(wxSetCursorEvent& event)
{
    if ( SashHitTest(event.GetX(), event.GetY(), 0) )
    {
        // 使用默認的處理
        event.Skip();
    }
    //else:什麼也不做,換句話說,不調用Skip.則事件表不會被繼續搜索
}
\end{lstlisting} 

在這個例子中,當鼠標指針移過度割條的時候,SashHitTest函數返回True,所以Skip函數被調用,事件表調用失敗,這和沒有定義這個事件表的效果是同樣的,致使wxWidgets象往常同樣顯示指定給窗口的光標(wxCURSOR\_WE).而若是SashHitTest函數返回False,則代表光標是在子窗口上移動,這時候應該不顯示咱們指定的光標,所以咱們不調用Skip函數,讓事件表匹配成功,則事件表將不會在繼續匹配,這將使得wxWidgets認爲這個窗口沒有被指定光標,所以.在這種狀況下,即便子窗口本身沒有光標(象wxTextCtrl這種控件,通常系統會指定一個它本身的光標,不過wxWidgets對這個是不感知的),也將不會使用咱們指定給父窗口的光標.

\section{使用wxImage編程}

你可使用wxImage對圖形進行一些平臺無關的調整,或者將其做爲圖片加載和保存的中間步驟.圖片在wxImage中是按照每個象素使用一個分別表明紅色,綠色和藍色的字節的格式保存的,若是圖片包含alpha通道,則還會佔用額外的一個字節.

wxImage主要的函數以下:

\begin{mytblex}{ht!}{|>{\setlength{\baselineskip}{15pt}}m{3.8cm}|>{\vspace*{5pt}\setlength{\baselineskip}{15pt}}m{10.72cm}<{\vspace*{3pt}}|}{wxImage相關函數}\hline 
wxImage & wxImage的建立方法包括:指定寬度和高度, 從另一幅圖片建立, 使用XPM數據, 圖片元數據(char[]) 和可選的alpha通道數據,文件名及其類型,以及經過輸入流等多種方式建立.\\
\hline
ConvertAlphaToMask & 將alpla通道(若是有的話)轉換成一個透明遮罩.\\
\hline
ConvertToMono & 轉換成一個黑白圖片.\\
\hline
Copy & 返回一個不使用引用記數器的徹底同樣的拷貝.\\
\hline
Create & 建立一個指定大小的圖片,可選的參數指明是否初始化圖片數據.\\
\hline
Destroy & 若是沒有人再使用的話,釋放內部數據.\\
\hline
GeTData, SetData & 獲取和設置內部數據指針(unsigned char*).\\
\hline
GetImageCount & 返回一個文件或者流中的圖片個數.\\
\hline
GetOption, GetOptionInt, SetOption, HasOption & 獲取, 設置和測試某個選項是否設置.\\
\hline
GetSubImage & 將圖片的一部分返回爲一個新的圖像.\\
\hline
GetWidth, GetHeight & 返回圖片大小.\\
\hline
Getred, GetGreen, GetBlue, SetRGB, GetAlpha, SetAlpha & 得到和指定某個象素的RGB以及Alpha通道的值.\\
\hline
HasMask, GetMaskRed, GetMaskGreen, GetMaskBlue, SetMaskColour & 用來測試圖像是否有一個遮罩,以及遮罩顏色的RGB值或者整個顏色的值.\\
\hline
LoadFile, SaveFile & 各類圖片格式文件的讀取和保存操做.\\
\hline
Mirror & 在各類方向上產生鏡像,返回一個新圖片.\\
\hline
Ok & 判斷圖片是否已初始化.\\
\hline
Paste & 將某個圖片粘貼在這個圖片的指定位置.\\
\hline
Rotate, Rotate90 & 旋轉圖片,返回一個新圖片.\\
\hline
SetMaskFromImage & 經過指定的圖片和透明顏色產生一個遮罩而且設置這個遮罩.\\
\hline
Scale, Rescale & 縮放產生一個新圖片或者縮放本圖片.\\
\hline
\end{mytblex} 
   
\subsection{加載和保存圖像}

wxImage能夠讀取和保存各類各樣的圖片格式,而且使用圖像處理過程來增長擴展的能力.其它的圖像類(好比wxBitmap)在某個平臺不具有處理某種圖形格式的能力的時候,也一般使用的都是wxImage的圖象處理過程來加載特定格式的圖形.

本章第二小節中展現了wxWidgets支持的各類圖形處理過程.其中wxBMPHandler是默認支持的,而要支持其它的圖形格式處理,就須要使用wxImage::AddHandler函數增長對應的圖形處理過程或者使用wxInitAllImageHandlers增長全部支持的圖形處理過程.

若是你只須要特定的圖形格式支持,能夠在OnInit函數中使用相似下面的代碼:


\begin{lstlisting} 
#include "wx/image.h"
wxImage::AddHandler( new wxPNGHandler );
wxImage::AddHandler( new wxJPEGHandler );
wxImage::AddHandler( new wxGIFHandler );
wxImage::AddHandler( new wxXPMHandler );
\end{lstlisting} 

或者,你能夠簡單的調用:


\begin{lstlisting} 
wxInitAllImageHandlers();
\end{lstlisting} 

下面演示了幾種從文件或者流讀取圖片的方式,注意在實際使用過程當中,最好使用絕對路徑以免依賴於當前路徑的設置:


\begin{lstlisting} 
// 使用構造函數指定類型來讀取圖像
wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG);
if (image.Ok())
{
    ...
}
// 不指定圖像類型通常也能正常工做
wxImage image(wxT("image.png"));
// 使用兩步法建立圖像
wxImage image;
if (image.LoadFile(wxT("image.png")))
{
    ...
}
/* 若是一個文件包含兩副圖片Two-step loading with an 
index into a multi-image file:*/
// 下面演示選擇第2副加載
wxImage image;
int imageCount = wxImage::GetImageCount(wxT("image.tif"));
if (imageCount > 2)
    image.LoadFile(wxT("image.tif"), wxBITMAP_TYPE_TIFF, 2);
// 從文件流加載圖片
wxFileInputStream stream(wxT("image.tif"));
wxImage image;
image.LoadFile(stream, wxBITMAP_TYPE_TIF);
// 保存到一個文件
image.SaveFile(wxT("image.png")), wxBITMAP_TYPE_PNG);
// 保存到一個流
wxFileOutputStream stream(wxT("image.tif"));
image.SaveFile(stream, wxBITMAP_TYPE_TIF);
\end{lstlisting}  

除了XPM和PCX格式之外,其它的圖片格式都將以24位顏色深度保存(譯者注:GIF格式由於版權方面的緣由不支持保存到文件),這兩種格式的圖形處理過程將會計算實際的顏色個數從而選擇相應的顏色深度.JPEG格式還擁有一個質量選項可供設置.它的值的範圍爲從0到100,0表明最低的圖片質量和最高的壓縮比,100則表明最高的圖片質量和最低的壓縮比.以下所示:


\begin{lstlisting} 
// 設置一個合理的質量壓縮比
image.SetOption(wxIMAGE_OPTION_QUALITY, 80);
image.SaveFile(wxT("picture.jpg"), wxBITMAP_TYPE_JPEG);
\end{lstlisting}  

另外若是以XPM格式保存到流輸出中的時候,須要使用wxImage::SetOption函數設置一個名稱不然,處理函數不知道該用什麼名稱命名對應的C變量.


\begin{lstlisting} 
// 保存XPM到流格式
image.SetOption(wxIMAGE_OPTION_FILENAME, wxT("myimage"));
image.SaveFile(stream, wxBITMAP_TYPE_XPM);
\end{lstlisting}  

注意處理函數會自動在你設置的名稱後增長"\_xpm".

\subsection{透明}

有兩種方式設置一個wxImage爲透明的圖像:使用顏色遮罩或者alpha通道.一種顏色能夠被指定爲透明顏色,經過這種方法在將wxImage轉換成wxBitmap的時候能夠很容易的製做一個透明遮罩.

wxImage也支持alpha通道數據,在每個象素的RGB顏色以外來由另一個字節用來指示alpha通道的值,0表明徹底透明,255則表明徹底不透明.中間的值表明半透明.

不是全部的圖片都用有alpha通道數據的,所以在使用GetAlpha函數以前,應該使用HasAlpha函數來判斷圖像是否擁有alpha通道數據.到目前爲止,只有PNG文件或者調用SetAlpha設置了alpha通道的圖像才擁有alpha通道數據.保存一個帶有alpha通道的圖像目前還不被支持.繪製一個擁有alpha通道的方法是先將其轉換成wxBitmap而後使用wxDC::DrawBitmap或者wxDC::Blit函數.

下面的代碼演示了怎樣使用顏色掩碼建立一個透明的wxImage,它是藍色的,擁有一個透明的矩形區域:


\begin{lstlisting} 
// 建立一個有顏色掩碼的wxBitmap
// 首先,在這個wxBitmap上繪畫
wxBitmap bitmap(400, 400);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.SetBackground(*wxBLUE_BRUSH);
dc.Clear();
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle(50, 50, 200, 200);
dc.SelectObject(wxNullBitmap);
// 將其轉換成wxImage
wxImage image = bitmap.ConvertToImage();
// 設置掩碼顏色
image.SetMaskColour(255, 0, 0);
\end{lstlisting}  

在下面的例子中,使用從一個圖片建立顏色遮罩的方式,其中image.bmp是原始圖像,而mask.bmp則是一個掩碼圖像,在後者中全部透明的部分都是黑色顯示的.


\begin{lstlisting} 
// 加載一副圖片和它的掩碼遮罩
wxImage image(wxT("image.bmp"), wxBITMAP_TYPE_BMP);
wxImage maskImage(wxT("mask.bmp"), wxBITMAP_TYPE_BMP);
// 從後者建立一個遮罩而且設置給前者.
image.SetMaskFromImage(maskImage, 0, 0, 0);
\end{lstlisting}  

若是你加載的圖片自己含有透明顏色,你能夠檢測而且直接建立遮罩:


\begin{lstlisting} 
// 加載透明圖片
wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG);
// 獲取掩碼
if (image.HasMask())
{
    wxColour maskColour(image.GetMaskRed(),
    image.GetMaskGreen(),
    image.GetMaskBlue());
}
\end{lstlisting} 

\subsection{變形}

wxImage支持縮放,旋轉以及鏡像等多種變形方式,下面各舉一些例子:


\begin{lstlisting} 
// 把原始圖片縮放到200x200,並保存在新的圖片裏
// 原圖保持不變.
wxImage image2 = image1.Scale(200, 200);
// 將原圖縮放到200x200
image1.Rescale(200, 200);
// 旋轉固定角度產生新圖片.
// 原圖片保持不變.
wxImage image2 = image1.Rotate(0.5);
// 順時針旋轉90度產生新圖片.
// 原圖保持不變.
wxImage image2 = image1.Rotate90(true);
// 水平鏡像產生新圖片.
// 原圖保持不變.
wxImage image2 = image1.Mirror(true);
\end{lstlisting} 

\subsection{顏色消減}

若是你想對某個圖像的顏色進行消減,你可使用wxQuantize類的一些靜態函數,其中最有趣的函數Quantize的參數爲一個輸入圖片,一個輸出圖片,一個可選的wxPalette**指針用來存放通過消減的顏色,以及一個你但願保留的顏色個數,你也能夠傳遞一個unsigned char**變量來獲取一個8-bit顏色深度的輸出圖像.最後的一個參數style(類型)用來對返回的圖像進行一些更深刻的控制,詳情請參考wxWidgets的手冊.

下面的代碼演示了怎樣將一幅圖片的顏色消減到最多256色:


\begin{lstlisting} 
#include "wx/image.h"
#include "wx/quantize.h"
wxImage image(wxT("image.png"));
int maxColorCount = 256;
int colors = image.CountColours();
wxPalette* palette = NULL;
if (colors > maxColorCount )
{
    wxImage reducedImage;
    if (wxQuantize::Quantize(image, reducedImage,
                               & palette, maxColorCount))
    {
        colors = reducedImage.CountColours();
        image = reducedImage;
    }
}
\end{lstlisting}  

一個wxImage能夠設置一個wxPalette,例如加載GIF文件的時候. 而後,圖片內部仍然是以RGB的方式存儲數據的,調色板僅表明圖片加載時候的顏色隱射關係.調色板的另一個用途是某些圖片處理函數用它來將圖片保存爲低顏色深度的圖片,例如windows的BMP圖片處理過程將檢測是否設置了wxBMP\_8BPP\_PALETTE標記,若是設置了,則將使用調色板.而若是設置了wxBMP\_8BPP標記(而不是wxBMP\_8BPP\_PALETTE),它將使用本身的算法進行顏色消減.另外某些圖片處理過程本身也進行顏色消減,好比PCX的處理過程,除非它認爲剩餘的顏色個數已經足夠低了,不然它將對圖片的顏色進行消減.

關於調色板更多的信息請參考第5章的"調色板"小節.

\subsection{直接操做wxImage 的元數據}

你能夠直接經過GetData函數訪問wxImage的元數據以便以比GeTRed, GetBlue, GetGreen和SetRGB更快的方式對其進行操做,下面舉了一個使用這種方法將一個圖片轉換成灰度圖片的方法:


\begin{lstlisting} 
void wxImage::ConvertToGrayScale(wxImage& image)
{
    double red2Gray   = 0.297;
    double green2Gray = 0.589;
    double blue2Gray  = 0.114;
    int w = image.GetWidth(), h = image.GetHeight();
    unsigned char *data = image.GetData();
    int x,y;
    for (y = 0; y < h; y++)
        for (x = 0; x < w; x++)
        {
            long pos = (y * w + x) * 3;
            char g = (char) (data[pos]*red2Gray +
                              data[pos+1]*green2Gray +
                              data[pos+2]*blue2Gray);
            data[pos] = data[pos+1] = data[pos+2] = g;
        }
}
\end{lstlisting} 

\section{圖片列表和圖標集}

有時候,使用一組圖片是很是方便的.這時候,你能夠直接在你的代碼中使用wxImageList,也能夠和wxWidgets提供的一些控件一塊兒使用wxImageList,wxNotebook,wxtreeCtrl和wxListCtrl都須要wxImageList來管理它們所須要使用的圖標.你也可以使用wxImageList中的某個單獨的圖片在設備上下文上繪畫.

建立一個wxImageList須要的參數包括單個圖片的寬度和高度,一個bool值來指定是否須要指定圖片遮罩,以及這個圖片列表的初始大小(主要是爲了內部優化代碼),而後一個一個的增長wxBitmap對象或者wxIcon對象.wxImageList不能直接使用wxImage對象,你須要先將其轉換爲wxBitmap對象.wxImageList::Add函數返回一個整數的索引用來表明這個剛增長的圖片,在Add函數成功返回之後,你就能夠釋放原始圖片了,wxImageList已經在內部建立了一個這個圖片的拷貝.

下面是建立wxImageList以及在其中增長圖片的一些例子:


\begin{lstlisting} 
// 建立一個wxImageList
wxImageList *imageList = new wxImageList(16, 16, true, 1);
// 增長一個透明的PNG文件
wxBitmap bitmap1(wxT("image.png"), wxBITMAP_TYPE_PNG);
imageList->Add(bitmap1);
// 增長一個透明的來自別的bitmap的圖片
wxBitmap bitmap2(wxT("image.bmp"), wxBITMAP_TYPE_BMP);
wxBitmap maskBitmap(wxT("mask.bmp"), wxBITMAP_TYPE_BMP);
imageList->Add(bitmap2, maskBitmap);
// 增長一個指定透明顏色的透明圖片
wxBitmap bitmap3(wxT("image.bmp"), wxBITMAP_TYPE_BMP);
imageList->Add(bitmap3, *wxRED);
// 增長一個圖標
#include "folder.xpm"
wxIcon icon(folder_xpm);
imageList->Add(icon);
\end{lstlisting} 

你能夠直接把wxImageList中的圖片繪製在設備上下文上,經過指定wxIMAGELIST\_DRAW\_TRANS\-PARENT類型來指示繪製透明圖片,你還能夠指定的類型包括wxIMAGELIST\_DRAW\_NORMAL, wxIMAGELIST\_DRAW\-\_SELECTED或者wxIMAGELIST\_DRAW\_FOCUSED,用來表徵圖片的狀態,以下所示:


\begin{lstlisting} 
// 繪製列表中全部的圖片
wxClientDC dc(window);
size_t i;
for (i = 0; i < imageList->GetImageCount(); i++)
{
    imageList->Draw(i, dc, i*16, 0, wxIMAGELIST_DRAW_NORMAL|
                                    wxIMAGELIST_DRAW_TRANSPARENT);
}
\end{lstlisting} 

要把圖片列表和notebook的TAB頁面綁定在一塊兒,你須要建立一個包含大小爲16x16的圖片的列表,而後調用wxNotebook::SetImageList或者wxNotebook::AssignImageList將其和某個wxNotebook綁定,這兩個函數的區別在於,前者在wxNotebook釋放的時候不釋放列表,然後者在本身被釋放的時候,會同時釋放圖片列表.指定完圖片列表之後,你就能夠給某個頁面指定圖標索引以便在頁面標籤上顯示圖標了,下面的代碼演示了這個過程:


\begin{lstlisting} 
//建立一個wxImageList
wxImageList *imageList = new wxImageList(16, 16, true, 1);
// 增長一些圖標
wxBitmap bitmap1(wxT("folder.png"), wxBITMAP_TYPE_PNG);
wxBitmap bitmap2(wxT("file.png"), wxBITMAP_TYPE_PNG);
int folderIndex = imageList->Add(bitmap1);
int fileIndex = imageList->Add(bitmap2);
// 建立一個擁有兩個頁面的notebook
wxNotebook* notebook = new wxNotebook(parent, wxID_ANY);
wxPanel* page1 = new wxPanel(notebook, wxID_ANY);
wxPanel* page2 = new wxPanel(notebook, wxID_ANY);
// 綁定圖片列表
notebook->AssignImageList(imageList);
// Add the pages, with icons
notebook->AddPage(page1, wxT("Folder options"), true, folderIndex);
notebook->AddPage(page2, wxT("File options"), false, fileIndex);
\end{lstlisting} 

wxtreeCtrl和wxListCtrl的使用方法和上面介紹的很是類似,也包含相似的兩種綁定方法.

若是你擁有不少圖標,有時候很難經過索引來對應到具體的圖標,你可能想編寫一個類以便經過字符串來找到某個圖片索引.下面演示了基於這個目的的一個簡單的實現:


\begin{lstlisting} 
#include "wx/hashmap.h"
WX_DECLARE_STRING_HASH_MAP(int, IconNameToIndexHashMap);
// 經過名字引用圖片的類
class IconNameToIndex
{
public:
    IconNameToIndex() {}
    // 在圖片列表中增長一個已經命名的圖片
    void Add(wxImageList* list, const wxBitmap& bitmap,
        const wxString& name) {
        m_hashMap[name] = list->Add(bitmap);
    }
    // 在圖片列表中增長一個已命名的圖標
    void Add(wxImageList* list, const wxIcon& icon,
        const wxString& name) {
        m_hashMap[name] = list->Add(icon);
    }
    // 經過名稱找到索引
    int Find(const wxString& name) { return m_hashMap[name]; }
private:
    IconNameToIndexHashMap m_hashMap;
};
\end{lstlisting} 

wxIconBundle類一樣也是一個圖片列表,不過這個類的目的是爲了將多個不一樣分辨率的圖標保存在一個類中而不是多個類中,以便系統在合適的時候根據不一樣的使用目的選擇一個特定的圖標.好比,在資源管理器中的圖標一般比在主窗口標題欄上顯示的圖標要大的多.下面的例子演示了其用法:


\begin{lstlisting} 
// 建立一個只有單個16x16圖標的圖片集
#include "file16x16.xpm"
wxIconBundle iconBundle(wxIcon(file16x16_xpm));
// 在圖片集中增長一個32x32的圖片
iconBundle.Add(wxIcon(wxT("file32x32.png"), wxBITMAP_TYPE_PNG));
// 從一個包含多個圖片的文件中建立一個圖片集
wxIconBundle iconBundle2(wxT("multi-icons.tif"), wxBITMAP_TYPE_TIF);
// 從圖片集中獲取指定大小的圖片,若是找不到則繼續尋找
// wxSYS_ICON_X, wxSYS_ICON_Y大小的圖片
wxIcon icon = iconBundle.GetIcon(wxSize(16,16));
// 將圖片集指定給某個主窗口
wxFrame* frame = new wxFrame(parent, wxID_ANY);
frame->SetIcons(iconBundle);
\end{lstlisting} 

在windows系統上,SetIcons函數期待一個包含16x16和32x32大小的圖標的圖標集.

\section{自定義wxWidgets提供的小圖片}

wxArtProvider這個類容許你更改wxWidgets默認提供的那些小圖片,好比wxWidgets HTML幫助閱讀器中或者默認的Log對話框中使用的圖片.

wxWidgets提供了一個標準的wxArtProvider對象,而且體系內的一些須要使用圖標和小圖片的地方都調用了這個類的wxArtProvider::GetBitmap和wxArtProvider::GetIcon函數.

小圖片是由兩個標識符決定的:主標識符(wxArtID)和客戶區標識符(wxArtClient).其中客戶區標識符只在同一個主標識符在不一樣的窗口中須要不一樣的圖片的時候才使用,好比,wxHTML幫助窗口使用的圖標使用下面的代碼取得的:


\begin{lstlisting} 
wxBitmap bmp = wxArtProvider::GetBitmap(wxART_GO_BACK,wxART_TOOLBAR);
\end{lstlisting} 

若是你想瀏覽全部wxWidgets提供的小圖片以及它們的標識符,你能夠編譯和運行wxWidgets自帶的samples/artprov中的例子,它的外觀以下圖所示:


\begin{figure}[ht!]
\centering
\includegraphics[scale=.6]{f10-01}
\caption{wxWidgets提供的artprov例子}
\end{figure} 

要替換wxWidgets提供的這些小圖片,你須要實現一個wxArtProvider的派生類,重載其中的CreateBitmap函數,而後在OnInit函數中調用wxArtProvider::PushProvider以便讓wxWidgets知道.下面的這個例子替換了wxHTML幫助窗口中的大部分默認的圖標:


\begin{lstlisting} 
// 新的圖標
#include "bitmaps/helpbook.xpm"
#include "bitmaps/helppage.xpm"
#include "bitmaps/helpback.xpm"
#include "bitmaps/helpdown.xpm"
#include "bitmaps/helpforward.xpm"
#include "bitmaps/helpoptions.xpm"
#include "bitmaps/helpsidepanel.xpm"
#include "bitmaps/helpup.xpm"
#include "bitmaps/helpuplevel.xpm"
#include "bitmaps/helpicon.xpm"
#include "wx/artprov.h"
class MyArtProvider : public wxArtProvider
{
protected:
    virtual wxBitmap CreateBitmap(const wxArtID& id,
                                  const wxArtClient& client,
                                  const wxSize& size);
};
// 新的CreateBitmap函數
wxBitmap MyArtProvider::CreateBitmap(const wxArtID& id,
                                     const wxArtClient& client,
                                     const wxSize& size)
{
    if (id == wxART_HELP_SIDE_PANEL)
        return wxBitmap(helpsidepanel_xpm);
    if (id == wxART_HELP_SETTINGS)
        return wxBitmap(helpoptions_xpm);
    if (id == wxART_HELP_BOOK)
        return wxBitmap(helpbook_xpm);
    if (id == wxART_HELP_FOLDER)
        return wxBitmap(helpbook_xpm);
    if (id == wxART_HELP_PAGE)
        return wxBitmap(helppage_xpm);
    if (id == wxART_GO_BACK)
        return wxBitmap(helpback_xpm);
    if (id == wxART_GO_FORWARD)
        return wxBitmap(helpforward_xpm);
    if (id == wxART_GO_UP)
        return wxBitmap(helpup_xpm);
    if (id == wxART_GO_DOWN)
        return wxBitmap(helpdown_xpm);
    if (id == wxART_GO_TO_PARENT)
        return wxBitmap(helpuplevel_xpm);
    if (id == wxART_FRAME_ICON)
        return wxBitmap(helpicon_xpm);
    if (id == wxART_HELP)
        return wxBitmap(helpicon_xpm);

    // Any wxWidgets icons not implemented here
    // will be provided by the default art provider.
    return wxNullBitmap; 
}
// 你的初始化函數
bool MyApp::OnInit()
{
    ...
    wxArtProvider::PushProvider(new MyArtProvider);
    ...
    return true;
}
\end{lstlisting} 

\section{本章小結}

在這一章裏,咱們學習了怎樣使用wxWidgets中的圖片相關的類wxBitmap, wxIcon, wxCursor和wxImage,還學習了怎樣使用wxImageList和wxIconBundle,以及怎樣定義wxWidgets默認使用的小圖片.更多相關的例子請參考wxWidgets自帶的samples/image, samples/listctrl和samples/dragimag目錄中的例子.

在下一章裏,咱們將介紹一下怎樣使用剪貼板來傳輸數據以及怎樣實現拖放編程.
相關文章
相關標籤/搜索