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目录中的例子.

在下一章里,咱们将介绍一下怎样使用剪贴板来传输数据以及怎样实现拖放编程.
相关文章
相关标签/搜索