分享
 
 
 

Programming Windows摘要

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

第二章 输出文本

一、 WM_PAINT消息:

在应用程序进入WinMain函数后调用UpdateWindow函数,Windows利用这个机会就给窗体过程发送一个WM_PAINT消息,要求绘制无效区域。

在如下情况下窗体过程会收到WM_PAINT消息:

1、在用户移动窗口或显示窗口时,窗口中先前被隐藏的区域重新可见时

2、用户改变窗口大小时(但是必须具有CS_HREDRAW和CS_VREDRAW设置)

3、程序使用ScrollWindow或者ScrollDc函数滚动客户区一部分时

4、程序使用InvalidateRect或者InvalidateRect函数显式产生WM_PAINT消息。

如下情况下Windows可能发出WM_PAINT消息:

1、Windows擦除覆盖了部分窗口的对话框或者消息框

2、菜单下拉出来然后释放

3、显示工具提示

某些情况下Windows总是保存他所覆盖显示区域,然后自动恢复:

1、鼠标光标穿越客户区

2、图标拖过客户区

注意窗口过程接收WM_PAINT消息的唯一条件是:客户区的某一部分失效。

现对窗体过程对WM_PAINT消息的处理如下说明:

1、当窗口过程处理WM_PAINT之前另一个区域变无效,Windows就会去计算一个包围在两个区域的新无效区域,并将这些变化写入绘制信息结构中。Windows是不会,请注意,不会把多个WM_PAINT消息放入消息队列的。

2、Windows默认情况下对WM_PAINT消息的处理,也就是DefWindowProc对该消息的响应如下:

Case WM_PAINT:

BeginPaint(hwnd, &ps);

EndPaint(hwnd, &ps);

Return 0;

二、设备描述表

1、绘图信息结构

typedef struct tagPAINTSTRUCT { // ps

HDC hdc;

BOOL fErase;

RECT rcPaint;

BOOL fRestore;

BOOL fIncUpdate;

BYTE rgbReserved[32];

} PAINTSTRUCT;

对这个结构说明如下:

程序员所用到一般是前三个字段,其他的由Windows处理。

hdb设备描述表句柄。

fErase一般来说是FALSE(0),意味着Windows已经擦除了无效矩形背景。

如果使用InvalidRect(hwnd,NULL,FALSE)函数后,窗口过程处理完WM_PAINT消息后就将fErase字段置1。

第三个参数是Rect类型:

typedef struct _RECT {

LONG left;

LONG top;

LONG right;

LONG bottom;

} RECT;

表示了无效区域的位置。

2、获取设备描述表的句柄

方法1:

处理WM_PAINT的时候使用这个方法:

PAINTSTRUCT ps;

HDC hdc;

case WM_PAINT:

hdc=BeginPaint(hwnd,&ps);

EndPaint(hwnd,&ps);

return 0;

注意这种方法错误:

case WM_PAINT:

return 0;

千万不要这样!!Windows将一个WM_Paint消息放入消息队列就是因为客户区一部分无效。如果不调用BeginPaint与EndPaint或者ValidateRect那么这个区域不会变成有效,然后Windows就会一直发WM_Paint消息。

另外,Windows通过一个InvalidateRect让整个客户区内的矩形无效,当收到WM_PAINT消息的时候可以通过GetUpdateRect在获得无效矩形的坐标。

在处理WM_PAINT消息期间,窗口过程调用了BeginPaint以后,(BeginPaint函数一般在准备绘制时导致无效区域的背景被当前的画刷擦除,该函数也填入ps结构的域)整个客户区变成有效,程序可以通过调用ValidateRect函数使客户区内的任意矩形区域变为有效。如果调用这条命令以后使得整个客户区有效,那么当前消息队列中的所有的WM_PAINT消息就被删除。

方法二:

一般调用GetDC和ReleaseDC对键盘消息或者鼠标消息作出反应。

hdc=GetDC(hwnd);

ReleaseDC(hwnd,hdc);

注意:必须在退出窗口过程之前调用ReleaseDC,不要在一个消息中调用GetDC,却在另一个消息中去调用ReleaseDC

与GetDC相似的还有GetwindowDC,这个函数返回整个窗口的设备描述句柄。

两种方式的不同:

GetDC返回的设备描述表句柄具有一个剪取区域,等于整个客户区,GetDC也不会使无效区域变成有效。

而BeginPaint开始的时候就会恢复无效区域。

如下调用

InvalidateRect(hwnd,NULL,TRUE)

可以使得整个客户区变为无效,并擦除背景,这是一种简单的重画客户区的方法。

