# 5.2 绘画工具
在wxWidgets中,绘画操作就象是一个技术非常高超的艺术家,快速的选择颜色,绘画工具,然后画场景的一小部分,然后换不同的颜色,不同的工具,再绘画场景的其它部分,周而反复的操作。因此,接下来我们来介绍一下wxColour,wxPen, wxBrush, wxFont和wxPalette这些绘画工具。还有其它的一些内容也是有帮助的,比如wxRect,wxRegion,wxPoint和wxSize,我们会在第13章,�数据结构类�中对它们进行介绍。
注意这些类使用了�引用记数�的方法,使用内部指针以避免大块的内存拷贝,在大多数情况下,你可以直接以局部变量的方式定义颜色,画笔,画刷和字体对象而不用担心性能。如果你的程序确实因此而拥有性能上的问题,你才需要考虑采取一些方法来提高性能,比如将其中的一些局部变量改变成类的成员。
wxColour
你可以使用wxColour类来定义各种各样的颜色。(因为wxWidgets开始于爱丁堡,它的API使用英式拼写,不过对于那些对拼写很敏感的人,wxWidgets还是给wxColor定义了一个别名wxColour)。
你可以使用SetTextForeground和SetTextBackground函数来定义一个设备上下文中文本的颜色,也可以使用wxColour来创建画笔和刷子。
wxColour对象有很多种创建方法,你可以使用RGB三元色的值(0到255)来构建wxColour,或者通过一个标准的字符串,比如WHITE或者CYAN,或者从另外一个wxColour对象创建。或者你还可以直接使用系统预定的颜色对象指针: wxBLACK, wxWHITE, wxRED, wxBLUE, wxGREEN, wxCYAN,和 wxLIGHT_GREY.还有一个wxNullColour对象用来代表未初始化的颜色,它的Ok函数总是返回False。
使用wxSystemSettings类可以获取很多系统默认的颜色,比如3D表面颜色,默认的窗口背景颜色,菜单文本颜色等等。请参考相关文档中wxSystemSettings::GetColour的部分来获取详细的列表。
下面的例子演示了创建wxColour的方法:
```
wxColour color(0, 255, 0); // green
wxColour color(wxT("RED")); // red
// 使用面板的三维表面系统颜色
wxColour color(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
```
wxTheColourDatabase指针用来在系统之类的颜色和颜色名之间建立映射,通过颜色名寻找对应的颜色对象或者通过颜色对象来寻找对应的颜色名,如下所示:
```
wxTheColourDatabase->Add(wxT("PINKISH"), wxColour(234, 184, 184));
wxString name = wxTheColourDatabase->FindName(
wxColour(234, 184, 184));
wxString color = wxTheColourDatabase->Find(name);
```
下面列出了目前支持的标准颜色:aquamarine, black, blue, blue violet, brown, cadet blue, coral, cornflower blue, cyan, dark gray, dark green, dark olive green, dark orchid, dark slate blue, dark slate gray dark turquoise, dim gray, firebrick, forest green, gold, goldenrod, gray, green, green yellow, indian red, khaki, light blue, light gray, light steel blue, lime green, magenta, maroon, medium aquamarine, medium blue, medium forest green, medium goldenrod, medium orchid, medium sea green, medium slate blue, medium spring green, medium turquoise, medium violet red, midnight blue, navy, orange, orange red, orchid, pale green, pink, plum, purple, red, salmon, sea green, sienna, sky blue, slate blue, spring green, steel blue, tan, thistle, turquoise, violet, violet red, wheat, white, yellow, 和 yellow green.
wxPen
你可以使用SetPen函数指定一个设备上下文使用的画笔(wxPen)。画笔指定了随后的绘画操作中线条的颜色,粗细以及线条类型。wxPen的开销很小,你可以放心的在你的绘图代码中创建局部变量类型的画笔对象而不用对它们进行全局存储。
下表列出了目前支持的画笔线条类型,其中Hatch和stipple类型目前的GTK+版本不支持:
| 线形 | 示例 | 描述 |
|:--- |:--- |:--- |
| wxSOLID | ![](img/mht8198%281%29.tmp) | 纯色线. |
| wxTRANSPARENT | 透明颜色. |
| wxDOT | ![](img/mht819B%281%29.tmp) | 纯点线. |
| wxLONG_DASH | ![](img/mht81AE%281%29.tmp) | 长虚线. |
| wxSHORT_DASH | ![](img/mht81B1%281%29.tmp) | 短虚线.在windows平台上等同于wxLONG_SASH. |
| wxDOT_DASH | ![](img/mht81B4%281%29.tmp) | 短线和点间隔线. |
| wxSTIPPLE | ![](img/mht81C6%281%29.tmp) | 使用一个位图代替点的点虚线,这个位图是其构造函数的第一个参数 |
| wxUSER_DASH | ![](img/mht81C9%281%29.tmp) | 自定义虚线. 参考用户手册. |
| wxBDIAGONAL_HATCH | ![](img/mht81CC%281%29.tmp) | 反斜线虚线. |
| wxCROSSDIAG_HATCH | ![](img/mht81DF%281%29.tmp) | 交叉虚线. |
| wxFDIAGONAL_HATCH | ![](img/mht81E2%281%29.tmp) | 斜线虚线. |
| wxCROSS_HATCH | ![](img/mht81F4%281%29.tmp) | 十字虚线. |
| wxHORIZONTAL_HATCH | ![](img/mht81F7%281%29.tmp) | 水平线段虚线. |
| wxVERTICAL_HATCH | ![](img/mht820A%281%29.tmp) | 垂直线段虚线. |
使用SetCap定义粗线条的末端的样子:wxCAP_ROUND是默认的设置,只是粗线条的末端应该使用圆形,wxCAP_PROJECTING则只是使用方形并且有一个凸起,wxCAP_BUTT则只是直接使用方形。
使用SetJoin函数来设置当有线段相连时候的联结方式,默认的值是wxJOIN_ROUND,这种情况下转角是圆形的,其它可选的值还有wxJOIN_BEVEL和wxJOIN_MITER.
你也可以直接使用预定的画笔对象:wxRED_PEN, wxCYAN_PEN, wxGREEN_PEN, wxBLACK_PEN, wxWHITE_PEN, wxtrANSPARENT_PEN, wxBLACK_DASHED_PEN, wxGREY_PEN, wxMEDIUM_GREY_PEN 和 wxLIGHT_GREY_PEN.这些都是指针,所以在SetPen函数中使用的时候,应该使用"*"号指向它们的实例。还有一个预定义的对象(不是指针)wxNullPen,可以用来复位设备上下文中的画笔。
下面是创建画笔的一些演示代码,都用来产生一个纯红色的画笔:
```
wxPen pen(wxColour(255, 0, 0), 1, wxSOLID);
wxPen pen(wxT("RED"), 1, wxSOLID);
wxPen pen = (*wxRED_PEN);
wxPen pen(*wxRED_PEN);
```
上面例子中的最后两行使用了引用记数的方法,实际上内部指向同一个对象。这种引用记数的方法在绘画对象中很常用,它使得对象赋值和拷贝的系统开销非常小,不过同时它意味着一个对象的改变将会影响到其它所有使用同一个引用的对象。
一个既可以简化画笔对象的创建和释放过程,又不需要将画笔对象存储在自己的对象中的方法,是使用全局指针wxThePenList来创建和存储所有你需要的画笔对象,如下所示:
```
wxPen* pen = wxThePenList->FindOrCreatePen(*wxRED, 1, wxSOLID);
```
这个wxThePenList指向的对象将负责存储所有的画笔对象并且在应用程序退出的时候自动释放所有的画笔。很显然,你应该小心不要过量使用这个对象以免画笔对象占用大量的系统内存,而且也要注意前面我们提到过的使用引用对象的问题,你可以使用RemovePen函数从 wxThePenList中删除一个画笔但是却不释放它所占的内存。
wxBrush
设备上下文当前使用的画刷对象可以用SetBrush函数指定,它决定设备上下文中图像的填充方式。你也可以使用它来定义设备上下文的默认背景,这样的定义方式可以使得背景不只是简单的纯色。和画笔对象一样,画刷对象的系统消耗也非常小,你可以直接使用局部变量的方式定义它。
画刷的构造函数采用一个颜色参数和一个画刷类型参数,如下表所示:
| 画刷类型 | 例子 | 描述 |
|:--- |:--- |:--- |
| wxSOLID | ![](img/mht820D%281%29.tmp) | 纯色画刷. |
| wxTRANSPARENT | 透明画刷. |
| wxBDIAGONAL_HATCH | ![](img/mht8210%281%29.tmp) | 反斜线画刷. |
| wxCROSSDIAG_HATCH | ![](img/mht8223%281%29.tmp) | 交叉画刷. |
| wxFDIAGONAL_HATCH | ![](img/mht8226%281%29.tmp) | 斜线画刷. |
| wxCROSS_HATCH | ![](img/mht8238%281%29.tmp) | 十字画刷. |
| wxHORIZONTAL_HATCH | ![](img/mht823B%281%29.tmp) | 水平线画刷. |
| wxVERTICAL_HATCH | ![](img/mht823E%281%29.tmp) | 垂直线画刷. |
| wxSTIPPLE | ![](img/mht8251%281%29.tmp) | 位图画刷, 其位图在构造函数中指定. |
你也可以直接使用下面这些系统预定义的画刷:wxBLUE_BRUSH, wxGREEN_BRUSH, wxWHITE BRUSH, wxBLACK_BRUSH, wxGREY_BRUSH, wxMEDIUM_GREY_BRUSH, wxLIGHT_GREY_BRUSH, wxtrANSPARENT_BRUSH, wxCYAN_BRUSH和 wxRED_BRUSH. 这些都是指针,类似的还有wxNullBrush用来复位设备上下文的画刷。
下面是创建红色纯色画刷的例子:
```
wxBrush brush(wxColour(255, 0, 0), wxSOLID);
wxBrush brush(wxT("RED"), wxSOLID);
wxBrush brush = (*wxRED_BRUSH); // a cheap operation
wxBrush brush(*wxRED_BRUSH);
```
和画笔一样,画刷也有一个用来保存列表的全局指针指针: wxTheBrushList,你可以象下面这样使用它:
```
wxBrush* brush = wxTheBrushList->FindOrCreateBrush(*wxBLUE, wxSOLID);
```
同样要避免在应用程序过量使用以及要注意引用记数使用的问题。使用RemoveBrush来从wxTheBrushList中移除一个画刷而不释放其内存。
wxFont
你可以使用字体对象来设置一个设备上下文使用的字体,字体对象有下面一些属性:
字体大小用来以点(1/72英寸)为单位指定字体中的最大高度。wxWidgets会选择系统中最接近的字体。
字体家族用来指定一个家族系列,象下表中描述的那样,指定一个字体家族而不指定一个字体的名字是为了移植的方便,因为你不大可能要求某个字体的名字存在于所有的平台。
| 字体家族标识符 | 例子 | 描述 |
|:--- |:--- |:--- |
| wxFONTFAMILY_SWISS | ![](img/mht8254%281%29.tmp) | 非印刷字体,依平台的不同通常是Helvetica或Arial. |
| wxFONTFAMILY_ROMAN | ![](img/mht8267%281%29.tmp) | 一种正规的印刷字体. |
| wxFONTFAMILY_SCRIPT | ![](img/mht826A%281%29.tmp) | 一种艺术字体. |
| wxFONTFAMILY_MODERN | ![](img/mht827C%281%29.tmp) | 一种等宽字体.通常是Courier |
| wxFONTFAMILY_DECORATIVE | ![](img/mht827F%281%29.tmp) | 一种装饰字体. |
| wxFONTFAMILY_DEFAULT | wxWidgets选择一个默认的字体家族. |
字体类型可以是wxNORMAL, wxSLANT或wxITALIC。其中wxSLANT可能不是所有的平台或者所有的字体都支持。
weight属性的值则可以是wxNORMAL, wxLIGHT或wxBOLD.
下划线可以被设置或者关闭。
字体名属性是可选参数,用来指定一个特定的字体,如果其为空,则将使用指定字体家族默认的字体。
可选的编码方式参数用来指定字体编码和程序用设备上下文绘画的文本的编码方式的映射,详情请参考第16章,�编写国际化应用程序�。
你可以使用默认的构造函数创建一个字体,或者使用上表中列出的字体家族创建一个字体。
也可以使用下面这些系统预定义的字体: wxNORMAL_FONT, wxSMALL_FONT, wxITALIC_FONT和wxSWISS_FONT. 除了wxSMALL_FONT以外,其它的字体都使用同样大小的系统默认字体(wxSYS_DEFAULT_GUI_FONT), 而wxSMALL_FONT则比另外的三个字体小两个点.你可以使用wxSystemSettings::GetFont来获取当前系统的默认字体。
要使用字体,你需要在进行任何字体相关的操作(比如DrawText和GetTextExtent)之前,使用wxDC::SetFont函数设置字体。
下面的代码演示了怎样构造一个字体对象:
```
wxFont font(12, wxFONTFAMILY_ROMAN, wxITALIC, wxBOLD, false);
wxFont font(10, wxFONTFAMILY_SWISS, wxNORMAL, wxBOLD, true,
wxT("Arial"), wxFONTENCODING_ISO8859_1));
wxFont font(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
```
和画笔和画刷一样,字体也有一个全局列表指针wxTheFontList,用来查找以前创建的字体或者创建一个新的字体:
```
wxFont* font = wxTheFontList->FindOrCreateFont(12, wxSWISS,
wxNORMAL, wxNORMAL);
```
同样的,避免大量使用这个全局指针,因为其分配的内存要到程序退出的时候才会释放。你可以使用RemoveFont从中移除一个字体但是不释放相关的内存。
在本章晚些时候我们会看到一些使用文本和字体的例子。同时你也可以看一下字体例子程序,它允许你选择一个字体然后看看某些文本是什么样子,也可以让你更改字体的大小和别的属性。
![](img/mht8292%281%29.tmp)
wxPalette
调色板是一个表,这个表的大小通常是256,表中的每一个索引被映射到一个对应的rgb颜色值。通常在不同的应用程序需要在同一个显示设备上共享确定数目的颜色的时候使用。通过设置一个调色板,应用程序之间的颜色可以取得一个平衡。调色板也被用来把一个低颜色深度的图片映射到当前可用的颜色,因此每个wxBitmap都有一个可选的调色板。
因为现在大多数电脑的显示设备都支持真彩色,调色板已经很少使用了。应用程序定义的RGB颜色可以直接被显示设备映射到最接近的颜色。
创建一个调色板需要提供一个调色板大小参数和三个分别代表红绿蓝三种颜色的数组。你可以通过GetColoursCount函数得到当前调色板中条目的数量。GetRGB函数通过索引找到其代替的颜色的RGB值,而GetPixel则通过RGB值得到其相应的索引。
使用wxDC::SetPalette函数给某个设备上下文指定一个调色板。比如,你可以给当前的设备上下文指定一个位于某个低颜色深度的wxBitmap对象中的调色板,一边让设备上下文知道怎样把这个图片中的索引颜色映射到真实的RGB颜色。当在一个指定了调色板的设备上下文中使用 wxColour绘画的时候,系统会自动在设备上下文的调色板中查找最匹配的颜色的索引,因此你应该指定一个和你要用的颜色最接近的调色板。
wxPalette的另外一个用法是用来查询一个低颜色深度图像文件(比如GIF)中的图像的不同的颜色。如果这个图像拥有一个调色板,即时这个图片已经被转换成RGB格式,区分图像中的不同颜色也仍然是个很容易的事。类似的,通过调色板,你也可以把一个真彩色的图片转换成低颜色深度的图片,下面的代码演示了怎样将一个真彩色的PNG文件转换成8bit的windows位图文件:
```
// 加载这个PNG文件
wxImage image(wxT("image.png"), wxBITMAP_TYPE_PNG);
// 创建一个调色板
unsigned char* red = new unsigned char[256];
unsigned char* green = new unsigned char[256];
unsigned char* blue = new unsigned char[256];
for (size_t i = 0; i < 256; i ++)
{
red[i] = green[i] = blue[i] = i;
}
wxPalette palette(256, red, green, blue);
// 设置调色板和颜色深度
image.SetPalette(palette);
image.SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_8BPP_PALETTE);
// 存储文件
image.SaveFile(wxT("image.bmp"), wxBITMAP_TYPE_BMP);
```
降低颜色深度的更实用的方法请参考第10章,�在程序中使用图片�中的�降低颜色深度�小节,介绍怎样用wxQuantize类来作这件事。
wxWidgets定义了一个空的调色板对象wxNullPalette.
(译者注:这一小节翻译的太费劲了)
- 第一章 介绍
- 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 全书小结