Chinaunix首页 | 论坛 | 博客
  • 博客访问: 767391
  • 博文数量: 171
  • 博客积分: 3629
  • 博客等级: 中校
  • 技术积分: 1779
  • 用 户 组: 普通用户
  • 注册时间: 2005-02-23 21:21
文章分类

全部博文(171)

文章存档

2019年(4)

2018年(7)

2017年(1)

2016年(4)

2014年(1)

2013年(8)

2012年(10)

2011年(50)

2009年(12)

2008年(10)

2006年(56)

2005年(8)

分类: WINDOWS

2006-04-29 14:36:51

相关文章:
WIN32编程/探索Win32系统之窗口类
 
由于这几天看了windows的通用控制,发现一些基本的窗口风格是最基础的.也很有用.正好遇见了上面的文章,所以把相关的列在这儿,做个纪念.
 
控制从本质上来说,是一些定制的窗口.从外观来说,要绘制外形.从消息来说,和父窗口的交互占了很大一部分.因为显示需要精准定位,对于一些复杂的控制如Tab控制,需要一些额外的消息来传递相关信息.
除了定位需要,有些消息还需要父窗口处理,如Tab的WM_NOTIFY(包含的大量notify code).这样说吧,选择了一个标签需要给父窗口通知.以便在父窗口处理,这也是一个控制留给外界的接口.
所以在设计一个控制时,需要什么的交互决定了什么样的消息要传递.如果熟练windows控制的使用,在编程使用控制时不时思考一下使用方法,进行一下换位思考,会容易加深对MSDN的理解.
这就是为什么MSDN已经大而全了为什么还要哪么多的经典著作.没有人拿着字典能学会写作,只在有了一定能力以后才会充分发挥字典的威力.
 
下面有些例子是Tab控制对一些消息的处理方式,从中偶才理解了<控制就是窗口>这句话的实质.
只是MSDN英文居多,偶不翻译了,怕弄巧成拙了.

Default Tab Control Message Processing

This section describes the message processing performed by a tab control. Messages specific to tab controls are discussed in other sections of this documentation.

Message Processing performed
WM_CAPTURECHANGED Does nothing if the tab control released the mouse capture itself. If another window captured the mouse and a button is held down, the command releases the button.
WM_CREATE Allocates and initializes an internal data structure. The control creates a ToolTip control if the TCS_TOOLTIPS style is specified.
WM_DESTROY Frees resources allocated during WM_CREATE processing.
WM_GETDLGCODE Returns a combination of the DLGC_WANTARROWS and DLGC_WANTCHARS values.
WM_GETFONT Returns the handle to the font used for labels.
WM_KEYDOWN Processes direction keys and changes the selection, if appropriate.
WM_KILLFOCUS Invalidates the tab that has the focus so it will be repainted to reflect an unfocused state.
WM_LBUTTONDOWN Forwards the message to the ToolTip control, if any, and changes the selection if the user is clicking a tab. If the user is clicking a button, the control redraws the button to give a sunken appearance and captures the mouse. If the user is clicking either a tab or button and the TCS_FOCUSONBUTTONDOWN style is specified, the control sets the focus to itself.
WM_LBUTTONUP Releases the mouse if a button was pressed. If the cursor is over the button and is being held down, the control changes the selection accordingly and redraws the button.
WM_MOUSEMOVE Forwards the message to the ToolTip control, if any. If the TCS_BUTTONS style is specified and the mouse button is being held down after clicking, the control may also redraw the affected button to give it a raised or sunken appearance.
WM_NOTIFY Forwards notification messages sent by the ToolTip control.
WM_PAINT Draws a border around the display area (unless the TCS_BUTTONS style is specified) and paints any tabs that intersect the invalid rectangle. For each tab, it draws the body of the tab (or sends a WM_DRAWITEM message to the parent window) and then draws a border around the tab. If the wParam parameter is non-NULL, the control assumes that the value is an HDC and paints using that device context.
WM_RBUTTONDOWN Sends an NM_RCLICK notification message to the parent window.
WM_SETFOCUS Invalidates the tab that has the focus so that it will be repainted to reflect a focused state.
WM_SETFONT Sets the font used for labels.
WM_SETREDRAW Sets the state of an internal flag that determines whether the control is repainted when items are inserted and deleted, when the font is changed, and so on.
WM_SIZE