而ValidateRect(hwnd,NULL)则相反。

三、TextOut细节问题:

TextOut(hdc,x,y,psText,iLength)

psText:指向要显示的字符的指针

iLength:所显示字符串的长度

与wsprintf如下综合使用:

int iLength;

TCHAR szBuffer[40];

iLength=wsprintf(szBuffer,TEXT(“The sum of %i and %i is %i”),iA,IB,IA+IB);

TextOut(hdc,x,y,szBuffer,iLength);

四、字体的问题

程序调用一个GetSystemMetrics函数来确定用户界面的大小

如下调用

TEXTMERIC tm;

hdc=GetDC(hwnd);

GetTextMetrics(hdc,&tm);

ReleaseDC(hwnd,hdc);

关于TEXTMETRIC结构如下:

typedef struct tagTEXTMETRIC { // tm

LONG tmHeight;

LONG tmAscent;

LONG tmDescent;

LONG tmInternalLeading;

LONG tmExternalLeading;

LONG tmAveCharWidth;

LONG tmMaxCharWidth;

LONG tmWeight;

LONG tmOverhang;

LONG tmDigitizedAspectX;

LONG tmDigitizedAspectY;

BCHAR tmFirstChar;

BCHAR tmLastChar;

BCHAR tmDefaultChar;

BCHAR tmBreakChar;

BYTE tmItalic;

BYTE tmUnderlined;

BYTE tmStruckOut;

BYTE tmPitchAndFamily;

BYTE tmCharSet;

} TEXTMETRIC;

2、格式化文本

首先使用两个变量存放平均的字符高度宽度:

static int cxChar,cyChar;

case WM_CREATE:

hdc=GetDC(hwnd);

GetTextMerics(hdc,&tm);

cxChar=tm.tmAveCharWidth;

cyChar=tm.tmHeight+tm.tmExternalLeading;

ReleaseDC(hwnd,hdc);

return 0;

五、滚动条

1、客户区域的大小:

客户区与是否最大化可以通过

使用SM_CXFULLSCREEN和SM_CYFULLSCREEN为参数调用GetSystemMetrics获得。

另外可以通过GetClientRect函数来确定客户区的大小。这个函数应该在WM_SIZE消息发生的时候去调用。传给窗口过程的lParam参数的低位字中包含客户区的宽度,高位中包含客户区的高度。

使用如下两个变量保存:

static int cxClient,cyClient;

实际使用如下:

WM_SIZE:

cxClient=LOWORD(lParam);

cyClient=HIWORD(lParam);

return 0;

客户区文本的总行数:cyClient/cyChar

客户区水平方向可显示的小写字母数:cxClient/cxChar

另外大多数情况下,一个WM_SIZE消息后面总是跟着WM_PAINT消息,这是因为我们制定窗体风格:CS_HREDRAW|CS_VREDRAW

这类风格告诉Windows当水平或者垂直大小发生变化,强制刷新客户区。

2、滚动条生成:

滚动条的生成可以在CreateWindow中的窗体风格中标示:

WS_VSCROLL或者WS_HSCROLL

3、滚动条范围和位置:

默认情况下范围0~100

如下函数改变范围:

SetScrollRange(hwnd,iBar,iMin,iMax,bRedraw);

bRedraw:如果要windows根据新范围重画滚定条,则设置

bRedraw为TRUE,如果在调用SetScrollRange以后调用了影响滚动条位置的其他函数,应该将

bRedraw设置为FALSE,避免多次重画。

iBar:数值是SB_VERT或者SB_HORZ

设置滚动条位置:

SetScrollPos(hwnd,iBar,iPos,bRedraw);

另外Windows提供了GetScrollRange和GetScrollPos来获得滚动条的当前范围和当前的位置。

请注意这个函数GetScrollPos,该函数在用户拖动滚动条或者滚动块的时候并不改变,必须使用SetScrollPos函数才能改变其数值,这就是为什么拖动滚动块,如果不调用SetScrollPos来处理SB_THUMBTRACK或者SB_THUMPOSITION消息,在用户释放鼠标键后,滚动框会迅速跳回原来位置的原因。

4、滚动条消息

下面是windows对滚动条的处理:

处理所有滚动条鼠标时间

当用户在滚动条内单击鼠标时,提供一种“反向闪烁”

当用户在滚动条内拖动滚动框,移动滚动框

为包含滚动条窗口的窗口过程发送滚动条消息

以下是程序员要处理的:

初始化滚动条的范围和位置

处理窗口过程响应滚动条消息

更新滚动条内滚动框的位置

更改客户区的内容以响应对滚动条更改

