19. 文本显示¶
窗口显示文字的方式,前面讲过一个TEXTBOX文本框,下面讲解一下另一种方式。这种方式之前我们也稍微接触过,就是在WM_PAINT消息,调用TextOut函数绘制文本。
19.1. 文本显示¶
19.1.1. 文本显示相关的函数¶
19.1.1.1. x_wsprintf函数¶
为了适应各种平台,emXGUI自带了C标准库的函数,这些库函数都带了个“x_”的前缀,它们的函数功能与 C 标准库函数的一样。本章使用的函数x_wsprintf就是其中之一,代码清单19_1。x_wsprintf是字符串格式化命令,主要功能是把格式化的数据写入某个缓冲区中。
1 | int x_wsprintf(WCHAR *dest, const WCHAR *format, ...);
|
dest:WCHAR型指针,指向将要写入的字符串的缓冲区。
format:格式化字符串。
emXGUI中WCHAR型是unsigned short类型,这与C库的sprintf有点区别。因此,我们传入的format实参应该是一个unsigned short类型的字符串,否则,则会出现Error。
在C语言中,我们使用char来定义字符,占用一个字节,最多只能表示128个字符,也就是ASCII码中的字符。中文则需要用多个字节来表示,可以通过用字母 L 作为 ASCII 字符串的前缀将任何 ASCII 字符串表示为宽字符字符串形式,例如,L”野火”。L与字符串之间没有空格,这样编译器才知道每个字符占用两个字节,即宽字符。
19.1.1.2. TextOut函数¶
在指定位置显示字符串,使用的是函数TextOut。与DrawText的区别在于:TextOut可以在窗口的任何位置显示字符串。但是却不可以设置文字的格式,如居中对齐,左对齐等,见 代码清单19_2。
1 | BOOL TextOut(HDC hdc,int x,int y,LPCWSTR lpString,int nCount);
|
hdc:绘图上下文。
x,y:文字显示的起点坐标。
lpString:字符串(Unicode-UCS2格式),传入的实参需是宽字符型,支持换行’r’和回车符’n’。
nCount:要显示字符的字符数, 当设置小于0时, 将显示整个字符串文本的内容。
19.2. 文本显示实验¶
19.2.2. 代码分析¶
创建父窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | void GUI_DEMO_TextOut(void)
{
HWND hwnd;
WNDCLASS wcex;
MSG msg;
wcex.Tag = WNDCLASS_TAG;
wcex.Style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WinProc; //设置主窗口消息处理的回调函数.
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = NULL;
wcex.hIcon = NULL;
wcex.hCursor = NULL;
//创建主窗口
hwnd =CreateWindowEx( NULL,
&wcex,
_T("GUI_DEMO - TextOut"), //窗口名称
WS_CAPTION|WS_DLGFRAME|WS_BORDER|WS_CLIPCHILDREN,
0,0,GUI_XSIZE,GUI_YSIZE, //窗口位置和大小
NULL,NULL,NULL,NULL);
//显示主窗口
ShowWindow(hwnd,SW_SHOW);
//开始窗口消息循环(窗口关闭并销毁时,GetMessage将返回FALSE,退出本消息循环)。
while(GetMessage(&msg,hwnd))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
|
创建父窗口,标题栏为“GUI_DEMO_TextOut”,带有大小边框,设置winProc作为窗口回调函数。
窗口回调函数
WM_CREATE
1 2 3 4 5 6 7 | case WM_CREATE: //窗口创建时,会自动产生该消息,在这里做一些初始化的操作或创建子窗口.
{
GetClientRect(hwnd,&rc); //获得窗口的客户区矩形.
CreateWindow(BUTTON,L"OK",WS_VISIBLE,
rc.w-80,8,68,32,hwnd,ID_OK,NULL,NULL); //创建一个按钮(示例).
}
|
WM_CREATE消息中,在坐标(rc.w-80,8)处创建了一个OK按键。用来退出该界面。
WM_NOTIFY
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | case WM_NOTIFY: //WM_NOTIFY消息:wParam低16位为发送该消息的控件ID,高16位为通知码;
lParam指向了一个NMHDR结构体.
{
u16 code,id;
code =HIWORD(wParam); //获得通知码类型.
id =LOWORD(wParam); //获得产生该消息的控件ID.
if(id==ID_OK && code==BN_CLICKED) // 按钮“单击”了.
{
PostCloseMessage(hwnd); //使产生WM_CLOSE消息关闭窗口.
}
break;
}
|
WM_NOTIFY消息用来检测OK键是否被按下。使用HIWORD和LOWORD函数读取控件的ID和通知码。如果OK键被按下,则发送WM_CLOSE消息关闭窗口。
WM_PAINT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | case WM_PAINT: //窗口需要绘制时,会自动产生该消息.
{
PAINTSTRUCT ps;
HDC hdc;
RECT rc;
int i,t,y;
WCHAR wbuf[128];
POINT Point;
GetClientRect(hwnd,&rc);
hdc =BeginPaint(hwnd,&ps); //开始绘图
////用户的绘制内容...
SetTextColor(hdc,MapRGB(hdc,10,10,100));
t=GUI_GetTickCount();
y=24;
i=0;
Point.x = 0;
while(y<rc.h)
{
Point.y = y;
ClientToScreen(hwnd, &Point, 1);
if(Point.y > 480) break;
TextOut(hdc,10,y,L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",-1);
y+=20;
i++;
}
t =GUI_GetTickCount()-t;
SetTextColor(hdc,MapRGB(hdc,250,10,10));
x_wsprintf(wbuf,L"TextOut Time used:%dms; %.1fms/line",t,(float)t/(float)i);
TextOut(hdc,10,4,wbuf,-1);
EndPaint(hwnd,&ps); //结束绘图
break;
}
|
在WM_PAINT消息中,绘制显示的文字。绘制过程中,需要调用BeginPaint来获取绘图上下文和EndPaint函数结束绘图。使用GUI_GetTickCount函数来得到当前系统的时间,存放到变量t中。TextOut函数用来输出文本,这里显示的内容为:0123456789ABCDEFGHIJK LMNOPQRSTUVWXYZ。我们使用的字体为GB2312_20_4BPP,字体高是20,所以使每行的文本的起点y坐标偏移20个像素。
调用ClientToScreen函数,将每行的起点坐标,转换为屏幕坐标,这里的起点坐标指的是客户区里面的坐标。这样的话,一旦起点坐标超出了屏幕的高度,就会停止显示文字。ClientToScreen函数的具体说明,可以查阅《emXGUI API 编程手册》章节:窗口/消息系统API。
变量i记录行数,耗费的时间=总时间t/总行数i。x_wsprintf函数的用法,与C语言的sprintf用法一致。以x_w开头的函数,都是emXGUI封装的C库函数。最后,将耗费的时间显示在(10,4)处。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | void GUI_AppMain(void)
{
while(1)
{
GUI_DEMO_Button();
GUI_DEMO_Checkbox();
GUI_DEMO_Radiobox();
GUI_DEMO_Textbox();
GUI_DEMO_Progressbar();
GUI_DEMO_Scrollbar();
GUI_DEMO_Listbox();
GUI_DEMO_Messagebox();
GUI_DEMO_TextOut();
}
}
|
将GUI_DEMO_TextOut函数创建的窗口,加入到GUI_AppMain中,如 代码清单19_7。