Recalculates the positions of tabs and may invalidate part of the tab control to force repainting of some or all tabs.

 
 
从上面可以看出Tab的设计方法.细节还有很多,不过掌握了全局,细节就容易理解了.
下面是COPY来的,对偶有用.对您呢?看了就知道了.
 
窗口类风格:
Style成员决定了从该类创建出来的窗口的风格,可以使用下列值的一个或几个的组合。
 
CS_BYTEALIGNCLIENT ,CS_BYTEALIGNWINDOW
 
如果使用这两个标志,窗口的的客户区或整个窗口都在“字节边界”上对齐,也就是说,系统调整窗口的水平位置,客户区或整个窗口的左边坐标是8的倍数。win32 SDk的文档说这两个标志影响窗口的宽度,但是实际上笔者没有发现这个现象,此标志只影响窗口的水平位置(左边)。
 
 

CS_OWNDC, CS_CLASSDC, CS_PARENTDC

这几个标志决定窗口的默认DC

  • 如果使用CS_OWNDC标志,属于此窗口类的窗口实例都有自己的DC(称为私有DC),私有DC仅属于该窗口实例,所以程序只需要调用一次GetDCBeginPaint获取DC,系统就为窗口初始化一个DC,并且保存程序对其进行的改变。ReleaseDCEndPaint函数不再需要了,因为其他程序无法访问和改变私有DC。当选择了CS_OWNDC,程序改变影射模式(Mapping Mode)的时候必须小心,当由系统擦除窗口的背景时,系统假定和默认其影射模式是MM_TEXT。如果私有DC的影射模式不一样,窗口被擦除的地方将不再可见。

CS_OWNDC标志在WinNTWin9x的作用也是有差别的。在WinNT,win32子系统和其他NT进程有相同的地址空间(4GB),应用程序使用此地址空间里的2GB,每个有CS_OWNDC标志窗口实例占用800个字节,在NT下,这里面没有什么问题。而Win9xGDI保留了64K的局部堆,DC进入这个堆之后,即使其他GDI对象数据被释放,DC依然在。这意味着每个CS_OWNDC的窗口都在这个宝贵的内存空间里占用800个字节。所以,为win9x写的程序最好尽量少的使用CS_OWNDC这个标志。win9x的修正版打算解决这个问题,但效果不明显(而且win9x已经开始式微了)