windows给窗口过程发送的是WM_VSCROLL(上下移动),

WM_HSCROLL(供左右移动)消息。

滚动条的消息都是一对的,在鼠标按下和释放的时候。

与其他消息一样WM_VSCROLL和WM_HSCROLL也有wParam和lParam消息参数。对于来自作为窗口的一部分而创建的滚动条消息,可以忽略lParam,他只用于作为子窗口而创建的滚动条。

而wParam消息参数则被分为一个低字位和一个高字位。其中低字位是一个数值,指出了鼠标对滚动条进行的操作(见P91),高字位是用户在拖动滚动框时的当前位置。

鼠标拖动滚动框移动它的时候,应用程序将收到SB_THUMBTRACK消息。然而,如果不通过调用SetScrollPos来处理SB_THUMBTRACK或SB_THUMBPOSITION消息,用户释放释放鼠标键后,滚动框会迅速跳会原来的位置。

如果处理SB_THUMBTRACK消息,用户拖动滚动框时您需要移动客户区的内容。

如果处理SB_THUMBPOSITION消息,只要在用户停止滚动框时移动客户区的内容。

而WINUSER.H头文件还包括的SB_TOP、SB_BOTTOM、SB_LEFT和SB_RIGHT通知码之处滚动条已经移到了它的最大或者最小位置。但是作为应用程序窗口一部分而创建的滚动条来说,永远不会接受到这些通知码。

5、Win32API下的滚动条函数

Win32API提供了如下两个滚动条函数:

SetScrollInfo和GetScrollInfo函数

SetScrollInfo(hwnd, iBar, &si, bRedraw);

GetScrollInfo(hwnd, iBar, &si);

IBar: SB_VERT或SB_HORZ或者是滚动条控制的SB_CTL

SCROLLINFOR结构定义如下:

typedef struct tagSCROLLINFO

{

UINT cbSize ; // set to sizeof (SCROLLINFO)

UINT fMask ; // values to set or get

int nMin ; // minimum range value

int nMax ; // maximum range value

UINT nPage ; // page size

int nPos ; // current position

int nTrackPos ; // current tracking position

}

SCROLLINFO, * PSCROLLINFO ;

在程序中,可以定义如下的SCROLLINFO结构类型:SCROLLINFO si;

si.cbSize = sizeof(si);

si.cbSize = sizeof (SCROLLINFO);是一致的

fMask字段以SIZ前缀开头的一个或者多个标志,并可以采用C的位操作OR函数|组合这些标志。

SIFmask——nMin和nMax字段设置为滚动条所需的范围。

SIFPOS——nPos位置所需的位置

SIF_PAGE——获取页面的大小(行数)

fMask标志

含义

SIFmask

nMin和nMax字段设置为滚动条所需的范围。

SIFPOS

nPos位置所需的位置

SIF_PAGE

获取页面的大小(行数)

SIF_TRACKPOS

nTrackPos字段指出当前32位滚动条位置

SIFALL

以上所有参数均要设置

SIF_DISABLENOSCROLL

在程序试图隐藏滚动条时,禁用滚动条

6、Win32两个API函数设置滚动条的范围:

假设窗体大小50行,而NUMLINES等于75

那么滚动范围是从:0——50到25——75

因此可以通过如下参数设定:

si.cbSize = sizeof(SCROLLINFO);

si.cbMask = SIF_RANGE|SIF_PAGE;

si.nMin = 0;

si.nMax = NUMLINES –1;

si.nPage = cyClient/cyChar;

SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

这样设置以后,Windows会把最大滚动条位置限制为si.nMax – si.nPage +1,而不是si.nMax

也就是说:NUMLINES等于25(si.nMax等于74),

si.nPage等于50。于是最大的位置限制为74-50+1=25正是我们所需要的。

当页面大小与滚动条范围一样大的时候,也就是nPage大于等于75的时候,Windows通常就会隐藏滚动条,但是可以通过SIF_DISABLENOSCROLL标志来禁用滚动条而不是隐藏它。

6、ScrollWindow函数:

BOOL ScrollWindow(

HWND hWnd, // handle to window

int XAmount, // horizontal scrolling

int YAmount, // vertical scrolling

CONST RECT *lpRect, // client area

CONST RECT *lpClipRect // clipping rectangle

);

第二个参数指出了水平滚动客户区的数值。

第三个参数指出了垂直滚动客户区的数值,单位都是像素。

最后两个参数设置为NULL,指出了要滚动整个客户区。Windows自动把客户区中未被滚动操作覆盖的矩形设为无效。这样会产生WM_PAINT消息。再也不需要InvalidateRect了。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有