10.2 使用wxBitmap编程
你可以使用wxBitmap来作下面的事情:
- 通过设备上下文将其画在一个窗口上.
- 在某些类(比如wxBitmapButton, wxStaticBitmap, and wxToolBar)中将其作为一个图片标签.
- 使用其作为双缓冲区(在将某个图形绘制到屏幕上之前先绘制在一块缓冲区上).
某些平台(特别是windows平台)上限制了系统中bitmap资源的数目,因此如果你需要使用很多的bitmap,你最好使用wxImage类来保存它们,而只在使用的时候将其转化成bitmap.
在讨论怎样创建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在编译的时候已经打开了对应的支持.
目前支持的图形类型处理函数如下表所示:
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章:文件和流操作.