您的位置:首页 > 编程语言

windows基础应用程序编程(八)控件简介(一)

2014-09-29 17:38 579 查看
至今为止,我们的程序都是建立在一个窗口类,一个窗口回调函数的基础上的。但是我们的程序往往不止一个窗口,我们在程序中有着多个窗口。多个按钮等(按钮也是窗口,之后解释)。那么,如果要生成多个窗口,我们可能就需要不止一个窗口回调函数,下面我们首先来介绍一下子窗口的概念,之后,再来了解windows系统为我们提供的一些控件窗口的使用。

子窗口

我们在程序中,往往需要多个窗口。这些窗口把客户区划分成多个逻辑区域。每个子窗口都有自己的窗口句柄。窗口过程和客户区。每个窗口过程接受只适用于它的子窗口鼠标消息。使用子窗口能够有助于我们程序的结构化和模块化。不同的窗口可以使用不同的窗口类。下面我们首先演示一下,如何手动的去创建一个子窗口。
假设我们建立四个子窗口,每个子窗口都响应鼠标左键单击消息,当单击下左键,程序将在子窗口绘制一个黑色的实心圆。
我们首先声明子窗口处理函数,如下所示:
[align=left]LRESULT CALLBACK ChildProc(HWND, UINT, WPARAM, LPARAM);[/align]
[align=left]之后,如果我们想要生成一个窗口,根据第一篇文章可知,我们应该首先注册一个窗口类,然后才能去创建它,如下所示:[/align]

if( !RegisterClassEx(&wcex) )
{
MessageBox( NULL, TEXT( "ERROR"), TEXT("ERROR" ), MB_ICONERROR );
}

wcex.lpfnWndProc = ChildProc;
wcex.hIcon = NULL;
wcex.lpszClassName = TEXT( "ChildWindow");
wcex.cbWndExtra = sizeof(long );

if( !RegisterClassEx(&wcex) )
{
MessageBox( NULL, TEXT( "ERROR"), TEXT("ERROR" ), MB_ICONERROR );
}


第一次注册的窗口类是我们的父窗口,第二次注册的窗口类是我们子窗口。其中父窗口的窗口回调函数如下所示:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND HChildWnd[2][2];
int x, y;
int cxSize, cySize, cxBlock, cyBlock;

switch( message )
{
case WM_CREATE:
for( x = 0; x < 2; x ++ )
for( y = 0; y < 2; y ++ )
{
HChildWnd[x][y] = CreateWindow(TEXT("ChildWindow" ), NULL,
WS_CHILDWINDOW | WS_VISIBLE, 0, 0, 0, 0, hWnd, (HMENU)(y << 8 | x), hInst, NULL );
}
return 0;

case WM_SIZE:
cxSize = LOWORD(lParam);
cySize = HIWORD(lParam);

cxBlock = cxSize / 2;
cyBlock = cySize / 2;

for( x = 0; x < 2; x ++ )
for( y = 0; y < 2; y ++ )
{
MoveWindow( HChildWnd[x][y], x * cxBlock, y * cyBlock, cxBlock, cyBlock, TRUE );
}
return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}


我们可以很清楚的看到,在父窗口中,我们在WM_CREATE中去创建4个子窗口,并返回对应子窗口的句柄到HChildWnd数组中,并在WM_SIZE消息处理中利用MoveWindow函数去调整子窗口的大小。我们在注册子窗口时,窗口类的lpfnWndProc字段时就指定了ChildProc函数。故在我们的父窗口的WM_CREATE消息中创建子窗口,会向子窗口发送一个WM_CREATE消息。我们来看一下子窗口的窗口回调函数。
LRESULT CALLBACK ChildProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
RECT ClientRect;

switch( message )
{
case WM_CREATE:
SetWindowLong( hWnd, 0, 0 );
return 0;

case WM_LBUTTONDOWN:
SetWindowLong( hWnd, 0, GetWindowLong( hWnd, 0 ) == 0 ? 1 : 0 );
InvalidateRect( hWnd, NULL, FALSE );
return 0;

case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );

GetClientRect( hWnd, &ClientRect );
Rectangle( hdc, 0, 0, ClientRect.right, ClientRect.bottom );

if( GetWindowLong( hWnd, 0 ) )
{
HBRUSH OldBrush = (HBRUSH)SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
Ellipse( hdc, 0, 0, ClientRect.right, ClientRect.bottom );
DeleteObject( SelectObject( hdc, GetStockObject(WHITE_BRUSH) ) );
}
EndPaint( hWnd, &ps );
return 0;

}
return DefWindowProc( hWnd, message, wParam, lParam );
}


[align=left]值得说一下的是,我们在窗口类中使用了cbWndExtra字段,来存储一个Long类型的数据用来标识是否需要画椭圆。我们用SetWindowLong和GetWindLong两个函数来分别设置和获得这个值。[/align]

静态类

[align=left]在上面我们是自己建立了子窗口的控制,但是我们也可以利用一些预定义的窗口类,来建立标准的子窗口控制。我们在CreateWindow函数中指定窗口类为“static”,就可以建立静态的子窗口控制,一般这个窗口既不接受鼠标和键盘输入,也不向父窗口发送WM_COMMAND消息。我们一般只是用它来显示一些提示信息。[/align]

