<script type="text/javascript"><!--google_ad_client = "pub-3269163127493396";google_ad_width = 120;google_ad_height = 90;google_ad_format = "120x90_0ads_al";//2007-05-08: ITgoogle_ad_channel = "0064192373";google_color_border = "6699CC";google_color_bg = "003366";google_color_link = "FFFFFF";google_color_text = "AECCEB";google_color_url = "AECCEB";//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
2.2 文本
如何在画布上签名?下面就要解决这个问题。
2.2.1 TextOut
朝屏幕输出文本最简单的方法就是使用TextOut函数。下面看一下它的原型:
2.2.2 DrawText
DrawText比TextOut稍微复杂一点。它的原型如下:
表2.2DrawText格式化标志
样式
描述
DT_BOTTOM
文本在文本框内底部对齐。若要使用本标志,必须同时使用DT_SINGLELINE标志
DT_CENTER
这个标志使文本在文本框内水平居中
DT_LEFT
文本左对齐
DT_RIGHT
文本右对齐
DT_SINGLELINE
在单行里显示所有文字。有回车键文字也不换行
DT_TOP
文本顶部对齐
DT_WORDBREAK
这个标志的效果类似于字的换行
2.2.3 加入颜色和透明度
在Windows中可以自己定义背景色和前景色,还可以设置文本的透明度。为了设置文本颜色,需要利用SetTextColor函数:
为了将文本颜色设为红色而背景设为黑色,可以执行下面这些语句。
除了能够设置前景和背景色以外,还可以设置透明度。这把显示到屏幕上的文本的背景部分变成了透明(例如,如果文本背后是一个图案,则看起来就像是把文字直接打印到图案上一样)。
可以用SetBkMode函数设置背景的透明度:
int SetBkMode(
HDC hdc, //DC句柄
int iBkMode //用以指明背景模式标志
);只有两个标志可用:OPAQUE(不透明)和TRANSPARENT(透明)。因此,要使用透明背景绘制文本的时候,在具体绘制之前,应设置合适的背景模式。
GDI_Text的源代码示范了所有这些函数的使用。
默然:这里有两个文件:main.cpp和defines.h
首先是main.cpp
嗯,我不逐句翻译了,只把与前面不同的地方翻译一下。
//-----------------------------------------------------------------------
//
// Name: GDI_Text示例工程
//
// Author: Mat Buckland 2002
//
// Desc: 代码演示了文本输出
//------------------------------------------------------------------------
#include <windows.h>
#include <time.h>
#include "defines.h"
//--------------------------------- Globals ------------------------------
//
//------------------------------------------------------------------------
char* g_szApplicationName = "The Groovy GDI - Text Output";
char* g_szWindowClassName = "MyWindowClass";
//---------------------------- WindowProc ---------------------------------
//
// This is the callback function which handles all the windows messages
//-------------------------------------------------------------------------
LRESULT CALLBACK WindowProc (HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...{
//these hold the dimensions of the client window area
static int cxClient, cyClient;
switch (msg)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
//A WM_CREATE msg is sent when your application window is first
//created
case WM_CREATE:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
//to get get the size of the client window first we need to create
//a RECT and then ask Windows to fill in our RECT structure with
//the client window size. Then we assign to cxClient and cyClient
//accordingly
RECT rect;
GetClientRect(hwnd, &rect);
cxClient = rect.right;
cyClient = rect.bottom;
}
break;
case WM_KEYUP:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
switch(wParam)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
case VK_ESCAPE:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
PostQuitMessage(0);
}
break;
}
}
case WM_PAINT:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
PAINTSTRUCT ps;
BeginPaint (hwnd, &ps);
//Make the bottom part of window a pattern so you can see what
//the transparency flag does
HBRUSH PatternBrush = CreateHatchBrush(HS_BDIAGONAL, RGB(0,0,255));
HBRUSH OldBrush = (HBRUSH)SelectObject(ps.hdc, PatternBrush);
Rectangle(ps.hdc,0, cyClient/2, cxClient, cyClient);
//替换回旧画刷
SelectObject(ps.hdc, OldBrush);
//首先,演示用TextOut输出演示文本
char* text = "1. I ain't got time to bleed.";
TextOut(ps.hdc, 5, 5, text, strlen(text));
//现在是DrawText.首先我们创建一个文本框
RECT TextBox;
TextBox.top = 30;
TextBox.left = 100;
TextBox.bottom = 200;
TextBox.right = cxClient-100;
//文本赋值
text = "2. You take the blue pill and the story ends.You wake in your bed and believe whatever you want to believe.You take the red pill and you stay in Wonderland and I show you how deep the rabbit-hole goes.";
//现在,画文本
DrawText(ps.hdc, text, strlen(text), &TextBox, DT_WORDBREAK);
//现在改变颜色,先设置文本为红色
SetTextColor(ps.hdc, RGB(255, 0, 0));
//设置背景为黑色
SetBkColor(ps.hdc, RGB(0, 0, 0));
TextBox.top = 200;
TextBox.left = 5;
TextBox.bottom = 300;
TextBox.right = cxClient-200;
text = "3. The greatest trick the devil ever pulled was convincing the world he didn't exist.";
DrawText(ps.hdc, text, strlen(text), &TextBox, DT_WORDBREAK);
//现在,设置背景透明
SetBkMode(ps.hdc, TRANSPARENT);
TextBox.top = 300;
TextBox.left = 100;
TextBox.bottom = cyClient;
TextBox.right = cxClient-50;
text = "4. ...I抦 42 years old. In less than a year I抣l be dead";
DrawText(ps.hdc, text, strlen(text), &TextBox, DT_WORDBREAK);
EndPaint (hwnd, &ps);
}
break;
//has the user resized the client area?
case WM_SIZE:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
//if so we need to update our variables so that any drawing
//we do using cxClient and cyClient is scaled accordingly
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
}
break;
case WM_DESTROY:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
// kill the application, this sends a WM_QUIT message
PostQuitMessage (0);
}
break;
}//end switch
//this is where all the messages not specifically handled by our
//winproc are sent to be processed
return DefWindowProc (hwnd, msg, wParam, lParam);
}
//-------------------------------- WinMain -------------------------------
//
// The entry point of the windows program
//------------------------------------------------------------------------
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR szCmdLine,
int iCmdShow)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...{
//handle to our window
HWND hWnd;
//our window class structure
WNDCLASSEX winclass;
// first fill in the window class stucture
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hInstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = g_szWindowClassName;
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
//register the window class
if (!RegisterClassEx(&winclass))
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
MessageBox(NULL, "Registration Failed!", "Error", 0);
//exit the application
return 0;
}
//create the window and assign its ID to hwnd
hWnd = CreateWindowEx (NULL, // extended style
g_szWindowClassName, // window class name
g_szApplicationName, // window caption
WS_OVERLAPPEDWINDOW, // window style
0, // initial x position
0, // initial y position
WINDOW_WIDTH, // initial x size
WINDOW_HEIGHT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
//make sure the window creation has gone OK
if(!hWnd)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
MessageBox(NULL, "CreateWindowEx Failed!", "Error!", 0);
}
//make the window visible
ShowWindow (hWnd, iCmdShow);
UpdateWindow (hWnd);
//this will hold any windows messages
MSG msg;
//entry point of our message handler
while (GetMessage (&msg, NULL, 0, 0))
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
UnregisterClass( g_szWindowClassName, winclass.hInstance );
return msg.wParam;
}然后,是defines.h
#ifndef DEFINES_H
#define DEFINES_H
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 400
#endif2.2.4 实时消息抽取循环
在GDI_Polygon例子里,每次需要显示一个新的多边形,就得按一次空格键,这可能显得有点繁琐。但怎样才能在屏幕上连续不断地显示新的多边形来催眠用户呢?仅用GetMessage是办不到的。如果消息队列中没有消息,GetMessage就会等待,直到新的消息出现在队列中。需要这样一种消息循环,只有在需要处理消息时才去处理消息,其余的时间都让游戏代码去自动产生激动的场面。为了做到这一点,可以使用PeekMessage函数。其原型如下:
BOOL PeekMessage(
LPMSG lpMsg, //message结构指针
HWND hWnd, //窗口句柄
UINT wMsgFilterMin, //指定被检查的消息范围里的第一个message
UINT wMsgFilterMax, //指定被检查的消息范围里的最后的message
UINT wRemoveMsg //移走标志
);最后一个参数wRemoveMsg,它的值可以是PM_NOREMOVE(消息处理后仍保留在队列中),或PM_REMOVE(消息处理后移走),通常选择后者。如果队列中有消息,PeekMessage将返回true,否则返回false。
要创建实时的消息抽取循环,就需要更复杂一些,如果只把GetMessage替换作PeekMessage,那么,当队列中没有消息时,PeekMessage返回零,应用程序会因此而终止。下面尝试用另一种形式来修改绘制多边形的例子。
while(PeekMessage(&msg,NULL,0,0,PM_))
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...{
TranslateMessage(&msg);
DispatchMessage(&msg);
}这样只会见到应用程序窗口闪电般地打开,接着就立即关闭。而实际中需要的是一个更为强健的设计,过程如下:
//进入message抽取循环
bool bDone=false;
MSG msg;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
while(!bDone)...{
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE))...{
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
if(msg.message==WM_QUIT)...{
//如果是quit消息,就退出循环
bDone=true;
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
}else...{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//下面是调用WM_PAINT绘制场景
InvalidateRect(hWnd,NULL,TRUE);
UpdateWindow(hWnd);
}从GDI_Polygon2例子里的消息循环的运行情况中,可以发现WindowProc中的WM_PAINT部分现在包含产生新多边形的代码。这里利用了小巧的Sleep函数让程序每帧有几毫秒的延迟,这样就能实际看清每个多边形。调用Sleep时,参数表示程序应当暂停的毫秒数,暂停过后,程序接着就自动继续运行。
默然:下面公布GDI_Ploygon2的源代码,由于只有main.cpp与GDI_Ploygon不同,所以这里只列出了main.cpp的源代码,并只翻译了改变部分的注释。
//-----------------------------------------------------------------------
//
// Name: GDI_Polygon2 example project
//
// Author: Mat Buckland 2002
//
// Desc: Code demonstrating the creation and use of a realtime message
// pump
//
//------------------------------------------------------------------------
#include <windows.h>
#include <time.h>
#include "defines.h"
#include "utils.h"
//--------------------------------- Globals ------------------------------
//
//------------------------------------------------------------------------
char* g_szApplicationName = "The Groovy GDI - Dazzle";
char* g_szWindowClassName = "MyWindowClass";
//---------------------------- WindowProc ---------------------------------
//
// This is the callback function which handles all the windows messages
//-------------------------------------------------------------------------
LRESULT CALLBACK WindowProc (HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...{
//create some pens to use for drawing
static HPEN BluePen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
static HPEN OldPen = NULL;
//create a solid brush
static HBRUSH RedBrush = CreateSolidBrush(RGB(255, 0, 0));
static HBRUSH OldBrush = NULL;
//these hold the dimensions of the client window area
static int cxClient, cyClient;
//this will hold the vertices of the polygons we create
static POINT verts[NUM_VERTS];
static int iNumVerts = NUM_VERTS;
switch (msg)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
//A WM_CREATE msg is sent when your application window is first
//created
case WM_CREATE:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
//to get get the size of the client window first we need to create
//a RECT and then ask Windows to fill in our RECT structure with
//the client window size. Then we assign to cxClient and cyClient
//accordingly
RECT rect;
GetClientRect(hwnd, &rect);
cxClient = rect.right;
cyClient = rect.bottom;
//seed random number generator
srand((unsigned) time(NULL));
//now lets create some random vertices
for (int v=0; v<iNumVerts; ++v)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
verts[v].x = RandInt(0, cxClient);
verts[v].y = RandInt(0, cyClient);
}
}
break;
case WM_KEYUP:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
switch(wParam)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
case VK_SPACE:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
//create some new points for our polygon
//now lets create some random vertices
for (int v=0; v<iNumVerts; ++v)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
verts[v].x = RandInt(0, cxClient);
verts[v].y = RandInt(0, cyClient);
}
//refresh the display so we can see our
//new polygon
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
break;
case VK_ESCAPE:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
PostQuitMessage(0);
}
break;
}
}
case WM_PAINT:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
//create some random vertices for the polygon
for (int v=0; v<iNumVerts; ++v)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
verts[v].x = RandInt(0, cxClient);
verts[v].y = RandInt(0, cyClient);
}
PAINTSTRUCT ps;
BeginPaint (hwnd, &ps);
//first select a pen to draw with and store a copy
//of the pen we are swapping it with
OldPen = (HPEN)SelectObject(ps.hdc, BluePen);
//do the same for our brush
OldBrush = (HBRUSH)SelectObject(ps.hdc, RedBrush);
//draw the polygon
Polygon(ps.hdc, verts, iNumVerts);
//replace the original pen
SelectObject(ps.hdc, OldPen);
//and brush
SelectObject(ps.hdc, OldBrush);
EndPaint (hwnd, &ps);
//使用这个简单的Sleep,我们就可以控制绘制多边形的频率,以便让我们看清多边形
Sleep(100);
}
break;
//has the user resized the client area?
case WM_SIZE:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
//if so we need to update our variables so that any drawing
//we do using cxClient and cyClient is scaled accordingly
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
//create a new polygon
for (int v=0; v<iNumVerts; ++v)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
verts[v].x = RandInt(0, cxClient);
verts[v].y = RandInt(0, cyClient);
}
}
break;
case WM_DESTROY:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
//delete the pens
DeleteObject(BluePen);
DeleteObject(OldPen);
//and the brushes
DeleteObject(RedBrush);
DeleteObject(OldBrush);
// kill the application, this sends a WM_QUIT message
PostQuitMessage (0);
}
break;
}//end switch
//this is where all the messages not specifically handled by our
//winproc are sent to be processed
return DefWindowProc (hwnd, msg, wParam, lParam);
}
//-------------------------------- WinMain -------------------------------
//
// The entry point of the windows program
//------------------------------------------------------------------------
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR szCmdLine,
int iCmdShow)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...{
//handle to our window
HWND hWnd;
//our window class structure
WNDCLASSEX winclass;
// first fill in the window class stucture
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hInstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = g_szWindowClassName;
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
//register the window class
if (!RegisterClassEx(&winclass))
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
MessageBox(NULL, "Registration Failed!", "Error", 0);
//exit the application
return 0;
}
//create the window and assign its ID to hwnd
hWnd = CreateWindowEx (NULL, // extended style
g_szWindowClassName, // window class name
g_szApplicationName, // window caption
WS_OVERLAPPEDWINDOW, // window style
0, // initial x position
0, // initial y position
WINDOW_WIDTH, // initial x size
WINDOW_HEIGHT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
//make sure the window creation has gone OK
if(!hWnd)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
MessageBox(NULL, "CreateWindowEx Failed!", "Error!", 0);
}
//make the window visible
ShowWindow (hWnd, iCmdShow);
UpdateWindow (hWnd);
//进行消息循环
bool bDone = false;
MSG msg;
while(!bDone)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
if( msg.message == WM_QUIT )
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
// 如果是程序退出消息则停止循环
bDone = true;
}
else
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
...{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
//这里会调用WM_PAINT,完成对我们的窗口的重绘
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
//*** 你的游戏主循环应该就放在这里 ***//
}//end while
UnregisterClass( g_szWindowClassName, winclass.hInstance );
return msg.wParam;
}您好:
当您在阅读和使用我所提供的各种内容的时候,我非常感谢,您的阅读已是对我最大的支持。
我更希望您能给予我更多的支持。
1.希望您帮助我宣传我的博客,让更多的人知道它,从中获益(别忘记了提醒他们帮我点点广告,嘿嘿)。
2.希望您能多提出宝贵意见,包括我所提供的内容中的错误,建设性的意见,更希望获得哪些方面的帮助,您的经验之谈等等。
3.更希望能得到您经济上的支持。
我博客上面的内容均属于个人的经验,所有的内容均为开源内容,允许您用于任何非商业用途,并不以付费为前提,如果您觉得在阅读和使用我所提供的各种内容的过程中,您得到了帮助,并能在经济上给予我支持,我将感激不尽。
您可以通过点击我网站上的广告表示对我的支持。
您可以通过银行转帐付款给我:
招商银行一卡通:
卡号:6225888712586894
姓名:牟勇
您也可以通过汇款的方式:
通讯地址:云南省昆明市女子(28)中学人民中路如意巷1号
收信人:陈谦转牟勇收
邮编:650021
无论您给予我怎么样的支持,我都衷心的再次感谢。
欢迎光临我的博客,欢迎宣传我的博客
http://blog.csdn.net/mouyong
http://blog.sina.com.cn/mouyong
EMail:mouyong@yeah.net
QQ:11167603
MSN:mouyong1973@hotmail.com
<script type="text/javascript"><!--google_ad_client = "pub-3269163127493396";google_ad_width = 468;google_ad_height = 60;google_ad_format = "468x60_as";google_ad_type = "text_image";//2007-05-08: ITgoogle_ad_channel = "0064192373";google_color_border = "336699";google_color_bg = "FFFFFF";google_color_link = "0000FF";google_color_text = "000000";google_color_url = "008000";//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>