# 10.2 使用wxBitmap编程
你可以使用wxBitmap来作下面的事情:
1. 通过设备上下文将其画在一个窗口上.
2. 在某些类(比如wxBitmapButton, wxStaticBitmap, and wxToolBar)中将其作为一个图片标签.
3. 使用其作为双缓冲区(在将某个图形绘制到屏幕上之前先绘制在一块缓冲区上).
某些平台(特别是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章:文件和流操作.
- 第一章 介绍
- 1.1 为什么要使用wxWidgets?
- 1.2 wxWidgets的历史
- 1.3 wxWidgets社区
- 1.4 wxWidgets和面向对象编程
- 1.5 wxWidgets的体系结构
- 1.6 许可协议
- 第一章小结
- 第二章 开始使用
- 2.1 一个小例子
- 2.2 应用程序类
- 2.3 Frame窗口类
- 2.4 事件处理函数
- 2.5 Frame窗口的构造函数
- 2.6 完整的例子
- 2.7 wxWidgets程序一般执行过程
- 2.8 编译和运行程序
- 第二章小结
- 第三章 事件处理
- 3.1 事件驱动编程
- 3.2 事件表和事件处理过程
- 3.3 过滤某个事件
- 3.4 挂载事件表
- 3.5 动态事件处理方法
- 3.6 窗口标识符
- 3.7 自定义事件
- 第三章小结
- 第四章 窗口的基础知识
- 4.1 窗口解析
- 4.2 窗口类概览
- 4.3 基础窗口类
- 4.4 顶层窗口
- 4.5 容器窗口
- 4.6 非静态控件
- 4.7 静态控件
- 4.8 菜单
- 4.9 控制条
- 第四章小结
- 第五章绘画和打印
- 5.1 理解设备上下文
- 5.2 绘画工具
- 5.3 设备上下文中的绘画函数
- 5.4 使用打印框架
- 5.5 使用wxGLCanvas绘制三维图形
- 第五章小节
- 第六章处理用户输入
- 6.1 鼠标输入
- 6.2 处理键盘事件
- 6.3 处理游戏手柄事件
- 第六章小结
- 第七章使用布局控件进行窗口布局
- 7.1 窗口布局基础
- 7.2 窗口布局控件
- 7.3 使用布局控件进行编程
- 7.4 更多关于布局的话题
- 第七章小结
- 第八章使用标准对话框
- 8.1信息对话框
- 8.2 文件和目录对话框
- 8.3 选择和选项对话框
- 8.4 输入对话框
- 8.5 打印对话框
- 第八章小结
- 第九章创建定制的对话框
- 9.1 创建定制对话框的步骤
- 9.2 一个例子:PersonalRecordDialog
- 9.3 在小型设备上调整你的对话框
- 9.4 一些更深入的话题
- 9.5 使用wxWidgets资源文件
- 第九章小结
- 第十章使用图像编程
- 10.1 wxWidgets中图片相关的类
- 10.2 使用wxBitmap编程
- 10.3 使用wxIcon编程
- 10.4 使用wxCursor编程
- 10.5 使用wxImage编程
- 10.6 图片列表和图标集
- 10.7 自定义wxWidgets提供的小图片
- 第十章小结
- 第十一章剪贴板和拖放操作
- 11.1 数据对象
- 11.2 使用剪贴板
- 11.3 实现拖放操作
- 第十一章小结
- 第十二章高级窗口控件
- 12.1 wxTreeCtrl
- 12.2 wxListCtrl
- 12.3 wxWizard
- 12.4 wxHtmlWindow
- 12.5 wxGrid
- 12.6 wxTaskBarIcon
- 12.7 编写自定义的控件
- 第十二章小结
- 第十三章数据结构类
- 13.1 为什么没有使用STL?
- 13.2 字符串类型
- 13.3 wxArray
- 13.4 wxList和wxNode
- 13.5 wxHashMap
- 13.6 存储和使用日期和时间
- 13.7 其它常用的数据类型
- 第十三章小结
- 第十四章文件和流操作
- 14.1 文件类和函数
- 14.2 流操作相关类
- 第十四章小结
- 第十五章内存管理,调试和错误处理
- 15.1 内存管理基础
- 15.2 检测内存泄漏和其它错误
- 15.3 构建自防御的程序
- 15.4 错误报告
- 15.5 提供运行期类型信息
- 15.6 使用wxModule
- 15.7 加载动态链接库
- 15.8 异常处理
- 15.9 调试提示
- 第十五章小结
- 第十六章编写国际化程序
- 16.1 国际化介绍
- 16.2 从翻译说起
- 16.3 字符编码和Unicode
- 16.4 数字和日期
- 16.5 其它媒介
- 16.6 一个小例子
- 第十六章小结
- 第十七章编写多线程程序
- 17.1 什么时候使用多线程,什么时候不要使用
- 17.2 使用wxThread
- 17.3 用于线程同步的对象
- 17.4 多线程的替代方案
- 第十七章小结
- 第十八章使用wxSocket编程
- 18.1 Socket类和功能概览
- 18.2 Socket及其基本处理介绍
- 18.3 Socket标记
- 18.4 使用Socket流
- 18.5 替代wxSocket
- 第十八章小结
- 第十九章使用文档/视图框架
- 19.1 文档/视图基础
- 19.2 文档/视图框架的其它能力
- 19.3 实现Undo/Redo的策略
- 第十九章小结
- 第二十章完善你的应用程序
- 20.1 单个实例和多个实例
- 20.2 更改事件处理机制
- 20.3 降低闪烁
- 20.4 实现联机帮助
- 20.5 解析命令行参数
- 20.6 存储应用程序资源
- 20.7 调用别的应用程序
- 20.8 管理应用程序设置
- 20.9 应用程序安装
- 20.10 遵循用户界面设计规范
- 20.11 全书小结