如果使用CS_CLASSDC标志,所有属于该类的窗口实例共享相同的DC(称为类DC.DC有一些私有DC的优点,而更加节约内存(因为不需要为每个窗口实例都分配800字节的DC空间了)。每个窗口实例都通过GetDCBeginPaintde得到设备上下文(DC)句柄,如果没有别的窗口需要该DC,不需要调用ReleaseDCEndPaint释放DC。在一个窗口实例上通过GetWindowDC,GetDC,GetDCEx,BeginPaint获得 DC,并对其中的一些参数进行更改的话,所进行的更改除了剪切区域和设备本身属性(Device origin)之外对所有其他窗口实例都是有效的。和CS_OWNDC相同的是,必须确保影射模式也是MM_TEXT,否则,被系统擦除的背景将不再可见。

NT编写的程序最好不要使用这个标志,因为节约内存的好处根本不明显。对于win9x来说,却是有用的,因为对于win9x64KGDI局部堆来说,节约的空间意义更重大一些。

  • 如果使用了CS_PARENTDC标志,属于这个类的窗口都使用它的父窗口的句柄。和CS_CLASSDC相似的是,多个窗口共享一个DC,不同的是,这多个窗口(虽然有父子关系并且共享DC)并不要求都属于同一个窗口类。

WIN9x下,所有的标准窗口控件都有CS_PARENTDC标志。WinNT下,除了ComBoBox之外的窗口控件都有此标志。因此,比如Edit控件和ListBox控件都共享他们的父窗口(比如对话框)的DC

(注:这一段是我根据原文再加上自己的理解,不一定完全正确:) CS_PARENTDC带来的好处就一个字:速度。Win9x系统为每个线程预留了5DC缓冲区,如果一个窗口(比如一个对话框)有多于5个的字窗口(比如有6个或以上的编辑框),而每个子窗口都有自己的DC的话,DC缓冲区就失去了效力,系统得为每个子窗口根据剪切边界和设备属性重新初始化一个DC,这多于5个的DCDC缓冲里不停交换,不能确保在缓冲里被访问。而如果每个子窗口都和父窗口共享一个DC,在频繁访问该DC时,该DC在于DC 缓冲里被找到的几率显然相当的高,从而可以被高速的访问,显著的提高了速度,所以一般来说标准窗口控件都和父窗口共享DCWinNT可以拥有多于5个的DC缓冲,所以它可能可以提供足够的DC缓冲 -- 但是不保证时时如此。

使用CS_PARENTDC的另一个效果是,子窗口可以在父窗口的客户区随意做画,就象画在自己的客户区一样. 负责表现Edit控件和ListBox控件周围的3D效果的CTL3D库就是利用了这个特性。注意如果程序需要改变各子窗口的影射模式,那么最好不要用CS_PARENTDC标志,否则将很容易引起各子窗口影射模式的混乱,因为所有的子窗口都使用同一个DC

  • 如果不指定CS_OWNDCCS_CLASSDCCS_PARENTDC这几个标志,此类的窗口使用一个通用DC,并置于DC缓冲里以供使用。通用DC在使用前获取,使用后释放,在DC获取的时候,DC里的上下文按默认值初始化,除非当时该DC已经在窗口的DC缓冲里(比如没有调用ReleaseDCEndPaint释放DC),这样的话DC的剪切边界和设备属性都不需要被重新初试化,可以节约一些时间。

WinNT里,DC缓冲没有确定的数量。如果所有的DC缓冲都在使用中,而程序调用了GetDCBeginPaint,NT则再分配一个缓冲。

出于对win9x的兼容考虑,win32程序最好把 DC的使用限制在5个以下,并且尽可能快的释放DC.

如果要忽略类创建时由标志位决定的窗口的默认DC,程序可以使用GetDCEx函数,指定DCX_CACHE标志,则完全忽略CS_OWNDCCS_CLASSDC标志,并从缓冲里返回一个通用DC.

ScrollWindowScrollWindowEx函数处理DC的方法则有所不同:

  • ScrollWindow使用窗口默认的DC。因此,如果窗口使用CS_OWNDCCS_CLASSDC标志,ScrollWindow使用相应的DC(窗口私有DC或类DC,其影射模式有可能被程序改变,不为MM_TEXT.传递给ScrollWindow的坐标值必须和DC的影射模式相一致。

  • ScrollWindowEx使用系统通用DC(这种DC使用MM_TEXT的影射模式),而忽略窗口的标志。传递给ScrollWindowEx的坐标值必须是MM_TEXT影射模式下的客户区坐标值。

补充一些:
 
Tree View与ImageList是配合使用的.
ImageList是一堆ImageList_*之类的API组成的.一般需要一个image资源句柄.先创建,再添加资源.
创建时可以指定资源长,宽,初始imagelist数量,最大imagelist数量.
添加资源后有一个 
ImageList_SetOverlayImage
是可选的.用于指定overlay image.指imagelist可以覆盖TreeView项的图标.不过这是可选的.
ImageList里面可有多个Image,以0开始索引.每个Image里的多个图标也以0开始索引.
 
TreeView每个节点对应一个结构,TVITEMEX/TVITEM,修改TreeView外观其实就是修改这个结构.这个结构里关于image的部分和上面的ImageList结合紧密.需要理解一点图像索引的问题:
如果使用overlay image和 state image的话,ImageList里面的第一个索引为0的Image不能使用,知道这就可以了,如果不使用它们,当我不说.
 
 
阅读(3063) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~