按钮类

[align=left]按钮在程序中的作用,大家都不会陌生,下面我们用程序来演示几个常用的按钮。[/align]
[align=left]我们首先定义一个结构体,并声明了一个button结构数组。[/align]

struct
{
int iStyle;
TCHAR * szText;
}
button[] =
{
BS_PUSHBUTTON,                            TEXT( "PUSHBUTTON"),
BS_DEFPUSHBUTTON,    TEXT( "DEFPUSHBUTTON"),
BS_CHECKBOX,                                                 TEXT( "CHECKBOX"),
BS_AUTOCHECKBOX,     TEXT( "AUTOCHECKBOX"),
BS_RADIOBUTTON,                         TEXT( "RDIOBUTTON"),
BS_3STATE,                                                                        TEXT( "3STATE"),
BS_AUTO3STATE,                                            TEXT( "AUTO3STATE"),
BS_GROUPBOX,                                 TEXT( "GROUPBOX"),
BS_AUTORADIOBUTTON,             TEXT( "AUTORADIO"),
BS_OWNERDRAW,                           TEXT( "OWNERDRAW")
};

#define                   NUM       sizeof(button) / sizeof ( button[0] )

之后,我们处理在父窗口中处理WM_CREATE消息,如下所示:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndButton[NUM];
static int cxChar, cyChar;
int i;

switch( message )
{
case WM_CREATE:
cxChar = LOWORD(GetDialogBaseUnits());
cyChar = HIWORD(GetDialogBaseUnits());

for( i = 0; i < NUM; i ++ )
{
hwndButton[i] = CreateWindow( TEXT("button" ), button[i].szText,
WS_CHILD | WS_VISIBLE | button[i].iStyle,
cxChar, cyChar * ( 1 + 2 * i ),
20 * cxChar, 7 * cyChar / 4,
hWnd, (HMENU)i,
hInst, NULL );
}

return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}


[align=left]在我们的程序中,定义了一个叫做button的结构,它包括了按钮窗口风格和描述性文本串,它们对应于10个按钮类型,所有的按钮窗口风格都以字母‘BS’开头,是button style的缩写,即按钮风格。值得注意的是,我们使用GetDialogBaseUnits函数来获得默认字体字符的宽度和高度。此函数返回一个32位的值,其中低字表示宽度,高字表示高度。[/align]
[align=left]之后,我们编译运行程序,可以看到在窗口中我们的程序中显示了如下所示的几个按钮(可以比较一下不同风格的按钮的显示样式)。[/align]



[align=left]现在,我们已经能显示出按钮了,那么我们怎么来响应按钮呢,其实我们的子窗口(这里指按钮)可以向父窗口发送消息,当然父窗口也可以向子窗口发送消息。当我们单击按钮时,子窗口就会向父窗口发送一个WM_COMMAND消息,(菜单响应也是这个消息哦),其中wParam的低字表示子窗口的ID,高字表示通知码,lParam表示子窗口句柄。ID是我们创建子窗口时,传递给CreateWindow的值,即上例中的(HMENU)i。窗口句柄即调用CreateWindow成功后返回的值。关于通知码我们只需要简单的了解其中常用的两三个即可。如下所示:[/align]
[align=left]BN_CLICKED(0) BN_DBLCLK (5) BN_SETFOCUS (6) BN_KILLFOCUS(7)。[/align]

下压按钮

[align=left]在上图显示的前两个按钮是‘下压’按钮。按钮是一个矩形,包括了CreateWindow调用窗口文本参数所指定的文本。这两类按钮的作用相同,只是BS_DEFPUSHBUTTON的边框要粗一点。[/align]

复选框

[align=left]复选框是一个文本框,文本通常出现在复选框的右边。复选框常用的风格时BS_CHECKBOX和BS_AUTOCHECKBOX。在使用BS_CHECKBOX时,我们需要自己想该控制发送BM_SETCHECK消息来设置复选标记。而BS_AUTOCHECKBOX风格的按钮,将自己出发复选标记的开关。还有两种复选框的风格时BS_3STATE和BS_AUTO3STATE,这两种按钮风格可以显示3中状态,即复选框内是灰色,灰色表示此复选框不能被选中或者是禁用的。[/align]

单选按钮

[align=left]单选按钮的形状是一个圆圈,而不是方框,除此之外和复选框类似。常用风格有BS_RADIOBUTTON和BS_AUTORADIOBUTTON两种。[/align]

分组框

[align=left]一般不处理鼠标和键盘消息,常用了包含其他的按钮控制。风格为BS_GROUPBOX[/align]

自绘按钮

[align=left]如名所示,我们可以自己来绘制窗口的风格。使用BS_OWNERDRWA风格建立的按钮会在需要重新着色的任何时候都向它的父窗口发送一个WM_DRAWITEM消息。我们绘制按钮,需要捕获这个消息。[/align]
[align=left]关于按钮就简单的介绍这么多,至于使用,将在以后需要的时候穿插介绍。[/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: