第八章 子窗体控件

  图形界面和消息处理是任何一个基于Windows的应用程序必须认真考虑的事情。在前面的章节中已经介绍了Windows应用程序消息处理的机制,这种机制对于所有对象的消息处理都是一致的,即实行客户(用户操作或请求)到操作系统(捕获消息)到应用程序(接收消息并执行处理代码)的机制。而图形界面则包含丰富的内容,主要是指各种各样的控件,不仅包括前面章节中介绍的主窗口,还包括按钮、编辑框、滚动条等具有窗口风格的子窗口。丰富的图形界面元素为建立界面友好的应用程序提供了可能,而完整的消息处理机制则为应用程序的功能提供了高效集成的保证。

概述

子窗口的概念包含两方面的含义:
  从创建子窗口的过程来看,Createwindow函数为创建各类窗口提供了统一的函数,并且子窗口的类型唯一由第一个参数确定;从窗口的界面风格来看,这些子窗口都拥有窗口的许多性质。
  设计含有子窗口的程序都从调用函数 CreateWindow开始,它一共有 11个参数,指定待创建的子窗口的类型、标题、风格等非常重要的性质。
CreateWindow函数的原型定义如下:
HWND CreateWindow(LPCTSTR lpClassName, // 指定子窗口的类名
         LPCTSTR lPWindowName, // 指定窗口名称
         DWORD dwSty1e, // 指定窗口风格
         int x, // 指定窗口左上角顶点的水平坐标
         int y, // 指定窗口左上角顶点的垂直坐标
         int nWidth, // 指定窗口宽度
         int nHeight, // 指定窗口高度
         HWND hWndParent, //父窗口句柄,允许为NULL
         HMENU hMenu, //窗口的菜单句柄或者是子窗口自己的标识符
         HANDLE hInstance, //应用程序句柄,可以为NULL
         LPVOID lpParam //指向lParam数值的指针);
  当子窗口创建成功后,返回子窗口的句柄,否则返回NULL。在11个参数中 lpClassName、dwStyle和hMenu是三个最重要的参数。下面分别讲述它们的意义。 lpClassName指定子窗口的类名,它们的取值可以是如表所示的值。

子窗口类型
类名
描述
按钮 Button 创建按键按钮、单选按钮和三态按钮。
静态文本框 Static 显示用户不可直接编辑的文本,一般为标题。
滚动条 ScrollBar 滚动视图。
列表框 ListBox 显示具有多个子项的列表框。
编辑框 Edit 允许用户直接编辑文本。
组合框 ComboBox 与列表框类似,但多一个编辑区域。
多文档客户窗口 MDICLIENT 创建多文档应用程序的客户窗口。

  dwStyle指定子窗口的风格。这里只讲述一般窗口的风格,表所列的子窗口的风格在后面内容中分别讲述。一般窗口的风格取值如表所示。

取值
效果
WS_BORDER 创建一个带有窄边框的了窗口。
WS_CAPTION 创建一个带有标题栏的子窗口,包含了WS_BORDER。
WS_CHILD 创建子窗口,必须指定,并且不能与WS_POPUP同时使用。
WS_CHILDWINDOW 同WS_CHILD。
WS_CLIPCHILDREN 适用于父窗口,不会被子窗口覆盖。
WS_DISABLED 创建一个禁活的窗口,不接收用户的输入信息。
WS_DLGFRAME 创建一个对话框风格的窗口,并且不能与WS_CAPTION同用。
WS_GROUP 允许用户通过Tab键在子窗口之间切换。
WS_HSCROLL 创建带水平滚动条的了窗口。
WS_ICONIC 创建最小化的子窗口。
WS_MAXIMIZE 创建最大化的子窗口。
WS_MAXIMIZEBOX

创建具有最大按钮的子窗口。

WS_MINIMIZE 同WS_ICONIC。
WS_MINIMIZEBOX 创建最小按钮的子窗口。
WS_SIZEBOX 创建可缩放边框的子窗口。
WS_SYSMENU 使子窗口有系统菜单。
WS_TABSTOP 指定用户第一次接下Tab键时输入焦点所属的子窗口。
WS_THICKFRAME 同WS_SIZEBOX。
WS_VISIBLE 创建初始化可视的窗口。
WS_VSCROLL 使窗口具有垂直滚动条。

  参数hMenu指定菜单句柄或者子窗口的标识符。例如,已建立的菜单资源标识符为IDM_MENU, 窗口需要加载该菜单,则 hMenu参数可为 IDM_NENU子窗口的标识符可以是字符或者数字,但同一个应用程序中不同子窗口的  标识符必须相异,并且前面加上(hMENU)来满足参数类型兼容的要求。
  应用程序运行后,首先创建主窗口,并发送WM_CREATE消息,由于在该消息的处理代码中含有创建子窗口的代码,于是就创建了子窗口。当子窗口的WS_VISIBLE风格指定后,子窗口就显示出来。
  同前所讲的消息处理机制类似,子窗口的消息也主要依靠参数lParam和wParam来完成。
  应用程序创建子窗口后,在主窗口的消息处理函数中一般使用SendMessase向子窗口发送消息。当用户对子窗口进行某种操作后,将向父窗口发送WM_COMMAND类型的通知消息。其中,lParam包含子窗口的句柄;wParam参数的高位字节为通知代码,低位子代表子窗口的标识符。
  下面将分别讲述各种子窗口的特有风格以及消息循环,并结合实例介绍子窗口的应用。
一、Button子窗口
  Button(按钮)是Windows子窗口的最常用的元素之一。例如安装程序中选择Next或者Back按钮。
1. 按钮类型
  依据操作的类型可以把按钮分为按键按钮、单选按钮、复选按钮,另外还有存放单选按钮和复选按钮的按钮组合框(GroupBox)。
  按键按钮一般执行某项功能,例如弹出新的窗口。在创建子窗口的函数中,如果需要创建按键按钮,则dwStyle参数指定为BS_PUSHBUTTON。
  当某些选择相互排斥时,需要用到单选按钮,例如字体或者颜色。单选按钮的左端为一个圆圈,选中单选按钮,则显示实心,相反为空心圆。在同一个按钮组合框里的众多单选按钮中,用户只能选择一个。如果需要单选按钮,则dwStyle 参数必须指定为BS_RADIOBUTTON。
  当某些选择可以相互并存时,需要用到复选按钮。复选按钮的风格与单选按钮类似,左端为圆圈或者小空心正方形。在同一个按钮组合框里的复选按钮可以同时被选中几个。如果需要创建,则dwStyle参数设置为BS_CHECKBOX。
  在复选按钮中还有一类特殊的按钮,即三态按钮。顾名思义,三态按钮允许有三种状态:选中(Selected)、本选中(Unselected)、显灰(Grayed)。三态按钮在需要把单选按钮和复选按钮放在同一个组合框里时才有应用的价值,若要创建三态按钮,则把dwStyle参数设置为BS_3STATE。
按钮的风格取值如表所示。

按钮风格
描述
BS_AUTOCHECKBOX 创建一个自动选中的复选按钮,只有复选按钮在复选框里改设置值才起作用。
BS_AUTORADIOBUTTON 创建一个自动选中的单选按钮。
BS_AUTO3STATE 创建自动的三态按钮。
BS_CHECKBOX 创建一个复选按钮。
BS_DEFPUSHBUTTON 创建默认选中的按键按钮,当用户按下Enter键时,则表示选择该按键按钮。
BS_GROUPBOX 创建按钮组合框,当创建一组单选按钮或者复选按钮时,首先需要创建该按钮组合框。
BS_LEFTTEXT 创建单选按钮或复选按钮时,指定按钮名称的文本出现在左边。
BS_OWNERDRAW 创建自画按钮,必须先创建图形资源。
BS_PUSHBUTTON 创建按键按钮。
BS_RADIOBUTTON 创建单选按钮。
BS_3STATE 创建三态按钮

  按钮有自己特殊的消息类型。当用户选择了按钮时,它将向父窗口发送WM_COMMAND消息,这些通知消息包含在wParam的高位字节中。按钮的通知代码如表所示。

通知代码
描述
BN_CLICKED 表示用户单击丁该按钮
BN_DOUBLECLICKED 表示用户双击了该按钮
BN_HILITE 表示按钮显亮
BN_UNHlLlTE 取消按钮显亮
BN_PAINT 绘制按钮
BN_DISABLE 表示按钮禁活
BN_PUSHED 用户选中该按钮并按下了Enter键
BN_SETFOCUS 输入焦点转移到该按钮

2.Button子窗口的创建和使用示例
#include <windows.h>
Struct //定义按钮的风格和显示文本
{
  long style ;
  char *text ;
}
button[] = //定义9类按钮
{
  BS_PUSHBUTTON, "按键按钮",
  BS_DEFPUSHBUTTON, "默认按键按钮",
  BS_CHECKBOX, "检查按钮",
  BS_AUTOCHECKBOX, "自动检查按钮",
  BS_GROUPBOX, "复选框",
  BS_3STATE, "检查按钮",
  BS_AUTO3STATE, "三状态自动检查按钮",
  BS_AUTORADIOBUTTON, "自动圆按钮",
  BS_RADIOBUTTON, "圆按钮",
};
//取得按钮的数目
#define NUM (sizeof button/sizeof button[0])
//定义应用程序的名字
static char szAppName[] = "BtnLook" ;
//预先声明消息处理、窗口类申请和初始化函数
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
//函数:WinMain
//作用:主应用函数
int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
{
  MSG msg ;
  //申请窗口类
  MyRegisterClass(hInstance);
  //应用程序的初始化
  if(!InitInstance(hInstance,iCmdShow))
  {
    return FALSE;
  }

  while (GetMessage (&msg, NULL, 0, 0))
  {
    TranslateMessage (&msg) ;
    DispatchMessage (&msg) ;
  }
  return msg.wParam ;
}
//函数:MyRegisterClass
//作用:注册窗口类
ATOM MyRegisterClass(HINSTANCE hInstance)
{
  WNDCLASSEX wndclass ;
  wndclass.cbSize = sizeof (wndclass) ;
  wndclass.style = CS_HREDRAW | CS_VREDRAW ;
  wndclass.lpfnWndProc = WndProc ;
  wndclass.cbClsExtra = 0 ;
  wndclass.cbWndExtra = 0 ;
  wndclass.hInstance = hInstance ;
  wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
  wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
  wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  wndclass.lpszMenuName = NULL ;
  wndclass.lpszClassName = szAppName ;
  return RegisterClassEx (&wndclass) ;
}
  //函数:InitInstance
  //作用:初始化应用程序
BOOL InitInstance(HINSTANCE hInstance,int nCmdShow)
{
  HWND hwnd ;
  hwnd = CreateWindow(szAppName, "按钮设计",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL, NULL, hInstance, NULL) ;
  if(!hwnd)return FALSE;
  ShowWindow (hwnd, nCmdShow) ;
  UpdateWindow (hwnd) ;
  return TRUE;
}
//函数:WndProc
//作用:消息处理函数
LRESULT CALLBACK WndProc (HWND hwnd,UINT iMsg, WPARAM wParam,LPARAM lParam)
{//窗口上显示提示信息
  static char szTop[]="消息 参数wParam 参数lParam",
            szUnd[] = "____ ______ ______",
            szFormat[] = "%-16s%04X-%04X %04X-%04X",
            szBuffer[50] ;
  //定义需要建立的按钮
  static HWND hwndButton[NUM] ;
  static RECT rect ;
  static int cxChar, cyChar ;
  HDC hdc ;
  PAINTSTRUCT ps ;
  int i ;
  TEXTMETRIC tm ;
  switch (iMsg)
  {
    case WM_CREATE :
    //取得图形设备描述表的句柄
    hdc = GetDC (hwnd) ;
    SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
    GetTextMetrics (hdc, &tm) ;
    cxChar = tm.tmAveCharWidth ;
    cyChar = tm.tmHeight + tm.tmExternalLeading ;
    ReleaseDC (hwnd, hdc) ;
    //创建按钮
    for (i = 0 ; i < NUM ; i++)
    hwndButton[i] = CreateWindow("button",
                   button[i].text,
                   WS_CHILD|WS_VISIBLE|button[i].style,
                   cxChar,cyChar * (6+ 2 * i), 22 * cxChar,
                   7 * cyChar / 4,
                   hwnd,
                   (HMENU) i,
                   ((LPCREATESTRUCT) lParam) -> hInstance,
                   NULL) ;
    return 0 ;
    //取得文本显示区域的大小

    case WM_SIZE :rect.left = 24 * cxChar ;
    rect.top = 2 * cyChar ;
    rect.right = LOWORD (lParam) ;
    rect.bottom = HIWORD (lParam) ;
    return 0 ;
    //重画文本

    case WM_PAINT :InvalidateRect (hwnd, &rect, TRUE) ;
    hdc = BeginPaint (hwnd, &ps) ;
    SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
    SetBkMode (hdc, TRANSPARENT) ;
    //输出文本头
    TextOut(hdc, 24 * cxChar, cyChar, szTop, sizeof (szTop) - 1) ;
    TextOut(hdc, 24 * cxChar, cyChar, szUnd, sizeof (szUnd) - 1);
    EndPaint (hwnd, &ps) ;
    return 0 ;

    case WM_DRAWITEM :

    case WM_COMMAND :
    ScrollWindow (hwnd, 0, -cyChar, &rect, &rect) ;
    hdc = GetDC (hwnd) ;
    SelectObject(hdc, GetStockObject (SYSTEM_FIXED_FONT));
    //输出新的消息
    TextOut(hdc,24 * cxChar,
        cyChar * (rect.bottom / cyChar - 1),
        szBuffer,wsprintf(szBuffer,
        szFormat,
        iMsg == WM_DRAWITEM?"WM_DRAWITEM" : "WM_COMMAND",
        (int)(wParam), (int)(wParam),
        HIWORD(lParam), LOWORD(lParam))) ;
    //释放图形设备资源
    ReleaseDC (hwnd, hdc) ;
    //重新描绘客户区域
    ValidateRect (hwnd, &rect) ;
    //弹出消息对话框
    switch(LOWORD(wParam))
    {
      case 0:
      case 1:
      case 2:
      case 3:
      MessageBox(hwnd,"Good","Yes",MB_OKCANCEL);
      break ;
      //推出应用程序
      case WM_DESTROY :
      PostQuitMessage (0) ;
      return 0 ;
    }
    return DefWindowProc(hwnd, iMsg, wParam, lParam) ;
  }
}
  本应用程序主要创建各种各样的按钮,并把有关按钮的高位、低位字节信息显示出来。程序首先定了一个记录按钮风格和名称的结构体变量类型,然后定义按钮的结构体变量数组,代码如下: // 定义按钮的风格和显示文本
Struct{
  long style;
  char*text;
}
button[]//定义 9类按钮
{
  BS_PUSHBUTTON, “按键按钮”,
  BS_DEFPUSHBUTTON,“默认按键按钮”,
  BS_CHECKBOX “检查按钮”,
  BS_AUTOCHECAnOX “自动检查按钮”,
  BS_GROUPBOX “复选框”,
  BS_3STATE “检查按钮”,
  BS_AUTO3STATE,“三状态自动检查按钮”,
  BS_AUTORADIOBUTTON “自动圆按钮”,
  BS_RADIOBUTTON, “圆按钮”
};
  这样定义的好处是便于程序在调用CreateWindow函数时可以方便地通过for循环语句取得按钮风格值,从而大大精简了代码。
  在CreateWindow函数中,参数hMenu的值为(HMENU)i,这里i代表按钮的标识符,在消息循环处理函数中可以通过i来访问按钮,代码如下:
switch(LOWORD(wParam))
  case 0:
  case l:
  case 2:
  case 3:
MessageBox(hWnd”Good”,”Yes”,MB_OKCANCEL);
程序编译、运行后,结果如图所示。

  按下任意按钮,将显示按钮的有关信息。图中WM_COMMAND表示按下按钮发给主窗口的消息类型是WM_COMMAND,按下按钮的结果如图所示。

编辑框

  编辑框的主要作用是让用户输入文本,例如要求用户在编辑框中输入密码的文本。
1.基础知识
  编辑框里的文本可以是单行,也可以是多行,后者的风格取值为 ES_MULTILINE。一般对于多行文本编辑框还需设置 ES_AUTOVSCROLL,这样用户可以输入多行文本,并自动滚动。在默认的状况下,编辑框是没有边框的,如果需要边框,设置WS_BORDER即可。另外还可规定编辑框里的文本是否只读,风格属性设置为ES_READONLY。当需要建立密码编辑框时,只要设置ES_PASSWORD风格属性即可。
编辑框的全部风格如表所示。

风格取值
描述
ES_AUTOHSCROLL 自动增加水平滚动条
ES_AUTOVSCROLL 当按下Enter键后,自动切换到下一页
ES_CENTER 文本居中
ES_LEFT 文本左对齐
ES_LOWERCASE 把所有的字母都小写
ES_MULTILINE 建立多行文本编辑框
ES_NOHIDESEL 当失去输入焦点时,选中的文本将隐藏
ES_OEMCONVERT 把输入的文本从ANSI码转换成OEM码,然后又转换成ANSI码,这样的目的是保证函数AnsiToOem的正确调用
ES_PASSWORD 控制编辑框作为密码文本框的字符形式
ES_RIGHT 文本右对齐
ES_UPPERCASE 将所有的字符转换成大写字符
ES_READONLY 文本只读

  Windows系统把编辑框的操作以 WM_COMMAND的形式发送给父窗口。消息的有关信息仍然包含在参数wParam和IParam中。wParam的低位字节包含编辑框的标识符,高位字节包含通知消息的类型,lParam包含编辑框的句柄。编辑框的通知消息如表所示。

消息取值
作用
EM_CANUNDO 检验编辑框是否可以执行取消操作
EM_GETHANDLE 得到内存区文本的句柄,不适用于单行文本编辑框
EM_GETLIMITTEXT 得到文本限制的信息
EM_GETLINE 把指定行文本拷贝到字符串指针中
EM_GETLINECOUNT 得到编辑框的行的数目
EM_GETMARGINS 得到编辑框的边框宽度
EM_GETMODIFY 确认编辑框是否被修改
EM_GETPASSWORDCHAR 得到密码编辑框设置的密码字符
EM_GETRECT 得到文本矩形区域
EM_GETSEL 得到选中的文本
EM_GETTHUMB 得到编辑框滚动条的位置
EM_GETWORDBREAKPROC 得到折行函数的地址
EM_LIMITTEXT 设置用户能够输入的字符数目
EM_LINEINDEX 得到字符所在的行序号
EM_LINELENGTH 得到行的长度
EM_LINESCROLL 使文本滚动
EM_SCROLL 在多行编辑框中垂直滚动文本
EM_SCROLLCARET 把插入符移到编辑框的可见区
EM_SETHANDLE 给文本内存缓冲区设置句柄
EM_SETPASSWORDCHAR 设置密码字符
EM_SETTABSTOPS 在多行编辑框里设置制表符停止位置,但单行编辑框没有该消息
EM_UNDO 取消上一次操作
EN_CHANGE 发送编辑框改变的消息
EN_ERRSPACE 当文本内存不够时,发送该消息
EN_KILLFOCUS 当编辑框失去输入焦点时发送该消息
EN_MAXTEXT 当输入的文本超过最大允许数目时发送该消息
EN_SETFOCUS 设置输入焦点
EN_UPDATE 当编辑框被改变时发送该消息,与EN CHANGE不同,它在编辑框重画前发送
WM_COPY 拷贝消息
WM_CTLCOLOREDIT 只读编辑框重画时向父窗口发送该消息
WM_CUT 剪切消息
WM_PASTE 粘贴消息
WM_UNDO 取消上一次操作消息

  在默认的情况下,当用户用鼠标右击后自动弹出菜单,形式如图3所示。

2.应用程序举例编辑框应用程序:
#include <windows.h>
#include "resource.h"
//定义应用程序的名字
char szAppName[] = "Edit Note";
//预先申明消息处理、注册窗口类以及应用程序初始化的函数
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
BOOL APIENTRY DlgProc (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
{
  MSG msg ;//注册窗口类
  MyRegisterClass(hInstance);//应用程序的初始化
  if(!DialogBox(hInstance,"IDD_DIALOG1",NULL,(DLGPROC)DlgProc))
  {
    MessageBox(NULL,"Sorry","Password Check",MB_OKCANCEL);
    return FALSE;
  }

  if(!InitInstance(hInstance,iCmdShow))
  {
    return FALSE;
  }

  while (GetMessage (&msg, NULL, 0, 0))
  {
    TranslateMessage (&msg) ;
    DispatchMessage (&msg) ;
  }
  return msg.wParam ;
}
//详细定义申请窗口类的函数
ATOM MyRegisterClass(HINSTANCE hInstance)
{
  WNDCLASSEX wndclass ;
  wndclass.cbSize = sizeof (wndclass) ;
  wndclass.style = CS_HREDRAW | CS_VREDRAW ;
  wndclass.lpfnWndProc = WndProc ;
  wndclass.cbClsExtra = 0 ;
  wndclass.cbWndExtra = 0 ;
  wndclass.hInstance = hInstance ;
  wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
  wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
  wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  wndclass.lpszMenuName = "IDR_MENU1";
  wndclass.lpszClassName = szAppName ;
  wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;
  return RegisterClassEx (&wndclass) ;
}
//详细定义初始化应用程序的函数
BOOL InitInstance(HINSTANCE hInstance,int nCmdShow)
{
  HWND hwnd ;
  hwnd = CreateWindow (szAppName,
             "编辑框设计",WS_OVERLAPPEDWINDOW,
             CW_USEDEFAULT, CW_USEDEFAULT,
             CW_USEDEFAULT, CW_USEDEFAULT,
             NULL, NULL, hInstance, NULL) ;
  if(!hwnd)
  {
    return FALSE;
  }
  ShowWindow (hwnd, nCmdShow) ;
  UpdateWindow (hwnd) ;
  return TRUE;
}
BOOL APIENTRY DlgProc (HWND hwnd,UINT iMsg, WPARAM wParam,LPARAM lParam)
{
  int i;
  BOOL truth=TRUE;
  //标志密码是否输入正确
  char ss[]="55555"; //定义密码文本
  //设置密码符号,本例中设置为"@"
  SendDlgItemMessage(hwnd,IDC_EDIT1,EM_SETPASSWORDCHAR,(WPARAM)'@',(LPARAM)0);
  //设置密码文本字符的数目,本例中设置为5
  SendDlgItemMessage(hwnd,IDC_EDIT1, EM_SETLIMITTEXT,(WPARAM)5,(LPARAM)0);

  switch(iMsg)
  {
    case WM_COMMAND:
    //取出编辑框里的文本
    SendDlgItemMessage(hwnd,IDC_EDIT1,EM_GETLINE,(WPARAM)0,(LPARAM)ss);
    switch(LOWORD(wParam))
    {//如果用户选择OK按钮,则判断密码是否正确
    case IDOK:
    MessageBox(NULL,ss,ss,MB_OKCANCEL);
    for(i=0;i<5;i++)
    {
      if(ss[i]!='1')
      {
        truth=FALSE;//密码不对,则标志为FALSE;
        break;
      }

      if(truth==TRUE)
      {
        EndDialog(hwnd,TRUE);//结束对话框
        return TRUE;
      }

      EndDialog(hwnd,FALSE);
      case IDCANCEL:
      //如果选择Cancel按钮,直接结束对话框
      EndDialog(hwnd,FALSE);
      return TRUE;
      default:
      return FALSE;
    }
  }
  return FALSE;
}
//函数:WndProc
//作用:消息处理
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg,WPARAM wParam,LPARAM lParam)
{
  //定义编辑框句柄
  static HWND hwndEdit ;
  switch (iMsg)
  {//定义创建窗口的事件
    case WM_CREATE :
    //创建编辑框,其中第一个参数"edit"定义了创建的窗口是编辑框
    hwndEdit = CreateWindow("edit", NULL,
                WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |WS_BORDER
                | ES_LEFT | ES_MULTILINE |ES_AUTOHSCROLL | ES_AUTOVSCROLL,
                0, 0, 0, 0,
                hwnd, (HMENU) 1,
                ((LPCREATESTRUCT) lParam) -> hInstance, NULL) ;
    return 0 ;
    //设定输入焦点

    case WM_SETFOCUS :
    SetFocus (hwndEdit) ;
    return 0 ;
    //移动窗口

    case WM_SIZE :
    MoveWindow(hwndEdit,0,0,LOWORD(lParam),HIWORD(lParam),TRUE) ;
    return 0 ;
    //定义消息处理函数

    case WM_COMMAND :
    if (LOWORD (wParam) == 1)
      if (HIWORD (wParam) == EN_ERRSPACE || HIWORD (wParam) == EN_MAXTEXT)
        MessageBox(hwnd, "Edit control out of space.",szAppName, MB_OK | MB_ICONSTOP);
    return 0 ;
    //退出应用程序

    case WM_DESTROY:
    PostQuitMessage (0) ;
    return 0 ;
  }
  return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}
  本程序的主要功能是实现密码设置,当用户输入的密码正确后才能进入应用程序的主界面,相反只能重新输入。该应用程序首先建立对话框资源,标识符为IDD_DIALOGI。然后在主应用程序中显示该对话框(密码对话框),代码如下:
if(!DialogBox(hInstance,"IDD_DIALOG1", NULL,(DLGPROC)DlgProc))
{
  MessageBox(NULL,"Sorry","Password Check",MB_OKCANCEL);
  return FALSE;
}
  程序通过DialogBox函数显示已经创建的对话框,当输入的密码不对时,则弹出出错消息,并退出应用程序。上述代码指定了对话框自身的消息处理函数DlgProc,它的定义形式与主窗口消息处理函数一样,其作用主要用来判断密码输入是否正确。
  在WinProc函数中首先把编辑框设置为密码编辑框,符号为“@”,然后设置密码的最大输入字符,代码如下:
SendDlgItemMessage(hwnd,IDC_EDIT1,EM_SETPASSWORDCHAR,(WPARAM)'@',(LPARAM)0);
//设置密码文本字符的数目,本例中设置为5
SendDlgItemMessage(hwnd,IDC_EDIT1,EM_SETLIMITTEXT,(WPARAM)5,(LPARAM)0);
  接着程序判断当前用户按下的按钮,如果是Cancel按钮,就直接返回FALSE;如果是OK按钮被按下,消息处理函数立即判断密码是否正确。首先把输入的密码文本取出来,存放到字符串指针ss中,然后再对ss进行判断,如果正确,则返回TRUE,从而进入应用程序主窗口。
获取编辑框里的密码文本的代码如下:
SendDlgItemMessage(hWnd,IDC_EDIT,EM_GETLINE,(WPARAM)00,(LPARAM)ss);
这样密码文本被存放到字符串指针ss中,EM_GETLINE表示得到编辑框里的一行文本。
  在主窗口的消息处理函数中,除文本越界处理外,编辑框的消息全部由Windows自己完成,并且能完成一般编辑框所需要的剪切、拷贝、粘贴等常用功能。处理文本越界的代码如下:
if (LOWORD (wParam) == 1)
  if(HIWORD (wParam) == EN_ERRSPACE || HIWORD (wParam) == EN_MAXTEXT)
    MessageBox (hwnd, "Edit control out of space.",szAppName, MB_OK | MB_ICONSTOP) ;
  当文本内存空间不够或者输入的字符数目大于最大设置的数目时,将弹出出错消息框。程序编译、运行后,首先弹出密码对话框,如图所示。

  当用户输入的密码有误时,则弹出消息框,把用户输入的密码文本显示出来,当单击“确定”按钮后,则显示密码输入错误的消息,单击“确定”或“取消”按钮,退出本程序。如果密码输入正确,就弹出应用程序的主窗口,如图所示。

可以在编辑框里输入文本,也可以从剪贴板上粘贴文本,当右击选中的某段文本后,则弹出浮动菜单。
编辑控件实例2
#include <windows.h>
HINSTANCE hInst;
HWND hMainWnd;
HWND hCtl;
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int);
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
  hInst = hInstance;
  WNDCLASSEX wcex;
  wcex.cbSize = sizeof(WNDCLASSEX);
  wcex.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
  wcex.lpfnWndProc = (WNDPROC)WndProc;
  wcex.cbClsExtra = 0;
  wcex.cbWndExtra = 0;
  wcex.hInstance = hInstance;
  wcex.hIcon = LoadIcon(hInstance,IDI_APPLICATION);
  wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
  wcex.hbrBackground = (HBRUSH)COLOR_WINDOW;
  wcex.lpszMenuName = NULL;
  wcex.lpszClassName = "MainWndClass";
  wcex.hIconSm = LoadIcon(hInstance,IDI_APPLICATION);
  if(!RegisterClassEx(&wcex)) return FALSE;
  int SW_XFS = GetSystemMetrics(SM_CXSCREEN);
  int SW_YFS = GetSystemMetrics(SM_CYSCREEN);
  hMainWnd = CreateWindowEx(WS_EX_CLIENTEDGE,
               "MainWndClass",
               "Main window of the edit control",
               WS_OVERLAPPEDWINDOW,
               0, 0, SW_XFS, SW_YFS,
               NULL,
               NULL,
               hInstance,
               NULL);
  if(!hMainWnd) return FALSE;
  ShowWindow(hMainWnd,nCmdShow);
  UpdateWindow(hMainWnd);
  MSG msg;

  while(GetMessage(&msg,NULL,0,0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
  static int wwp,whp;
  RECT rect;

  switch(message)
  {
    case WM_CREATE:
    GetClientRect(hWnd,&rect);
    wwp = rect.right-rect.left;
    whp = rect.bottom-rect.top;
    hCtl = CreateWindowEx(WS_EX_CLIENTEDGE,
               "EDIT",
               NULL,
               WS_CHILD|WS_HSCROLL|WS_VSCROLL|WS_VISIBLE
               |ES_MULTILINE|ES_AUTOHSCROLL|ES_AUTOVSCROLL,
               wwp/4, whp/4, wwp/2,whp/2,hWnd,
               NULL, hInst, NULL);
    if(!hCtl) PostQuitMessage(0);
    break;

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

列表框

  列表框允许用户从多个对象中选择一项 或多项,这些对象可以是文本、文件和 位图等。当列表框的项不能全部显示出来 时,可以用滚动条来滚动显示。
1. 基础知识
  默认的列表框只允许用户单选,需要多选时,须把列表框的风格定义为 LBS_ MULTIPLESEL 和 LBS_EXTENDEDSEL 。列表框提供的其他风格取值可以控制列表框的外观和操作。例如是否按照列表框各项的名称排序,是否多行排列,是否有滚动条等。

风格取值
描述
LBS_EXTENDEDSEL 能通过Shift键或者鼠标进行多选
LBS_HASSTRINGS 可以用GetText函数得到列表框里选项的字符串
LBS_MULTICOLUMN 指定列表框以多列形式显示内容
LBS_MULTIPLESEL 用户可以选择多个项
LBS_NOINTEGRALHEIGHT 当应用程序创建列表框时,列表框的大小由系统指定
LBS_NOREDRAW 列表框不响应用户的修改,可以通过发送WM_REDRAW 来取消该设置
LBS_NOTIFY 让主窗口接收列表框的任何改变的消息
LBS_OWNERDRAWFIXED 主窗口负责列表框的重画,列表框里每项的高度相同
LBS_0WNERDRAWVARIABLE 主窗口负责列表框的重画,列表框里每项的高度可以变化
LBS_SORT 按各项名称的字母排序
LBS_STANDARD 等同于LBS_SORT和LBS_NOTIFY
LBS_USETABSTOPS 允许用户使用Tab键在各项中切换
LBS_WANTKEYBOARDINPUT 输入焦点在列表框时,任何键盘输入都会向父窗口发送WM_VKEYTOITEM或者WM_CHARTOITEM消息
LBS_DISABLENOSCROLI 当列表框的项不够时,垂直滚动条禁活:没有该属性时,滚动条隐藏

  当用户对列表框进行了操作时,就会向主窗口发送一条消息。列表框的消息类型比较简单,主要是单击、双击和选择等。同编辑框一样,列表框也会遇到内存不够的问题,所以消息类型中含有这一项。消息总是通过WM_COMMAND的形式发送给主窗口的。其中,wParam的低位字节表示列表框的标识符,高位字节表示消息的类型,lParam表示主窗口句柄。列表框的消息类型如表所示。

消息类型
描述
LB_DELETESTRING 删除指定的选项
LB_ADDFILE 向列表框里增加一个文件(包括目录)
LB_FINDSTRING 在列表框里查找指定的项
LB_FINDSTRlNGEXACT 精确查找指定的项
LB_GETCOUNT 得到列表框里项的数目
LB_GETCURSEL 返回当前被选中选项的序号
LB_GETSEL 得到被选项的状态,如果出错,则返回零值
LB_GETSELCOUNT 得到被选中的个数
LB_GETTEXT 返回选中的文本,返回值为字符串长度
LB_GETTEXTLEN 返回字符串长度
LB_INITSTORAGE 向列表框增加项之前存储原来的内容
LB_INSERTSTRING 向列表框增加一项,但不重新排序
LB_ITEMFROMPOINT 返回离指定点最近项的序号
LB_RESETCONTENT 清除列表框里所有的项
LB_SELECTSTRING 寻找指定的项
LB_SELITEMRANGE 指定选择的范围
LB_SELITEMRANGEEX 选定或者删除指定的项
LB_SETCOLUMNWIDTH 设置列的宽度
LB_SETCOUNT 设置列表框里项的最大数目
LB_SETCURSEL 选中指定的项
LBN_DBLCLK 发送用户双击的消息
LBN_ERRSPACE 发送内存空间不够的消息
LBN_KILLFOCUS 当列表框失去焦点时发送该消息
LBN_SELCANCEL 当用户取消选择时发送该消息
LBN_SELCHANGE 当用户选择改变时发送该消息
LBN_SETFOCUS 当输入焦点转移到列表框时发送该消息
WM_CTLCOLORLISTBOX 在列表框重画时向父窗口发送该消息
WM_DELETEITEM 删除选项
WM_VKEYTOITEM 输入焦点在列表框里,用户按键时发送该消息

  列表框也是通过调用函数CreateWindow来创建的,第一参数设置为ListBox即可。风格取值可以取表所示的值。在主窗口里的消息一般是在 WM_ COMMAND里处理表中以LBN开头的消息。下面以一个具体的例子介绍列表框的常见操作。

2.应用程序举例列表框的应用:
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#define MAXENV 4096
static char szAppName[]="Environ";
//预先申明消息处理、申请窗口类以及应用程序初始化的函数
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
//函数:WinMain
//作用:主应用函数
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
  MSG msg ;
  //申请窗口类
  MyRegisterClass(hInstance);
  //应用程序的初始化
  if(!InitInstance(hInstance,iCmdShow)) return FALSE;

  while (GetMessage (&msg, NULL, 0, 0))
  {
    TranslateMessage (&msg) ;
    DispatchMessage (&msg) ;
  }
  return msg.wParam ;

  wndclass.lpszClassName = szAppName ;
  wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;
  return RegisterClassEx (&wndclass) ;
}
//函数:InitInstance 作用:初始化应用程序
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
  HWND hwnd ;
  hwnd = CreateWindow(szAppName, "Environ List Box",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL, NULL, hInstance, NULL) ;
  if(!hwnd) { return FALSE; }
  ShowWindow (hwnd, nCmdShow) ;
  UpdateWindow (hwnd) ;
  return TRUE;
}
//函数:WndProc
//作用:消息处理函数
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
  //定义字符串变量,必须是静态变量
  static char szBuffer[MAXENV + 1] ;
  static HWND hwndList, hwndText,hwndEdit,AddButton,DeleteButton;
  //定义设备描述表句柄
  HDC hdc ;
  int i ;
  //定义文本区域尺寸
  TEXTMETRIC tm ;
  switch (iMsg)
  {
    case WM_CREATE :
    //获取设备描述表句柄
    hdc = GetDC (hwnd) ;
    GetTextMetrics (hdc, &tm) ;
    ReleaseDC (hwnd, hdc) ;
    //创建列表框,第一个参数"ListBox"表示将创建列表框
    hwndList = CreateWindow("ListBox", NULL,
                WS_CHILD | WS_VISIBLE | LBS_STANDARD|LBS_SORT|WS_VSCROLL,
                tm.tmAveCharWidth*4, tm.tmHeight * 3,
                tm.tmAveCharWidth * 30 + GetSystemMetrics (SM_CXVSCROLL),
                tm.tmHeight * 10,
                hwnd, (HMENU) 1,
                (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),NULL) ;
    //建立静态文本框,第一个参数"static“表示将建立静态文本框
    hwndText = CreateWindow("static", NULL,
                WS_CHILD | WS_VISIBLE | SS_LEFT,
                tm.tmAveCharWidth*2, tm.tmHeight-10,
                tm.tmAveCharWidth * MAXENV/2, tm.tmHeight,
                hwnd, (HMENU) 2,
                (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),NULL) ;
    //建立编辑框,主要用来编辑向
    //列表框添加的文本
    hwndEdit = CreateWindow("edit","ItemEdit",//定义初始值为"ItemEdit"
                WS_CHILD | WS_VISIBLE |WS_BORDER | ES_LEFT | ES_MULTILINE |
                ES_AUTOHSCROLL | ES_AUTOVSCROLL,
                tm.tmAveCharWidth * 35+GetSystemMetrics (SM_CXVSCROLL),
                tm.tmHeight * 3,
                tm.tmAveCharWidth*20+GetSystemMetrics (SM_CXVSCROLL),
                tm.tmHeight * 2,
                hwnd, (HMENU)3,
                ((LPCREATESTRUCT) lParam) -> hInstance, NULL) ;
    //创建添加按钮,当按下该按钮时,列表框添加编辑框里的文本
    AddButton = CreateWindow ("button","Add",
                 WS_CHILD | WS_VISIBLE |BS_PUSHBUTTON,
                 tm.tmAveCharWidth *39,
                 tm.tmHeight*6,
                 tm.tmAveCharWidth*9,
                 tm.tmHeight*2,
                 hwnd, (HMENU)4,
                 ((LPCREATESTRUCT) lParam) -> hInstance, NULL) ;
    //创建删除按钮,当按下按钮时,列表框里
    //的当前项被删除
    DeleteButton= CreateWindow ("button","Del",
                  WS_CHILD | WS_VISIBLE |BS_PUSHBUTTON,
                  tm.tmAveCharWidth*50,
                  tm.tmHeight*6,
                  tm.tmAveCharWidth*9,
                  tm.tmHeight*2,
                  hwnd, (HMENU)5,
                  ((LPCREATESTRUCT) lParam) -> hInstance, NULL) ;
    //添加一个列表框选项
    SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM)"good") ;
    return 0;

    case WM_SETFOCUS :
    //将输入焦点设置在编辑框
    SetFocus (hwndEdit) ;
    return 0 ;

    case WM_COMMAND :
    //显示列表框里选中的项
    if (LOWORD (wParam) == 1 && HIWORD (wParam) == LBN_SELCHANGE)
    {
      i = SendMessage (hwndList, LB_GETCURSEL, 0, 0) ;
      i = SendMessage (hwndList, LB_GETTEXT, i,(LPARAM) szBuffer) ;
      SetWindowText (hwndText, szBuffer);
      return 0;
    }

    switch(LOWORD(wParam))
    {
      //当单击增加按钮时,当前编辑框里的文本
      //被增加到列表框里,并自动排序
      case 4:
      GetDlgItemText(hwnd,3,szBuffer,10);
      SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM) szBuffer) ;
      return 0;

      case 5: //当单击删除按钮时,则当前列表
      //框里的选中的项被删除获取当前选中的项
      //的位置值
      i = SendMessage (hwndList, LB_GETCURSEL, 0, 0) ;
      //发送删除消息
      SendMessage(hwndList,LB_DELETESTRING,i,wParam);
      //选中上一个项
      SendMessage (hwndList, LB_SETCURSEL,i-1,0) ;
      default:
      return 0;
    }

    case WM_DESTROY :

    PostQuitMessage (0) ;

    return 0 ;
  }
  return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}
  本应用程序主要实现列表框的创建、选项的删除和添加等功能。在程序中分别创建了五个子窗口,它们分别是静态文本框、编辑框、列表框和两个按钮。
  静态文本框也属于子窗口,用CreateWindow函数创建时只需要把第一个参数设置为Static即可,调用代码如下:
hWndText = CreateWindow(“static”, NULL,
            WS_CHILD|WS_VISIBLE|SS_LEFT,
            tm.tmAveCharWidth*2,tm.tmHeight-10,
            tm.tmAveCharWidth*MAXENV,tm.tmHeight,
            hWnd, (HMENU)2,
            (HINSTANCE)GetWindowLong(hWnd,GWL_HINSTANCE),
            NULL);
  其中第二个参数设置为NULL表示静态文本框的文本初始值为空,它的主要作用是显示当前列表框被选中项的名称。编辑框主要用来编辑需要增加项的名称。创建列表框的代码如下:
hwndList = CreateWindow("ListBox", NULL,
            WS_CHILD | WS_VISIBLE | LBS_STANDARD|LBS_SORT|WS_VSCROLL,
            tm.tmAveCharWidth*4, tm.tmHeight * 3,
            tm.tmAveCharWidth * 30 + GetSystemMetrics (SM_CXVSCROLL),
            tm.tmHeight * 10,
            hwnd, (HMENU) 1,
            (HINSTANCE) GetWindowLong (hwnd,
            GWL_HINSTANCE),NULL) ;
  由第三个参数的设置可知,列表框只能单选,可自动排序,并带有垂直滚动条。创建列表框后,向列表框增加一项。名称为good,可用如下代码:
SendMessage(hWndList,LB_ADDSTRING,0,(LPARAM)"good");
  两个按钮的名称分别为Add和Del,其创建过程在前节中已有详细介绍,这里不再剖析。
  本应用程序的消息处理比较复杂,它包括跟踪当前列表框选中的项,并在静态文本框里显示出来;从编辑框里取出文本;向列表框增加项,删除当前选中的项等。
显示当前列表框选中的项的代码如下:
if (LOWORD (wParam) == 1 && HIWORD (wParam) == LBN_SELCHANGE)
{
  i = SendMessage (hwndList, LB_GETCURSEL, 0, 0) ;
  i = SendMessage (hwndList, LB_GETTEXT, i,(LPARAM) szBuffer) ;
  SetWindowText (hwndText, szBuffer);
  return 0;
}
  程序首先获得当前选中项的序号,然后得到当前选中项的文本,并把文本拷贝到字符串指针szBuffer中,最后,用函数SetWindowText发送到静态文本框,从而实现了列表框选项的显示。
  当用户按下Add按钮后,将把编辑框里当前的文本增加进列表框,并重新排序,代码如下:
case 4:
GetDlgItemText(hWnd,3,szBuffer,10);
SendMessage(hWndList,LB_ADDSTRING,0,(LPARAM)SzBuffer);
return 0;
  首先从编辑框中取得文本,然后向列表框发送LB_ADDSTRING消息,把文本增加到列表框里,同时由于列表框在创建时具有LBS_SORT风格,所以列表框在增加了新的选项后立即自动排序,用户只能看到在新的排序下增加的选项的情况。
当用户按下Del按钮后,将把选中的选项删除,代码如下:
case 5: //当单击删除按钮时,则当前列表框里的选中的项被删除
//获取当前选中的项的位置值
i = SendMessage (hwndList, LB_GETCURSEL, 0, 0) ;
//发送删除消息
SendMessage(hwndList,LB_DELETESTRING,i,wParam);
//选中上一个项
SendMessage (hwndList, LB_SETCURSEL,i-1,0) ;
  首先取得当前选项的序号,然后向列表框发送LB_ DELETESTRING消息,这样就删除了指定的选项。然后又向列表框发送LB_SETCURSEL消息,使当前焦点自动转移到刚删除的选项的上一项。程序编译、运行后出现如图所示的界面。

  当按下Add按钮后,将向列表框添加一项;也可以按下Del键,从而删除选中的那如图所示。

组合框

  组合框兼具编辑框和列表框的功能,既能编辑选项,又能显示多个项。在Windows程序设计中可以见到大量组合框的应用实例,例如文件对话框里的目录搜索组合框。
1.基础知识
  组合框的风格主要有三种,分别是简单组合框( Simple ComboBox)、下拉式组合框(DropDown ComboBox)和下拉式列表框( DropDown ListBox)。
  下拉式列表框和下拉式组合框平时只显示编辑区域,只在打开时才显示组合框的各项,这样有利于节省屏幕空间。这三种组合框的基本功能如表所示。

组合框类型
是否有下拉式列表
是否有编辑区域
简单组合框
下拉式组合框
下拉式列表框

  组合框的风格取值定义了组合框的具体属性,包括是否自动排序,是否有滚动条。这些风格取值如表所示。

风格取值
描述
CBS_AUTOHSCROLL 当用户在编辑区域键入字符时,列表框自动滚动,使当前项的名称与键入的字符排序相同
CBS_DROPDOWN 创建一个下拉式组合框
CBS_DROPDOWNLIST 创建一个下拉式列表框
CBS_HASSTRINGS 让应用程序能够使用GetText取得组合框里的文本
CBS_OEMCONVERT 把输入的文本将从ANSI码转换成OEM码,然后又转换成ANSI码;这样的目的是保证函数AnsiToOem的正确调用
CBS_OWNERDRAWFIXED 父窗口负责重画组合框里的各项,并使各项的高度一致
CBS_OWNERDRAWVARIABLE 父窗口负责重画组合框里的各项,各项的高度不一致
CBS_SIMPLE 组合框显示所有的项,当前的选项在编辑区域中显示
CBS_SORT 自动排序
CBS_DISABLENOSCROLL 组合框有垂直滚动条,当组合框的项不足时,滚动条禁活;没有该风格,则滚动条隐藏
CBS_NOINTEGRALHEIGHT 指定组合框的大小由程序精确控制,通常组合框的大小由组合框里项的数目决定

  创建一个组合框只需把CreateWindow的第一个参数设置为ComboBox,然后取表中的值即可。组合框创建后,需要初始化,即通过向组合框发送CB_ADDSTRING增加最初的项,这类似于列表框。如果没有定义CBS_SORT风格,新增的项将被增加到组合框的末尾。
  应用程序的父窗口主要通过 WM_COMMAND消息与组合框通信,应用程序可以用CB_FINDSTRINGEXACT搜索指定的项,还可以发送CB_DELETESTRING删除指定的项,当需要删除所有的项时,发送消息CB_RESETCONTENT即可。
  组合框的编辑区域用来显示当前选中的项或者编辑组合框里没有的项。可以用CB_LIMITTEXT来限制输入文本的大小;为了获得编辑区域的文本,可发送CB_GETTEXT消息,这样就把文本复制到指定的字符串中,当需要设置编辑区域的文本时,只需要发送CB_SETTEXT消息。
  Windows API为组合框提供了文件显示和搜索的功能,它们主要通过函数DlgDirListComboBox和DlgDirSelectComboBox来实现。本节的应用程序中将用到这些函数,并把文件的内容显示在窗口里。

取 值
描 述
CB_ADDSTRlNG 增加一项
CB_DELETESTRING 删除指定的项
CB_DIR 发送搜索目录的消息
CB_FINDSTRING 搜索指定的项
CB_FINDSTRINGEXACT 精确搜索指定的项
CB_GETCOUNT 得到组合框中项的数目
CB_GETCURSEL 得到当前选中项的序号
CB_GETEDITSEL 得到编辑区域选中的文本
CB_GETLBTEXT 得到编辑区域的文本
CB_GETLBTEXTLEN 得到编辑区域中文本的长度
CB_LIMITTEXT 发送限制编辑区域文本的消息
CB_RESETCONTENT 删除所有的项
CB_SELECTSTRING 选中指定的字符串
CB_SETCURSEL 将光标设置在指定的位置
CB_SETDROPPEDWIDTH 设置下拉的宽度
CB_SETEDITSEL 选取编辑区域的文本
CBN_CLOSEUP 关闭组合框
CBN_DBLCLK 发送用户双击组合框中项的消息
CBN_DROPDOWN 下拉时发送消息
CBN_EDITCHANGE 发送编辑区域改变的消息
CBN_EDITUPDATE 发送编辑区域改变的消息,但在更新之前发送
CBN_ERRSPACE 发送内存不够的消息
CBN_KILLFOCUS 当组合框失去输入焦点时发送该消息
CBN_SETFOCUS 设置输入焦点

2.应用程序举例
组合框的应用:
#include <windows.h>
#include <string.h>
#include <direct.h>
#define MAXPATH 256
#define MAXREAD 8192
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK ListProc (HWND, UINT, WPARAM, LPARAM) ;
WNDPROC fnOldList;
//定义应用程序的名字
static char szAppName[] = "Head" ;
//预先申明消息处理、申请窗口类以及应用程序初始化的函数
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
//函数:WinMain
//作用:主应用函数
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
  MSG msg ; //申请窗口类
  MyRegisterClass(hInstance); //应用程序的初始化
  if(!InitInstance(hInstance,iCmdShow)) {return FALSE;}

  while (GetMessage (&msg, NULL, 0, 0))
  {
    TranslateMessage (&msg) ;
    DispatchMessage (&msg) ;
  }
  return msg.wParam ;
}
//函数:MyRegisterClass
//作用:详细定义申请窗口类
ATOM MyRegisterClass(HINSTANCE hInstance)
{
  WNDCLASSEX wndclass ;
  wndclass.cbSize = sizeof (wndclass) ;
  wndclass.style = CS_HREDRAW | CS_VREDRAW ;
  wndclass.lpfnWndProc = WndProc ;
  wndclass.cbClsExtra = 0 ;
  wndclass.cbWndExtra = 0 ;
  wndclass.hInstance = hInstance ;
  wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
  wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
  wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
  wndclass.lpszMenuName = NULL ;
  wndclass.lpszClassName = szAppName ;
  wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;
  return RegisterClassEx (&wndclass) ;
}
//函数:InitInstance 作用:初始化应用程序
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
  HWND hwnd ;
  hwnd = CreateWindow(szAppName, "组合框",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL, NULL, hInstance, NULL) ;
  if(!hwnd) {return FALSE;}

  ShowWindow (hwnd, nCmdShow) ;
  UpdateWindow (hwnd) ;
  return TRUE;
}
//函数:WndProc
//作用:消息处理
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
  //定义文件是否合法的标志
  static BOOL bValidFile ;
  //定义文件存放字符串和文件名字符串
  static char sReadBuffer[MAXREAD],szFile[MAXPATH] ;
  //定义目录列表框和文件名文本框
  static HWND hwndList, hwndText ;
  static OFSTRUCT ofs ;
  //定义文本显示区域
  static RECT rect ;
  char szBuffer[MAXPATH + 1] ;
  HDC hdc ;
  int iHandle, i ;
  PAINTSTRUCT ps ;
  TEXTMETRIC tm ;
  switch (iMsg)
  {
    case WM_CREATE :
    hdc = GetDC (hwnd) ;
    SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
    GetTextMetrics (hdc, &tm) ;
    ReleaseDC (hwnd, hdc) ;
    rect.left = 1* tm.tmAveCharWidth ;
    rect.top = 3 * tm.tmHeight ;
    //建立组合框
    hwndList = CreateWindow("ComboBox", NULL,
                WS_CHILDWINDOW | WS_VISIBLE | CBS_AUTOHSCROLL|CBS_SORT,
                tm.tmAveCharWidth*40, tm.tmHeight * 3,
                tm.tmAveCharWidth * 13 +GetSystemMetrics (SM_CXVSCROLL),
                tm.tmHeight * 10,
                hwnd, (HMENU) 1,
                (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),NULL) ;
    //建立静态文本框,显示文件内容
    hwndText = CreateWindow("static", getcwd (szBuffer, MAXPATH),
                WS_CHILDWINDOW | WS_VISIBLE | SS_LEFT,
                tm.tmAveCharWidth, tm.tmHeight,
                tm.tmAveCharWidth * MAXPATH, tm.tmHeight,
                hwnd, (HMENU) 2,
                (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),NULL) ;
    //建立组合框的消息处理函数对应机制,其中最后一个参数"ListProc"
    //表示组合框的消息处理函数名称,这样就使组合框的事件和处理联系起来
    fnOldList = (WNDPROC) SetWindowLong (hwndList, GWL_WNDPROC, (LPARAM) ListProc) ;
    //"*.*"表示组合框中的上一级目录
    SendMessage (hwndList, CB_DIR, 0x37, (LPARAM) "*.*") ;
    return 0 ;
    //取得窗口的尺寸,并赋值给矩形变量

    case WM_SIZE :
    rect.right = (LOWORD (lParam))/2 ;
    rect.bottom = HIWORD (lParam) ;
    return 0 ;

    case WM_SETFOCUS :
    SetFocus (hwndList) ;//设置输入焦点
    return 0 ;

    case WM_COMMAND :
    if(LOWORD(wParam) == 1 && HIWORD (wParam) == CBN_DBLCLK)
    {
      //跟踪组合框的选项
      if(CB_ERR==(i=SendMessage(hwndList,CB_GETCURSEL, 0, 0L)))
      break ;

      //把组合框当前选项传送到字符串
      SendMessage(hwndList, CB_GETLBTEXT, i,(LPARAM) szBuffer) ;
      //判断是否能打开文件
      if (-1 != OpenFile (szBuffer, &ofs, OF_EXIST | OF_READ))
      {

        bValidFile = TRUE ;
        //把文件中的内容送给字符串
        strcpy (szFile, szBuffer) ;
        getcwd (szBuffer, MAXPATH) ;
        if (szBuffer [strlen (szBuffer) - 1] != '\\') strcat (szBuffer, "\\") ;
        //显示文件目录和名称

        SetWindowText (hwndText, strcat (szBuffer, szFile)) ;
      }
      else
      {
        bValidFile = FALSE ;
        szBuffer [strlen (szBuffer) - 1] = '\0' ;
        chdir (szBuffer + 1) ;
        getcwd (szBuffer, MAXPATH) ;

        SetWindowText (hwndText, szBuffer) ;
        SendMessage (hwndList, CB_RESETCONTENT, 0, 0L) ;
        SendMessage (hwndList, CB_DIR, 0x37, (LONG) "*.*") ;
      }
      InvalidateRect (hwnd, NULL, TRUE) ;//重新绘制窗口
    }

    return 0 ;

    case WM_PAINT :
    hdc = BeginPaint (hwnd, &ps) ;
    SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
    SetTextColor (hdc, GetSysColor(COLOR_BTNTEXT)) ;
    SetBkColor (hdc, GetSysColor (COLOR_BTNFACE)) ;
    //判断是否能打开文件
    if (bValidFile && -1 != (iHandle =OpenFile (szFile, &ofs, OF_REOPEN | OF_READ)))
    {
      i = _lread(iHandle,sReadBuffer,MAXREAD) ;
      _lclose (iHandle) ;
      //在矩形区域内显示文件内容
      DrawText (hdc, sReadBuffer, i, &rect,
           DT_WORDBREAK |DT_EXPANDTABS | DT_NOCLIP | DT_NOPREFIX) ;
    }
    else bValidFile = FALSE ;
    EndPaint (hwnd, &ps) ;
    return 0 ;

    case WM_DESTROY :
    PostQuitMessage (0) ;
    return 0 ;
  }
  return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}
//定义组合框的消息处理函数
LRESULT CALLBACK ListProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
  if (iMsg == WM_KEYDOWN && wParam == VK_RETURN)
    //判断是否有键按下,在把消息送给主窗口处理
    SendMessage (GetParent (hwnd), WM_COMMAND, 1,MAKELONG (hwnd, CBN_DBLCLK)) ;

  return CallWindowProc (fnOldList, hwnd, iMsg, wParam, lParam) ;
}
本应用程序主要利用组合框的文件搜索功能自动显示文件内容。
程序首先创建组合框,代码如下:
hwndList = CreateWindow("ComboBox", NULL,
            WS_CHILDWINDOW | WS_VISIBLE | CBS_AUTOHSCROLL|CBS_SORT,
            tm.tmAveCharWidth*40, tm.tmHeight * 3,
            tm.tmAveCharWidth * 13 + GetSystemMetrics (SM_CXVSCROLL),
            tm.tmHeight * 10,
            hwnd, (HMENU) 1,
            (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),NULL) ;
  由第三个参数的设置可看出,创建的组合框能自动排序,并有垂直滚动条。
  然后组合框当前选中项的文本显示到静态文本框里,代码如下:
SendMessage(hwndList,CB_GETLBTEXT,i,(LPARAM) szBuffer) ;
SetWindowText (hwndText, strcat (szBuffer, szFile)) ;
最后显示文件的内容,代码如下:
if(bValidFile && -1!=(iHandle=OpenFile(szFile,&ofs, OF_REOPEN | OF_READ)))
{
  i = _lread (iHandle, sReadBuffer, MAXREAD) ;
  _lclose (iHandle) ;
  //在矩形区域内显示文件内容
  DrawText (hdc, sReadBuffer, i, &rect,
       DT_WORDBREAK |DT_EXPANDTABS | DT_NOCLIP | DT_NOPREFIX) ;
}
  程序首先打开文件,并把文件的内容读人sReadBuffer字符串,然后再用DrawText函数显示出来。

滚动条

  滚动条既可以是许多子窗口(如编辑框、列表框)的附件,又可以独立成为子窗口。
1.基础知识
  滚动条的主要用途在于对某个在一定范围内变化的属性值或者变量进行动态设置。例如用滚动条可以方便地控制颜色的深浅,设置线条的宽度;滚动条也用来显示某个任务的进度,这样滚动条又被称为进度条。
  滚动条的风格如表所示。

风格取值
描述
SBS_BOTTOMALIGN 创建水平滚动条,滚动条在窗口的底端
SBS_HORZ 创建水平滚动条
SBS_LEFTALIGN 创建一个靠左对齐的垂直滚动条
SBS_mGHTALIGN 创建一个靠右对齐的垂直滚动条
SBS_SIZEBOX 创建一个对话框式的滚动条
SBS_TOPALIGN 适用于水平滚动条,顶端与指定的矩形对齐
SBS_VERT 创建垂直滚动条

  滚动条的消息类型如表所示。

滚动条消息
描述
SBM_ENABLE ARROWS 激活或者关闭滚动条的滚动按钮
SBM_GETPOS 得到滚动条当前滚动按钮的位置
SBM_GETRANGE 得到滚动条当前设置的范围
SBM_GETSCROLLINFO 得到滚动条的相关信息,包括位置、大小等
SBM_SETPOS 设置滚动条滚动按钮的位置
SBM_SETRANGE 设置范围
SBM_SETRANGEREDRAW 当需要重画滚动条时发送设置最大和最小值位置的消息
SBM_SETSCROLLINFO 设置滚动条属性
WM_CTLCOLORSCROLLBAR 当滚动条改变时向父窗口发送设置背景颜色的消息
WM_HSCROLL 水平滚动条变化
WM_VSCROLL 垂直滚动条变化

  滚动条有一些重要的函数和方法,下面分别介绍。
用来设置滚动条类型和活动状态的函数是EnableScrollBar,其原型定义如下:
BOOL EnableScrollBar(
  HWND hwnd // 指向父窗口或者滚动条的句柄
  UINT wSBflags,//标志滚动条的类型
  UINT wArrows //滚动条的滚动按钮设置
);
wSBflag用来设置滚动条的类型,可以取表所示的任意值。
wSBflag的取值参数

参数取值
描述
SB_BOTH 使一个水平或者垂直滚动条的滚动按钮禁活或者复活,hWnd必须指向父窗口
SB_CTL 设置滚动条的标识符,hWnd必须指向滚动条
SB_HORZ 使一个水平滚动条的滚动按钮禁活或者复活,hWnd必须指向父窗口
SB_VERT 使一个垂直滚动条的滚动按钮禁活或者复活,hWnd必须指向父窗口

wArrows设置滚动条滚动按钮的活动状态,取值如表所示。

参数取值
描述
ESB_DISABLE_BOTH 使滚动条两个滚动按钮都禁活
ESB_DISABLE_DOWN 使垂直滚动条向下的滚动按钮禁活
ESB_DISABLE_LEFT 使水平滚动条向左的滚动按钮禁活
ESB_DISABLE_LTUP 使水平滚动条向左的滚动按钮禁活,或者使垂直滚动条向上的滚动按钮禁活
ESB_DISABLE_RIGHT 使水平滚动条向右的滚动按钮禁活
ESB_DISABIE_RTDN 使水平滚动条向右的滚动按钮禁活,或者使垂直滚动条向下的滚动按钮禁活
ESB_DISABLE_UP 使垂直滚动条向上的滚动按钮禁活
ESB_ENABLE_BOTH 使两个滚动按钮都能活动

显示或隐藏滚动条的函数是ShowScrollBar,
其原型定义如下:
BOOL ShowScrollBar(
HWND hwnd ,//指向父窗日的句柄
int wBar ,//滚动条活动状态的标志
BOOL bShow//滚动条是否可见,当为TRUE时可见,相反则隐藏
);
其中参数 wBar取值如表所示。
2.应用程序举例
滚动条的应用:
#include <windows.h>
#include <stdlib.h>
LRESULT CALLBACK ScrollProc (HWND, UINT, WPARAM, LPARAM) ;
WNDPROC fnOldScr[3] ;
//定义全局变量,包括滚动条、标签、
// 颜色值和客户区
HWND hwndScrol[3], hwndLabel[3],HWND hwndValue[3], hwndRect ;
int color[3], iFocus,i;
//定义三种颜色
static char *szColorLabel[] = { "红色", "绿色", "蓝色" } ;
static char szAppName[]="颜色调整";
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
//函数:WinMain
//作用:主应用函数
Int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
  MSG msg ;
  //注册窗口类
  MyRegisterClass(hInstance);
  //应用程序的初始化
  if(!InitInstance(hInstance,iCmdShow))
  {
    return FALSE;
  }

  while (GetMessage (&msg, NULL, 0, 0))
  {
    TranslateMessage (&msg) ;
    DispatchMessage (&msg) ;
  }
  return msg.wParam ;
}
//函数:MyRegisterClass
//作用:注册窗口类
ATOM MyRegisterClass(HINSTANCE hInstance)
{
  WNDCLASSEX wndclass ;
  wndclass.cbSize = sizeof (wndclass) ;
  wndclass.style = CS_HREDRAW | CS_VREDRAW ;
  wndclass.lpfnWndProc = WndProc ;
  wndclass.cbClsExtra = 0 ;
  wndclass.cbWndExtra = 0 ;
  wndclass.hInstance = hInstance ;
  wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
  wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
  wndclass.hbrBackground =(HBRUSH)GetStockObject (WHITE_BRUSH) ;
  wndclass.lpszMenuName = NULL ;
  wndclass.lpszClassName = szAppName ;
  wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;
  return RegisterClassEx (&wndclass) ;
}
//函数:InitInstance
//作用:初始化应用程序
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
  HWND hwnd ;
  hwnd = CreateWindow(szAppName, "颜色选择",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL, NULL, hInstance, NULL) ;
  ShowWindow (hwnd, nCmdShow) ;
  UpdateWindow (hwnd) ;
  return TRUE;
}
//函数:WndProc
//作用:消息处理函数
LRESULT CALLBACK WndProc (HWND hwnd,UINT iMsg, WPARAM wParam, LPARAM lParam)
{//定义颜色结构变量
  static COLORREF crPrim[3] = { RGB (255, 0, 0), RGB (0, 255, 0),RGB (0, 0, 255) } ;
  static HBRUSH hBrush[3], hBrushStatic ;
  static int cyChar ;
  //定义颜色改变区域
  static RECT rcColor;
  char szbuffer[10] ;
  int i, cxClient, cyClient ;
  //定义静态文本区域
  HWND hwndstatic;
  HINSTANCE hInstance;
  hInstance=(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE)

  switch (iMsg)
  {
    case WM_CREATE :
    for (i = 0 ; i < 3 ; i++) hBrush[i] = CreateSolidBrush (crPrim[i]) ;
    //定义画刷
    hBrushStatic = CreateSolidBrush ( GetSysColor (COLOR_BTNHIGHLIGHT)) ;
    cyChar = HIWORD (GetDialogBaseUnits ()) ;
    //创建文本区域,用来存放滚动条
    hwndRect = CreateWindow("static", NULL,
                WS_CHILD | WS_VISIBLE | SS_WHITERECT, 0, 0, 0, 0,
                hwnd, (HMENU) 9, hInstance, NULL) ;
    //创建文本区域,显示应用程序当前状态
    hwndstatic = CreateWindow("static","颜色调整",
                 WS_CHILD | WS_VISIBLE|SS_CENTER,
                 400,300,100,30,
                 hwnd, (HMENU) 9, hInstance, NULL) ;
    //用For 循环来苏实现滚动条、标签、数值的显示
    for (i = 0 ; i < 3 ; i++)
    {
      hwndScrol[i] = CreateWindow("scrollbar", NULL,
                    WS_CHILD | WS_VISIBLE |SBS_HORZ,
                    0, 0, 0, 0,
                    hwnd, (HMENU) i, hInstance, NULL) ;
      hwndLabel[i] = CreateWindow("static", szColorLabel[i],
                    WS_CHILD | WS_VISIBLE | SS_CENTER,
                    0, 0, 0, 0,
                    hwnd, (HMENU) (i + 3), hInstance, NULL) ;
      hwndValue[i] = CreateWindow("static", "0",
                    WS_CHILD | WS_VISIBLE | SS_CENTER,
                    0,0,0,0,
                    hwnd, (HMENU) (i + 6), hInstance, NULL) ;
      fnOldScr[i] = (WNDPROC) SetWindowLong (hwndScrol[i], GWL_WNDPROC,(LONG) ScrollProc) ;
      //设置滚动条滚动范围
      SetScrollRange (hwndScrol[i], SB_CTL, 0, 255,FALSE) ;
      //设置滚动条初始位置
      SetScrollPos (hwndScrol[i], SB_CTL, 20,FALSE) ;
    }
    return 0 ;

    case WM_SIZE :
    //获取客户区大小
    cxClient = LOWORD (lParam) ;
    cyClient = HIWORD (lParam) ;
    //设置颜色变化区域
    SetRect (&rcColor, 0, 0, cxClient/2, cyClient) ;
    MoveWindow (hwndRect, cxClient/2,0,cxClient / 2, cyClient, TRUE) ;
    //设置滚动条的位置
    for (i = 0 ; i < 3 ; i++)
    {
      MoveWindow (hwndScrol[i],
            cxClient/2+60,(i+2)*cyClient/6-100,
            cxClient/3,
            cyClient/12,TRUE) ;
            MoveWindow (hwndLabel[i],
            cxClient/2+20,(i+2)*cyClient/6-100,
            40,cyClient/12, TRUE) ;
      MoveWindow (hwndValue[i],
            cxClient-40,(i+2)*cyClient/6-100,
            40, cyClient/12, TRUE) ;
    }
    SetFocus (hwnd) ;
    return 0 ;

    case WM_SETFOCUS :
    SetFocus (hwndScrol[iFocus]) ;
    return 0;

    case WM_HSCROLL :
    i = GetWindowLong ((HWND) lParam, GWL_ID) ;
    //设置滚动条滚动的步长
    switch (LOWORD (wParam))
    {
      case SB_PAGEDOWN :
      color[i] += 15 ;

      case SB_LINEDOWN :
      color[i] = min (255, color[i] + 1) ;
      break ;

      case SB_PAGEUP :
      color[i] -= 15 ;

      case SB_LINEUP :
      color[i] = max (0, color[i] - 1) ;
      break ;

      case SB_TOP :
      color[i] = 0 ;
      break ;

      case SB_BOTTOM :
      color[i] = 255 ;
      break ;

      case SB_THUMBPOSITION :

      case SB_THUMBTRACK :
      color[i] = HIWORD (wParam) ;
      break ;

      default :
      break ;
    }

    //从滚动条的位置读取颜色值
    SetScrollPos (hwndScrol[i], SB_CTL,color[i], TRUE) ;
    //显示颜色值
    SetWindowText (hwndValue[i], itoa (color[i],szbuffer, 10)) ;
    //释放画刷资源
    DeleteObject ((HBRUSH);
    SetClassLong(hwnd, GCL_HBRBACKGROUND,(LONG);
    CreateSolidBrush(RGB (color[0], color[1], color[2])))) ;
    //重画颜色变化区域
    InvalidateRect (hwnd, &rcColor, TRUE) ;
    return 0 ;

    case WM_CTLCOLORSCROLLBAR :
    //获取当前活动资源的标识符
    i = GetWindowLong ((HWND) lParam, GWL_ID) ;
    return (LRESULT) hBrush[i] ;

    case WM_CTLCOLORSTATIC :
    //获取当前活动资源的标识符,如果大于3且小于8则读取系统颜色值
    i = GetWindowLong ((HWND) lParam, GWL_ID) ;
    if (i >= 3 && i <= 8)
    {
      SetTextColor ((HDC) wParam, crPrim[i % 3]) ;
      SetBkColor ((HDC) wParam, GetSysColor (COLOR_BTNHIGHLIGHT));
      return (LRESULT) hBrushStatic ;
    }
    break ;

    case WM_SYSCOLORCHANGE :
    DeleteObject (hBrushStatic) ;
    hBrushStatic = CreateSolidBrush ( GetSysColor (COLOR_BTNHIGHLIGHT)) ;
    return 0 ;

    case WM_DESTROY :
    //释放画刷资源
    DeleteObject ((HBRUSH);
    SetClassLong (hwnd, GCL_HBRBACKGROUND, (LONG) GetStockObject (WHITE_BRUSH))) ;
    for (i = 0 ; i < 3 ; DeleteObject (hBrush[i++])) ;
    DeleteObject (hBrushStatic) ;
    PostQuitMessage (0) ;
    return 0 ;
  }
  return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}
//函数:ScrollProc
//作用:滚动条消息处理
LRESULT CALLBACK ScrollProc (HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
  int i = GetWindowLong (hwnd, GWL_ID) ;
  switch (iMsg)
  {

    case WM_KEYDOWN :
    //响应TAB键,当i小于3时,则转向下一个滚动条,否则重新开始
    if(wParam == VK_TAB) SetFocus(hwndScrol[(i+(GetKeyState(VK_SHIFT)< 0 ? 2 : 1))%3]) ;
    break ;

    case WM_SETFOCUS :
    iFocus = i ;
    break ;
  }
  Return CallWindowProc(fnOldScr[i],hwnd,iMsg,wParam,lParam);
}
本应用程序的主要功能是创建三个滚动条,分别控制红、黄、蓝三种颜色的深浅。
程序在消息循环函数中首先创建滚动条,代码如下:
hwndScrol[i] = CreateWindow ("scrollbar", NULL,
               WS_CHILD | WS_VISIBLE |SBS_HORZ,0, 0, 0, 0,
               hwnd, (HMENU) i, hInstance, NULL) ;
第一个参数为“scrollbar”,表示创建的子窗口是滚动条;第三个参数中的SBS_ HORZ表示滚动条是水平的;由于有三个滚动条将被创建,所以第九个参数为(HMENU)i,作为滚动条的标识符。
  滚动条有自己的消息处理函数,但是必须在应用程序中指定消息处理函数的句柄,并分配给相应的滚动条,代码如下:
fnOldScr[i] = (WNDPROC) SetWindowLong ( hwndScrol[i], GWL_WNDPROC, (LONG) ScrollProc) ;
第一个参数hWndScrol为滚动条的名称,第三个参数ScrollProc则为指向滚动条消息处理函数的指针。
创建滚动条后,需要对它初始化,包括设置滚动条的初始位置以及滚动条滚动的范围,代码如下:
SetScrollRange (hwndScrol[i], SB_CTL, 0, 255,FALSE) ;
//设置滚动条初始位置
SetScrollPos (hwndScrol[i], SB_CTL, 20,FALSE) ;
其中,SetScrollRange函数的原型定义如下:
BOOL SetScrollRange(HWND hwnd,//指向父窗口的句柄
          Int nBar,//滚动条的活动状态
          Int nMinPos, //最小值
          int nMaxPos, //最大值
          BOOL bRedraw //重画的标志);
SetScrollPos用来设置滚动条初始位置值,原型定义如下:
int SetScrollPos( HWND hwnd ,//指向父窗口的句柄
         int nBar, // 设置滚动条的活动状态
         int nPos, // 设置滚动条位置值
         BOOL bRedraw //重画的标志 );
当SetScrollPos函数执行成功后,将返回原来的位置值。初始化滚动条后,滚动条就能响应用户的操作,这些操作包括用户按下PageDown、PageUp以及方向键,而鼠标的拖动则由滚动条自动处理。
滚动条消息处理的代码如下:
case WM_HSCROLL:
I=GetWindowLong((HWND)lParam,GWL_ID);
SWitCh(LOWORD (Wpgram))
{
  case SB_PAGEDOWN:
  color[i]+=15
  代码中首先判断用户操作的消息类型是否为WMNSCROLL,注意,如果创建滚动条时定义的风格为SB_VERT,则该消息类型应该为WM_VSCROLL。然后得到当前滚动条的标识符,消息中参数wParam的低位字节包含了消息的通知代码,例如程序中的SB_ PAGEDOWN、SB_PAGEUP、SB_LINEDOWN、SB_TOP。它们分别表示用户对键盘的操作。滚动条每次拖动的步长为15。
程序运行结果如图所示。

按钮控件实例2
#include <windows.h>
#define IDE_AUTOCHECKBOX 100
#define IDE_AUTORADIOBUTTON 200
#define IDE_AUTO3STATE 300
#define IDE_CHECKBOX 400
#define IDE_DEFPUSHBUTTON 500
#define IDE_PUSHBUTTON 600
#define IDE_RADIOBUTTON 700
HWND hWnd;
HWND hCtlButton[8];
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int);
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
  WNDCLASSEX wcex;
  wcex.cbSize = sizeof(WNDCLASSEX);
  wcex.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
  wcex.lpfnWndProc = (WNDPROC)WndProc;
  wcex.cbClsExtra = 0;
  wcex.cbWndExtra = 0;
  wcex.hInstance = hInstance;
  wcex.hIcon= LoadIcon(NULL,(LPCTSTR)IDI_APPLICATION);
  wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
  wcex.hbrBackground = (HBRUSH)COLOR_WINDOW;
  wcex.lpszMenuName = NULL;
  wcex.lpszClassName = "WndCls";
  wcex.hIconSm = LoadIcon(NULL,(LPCTSTR)IDI_APPLICATION);
  if(!RegisterClassEx(&wcex)) return FALSE;
  int SW_XFS = GetSystemMetrics(SM_CXSCREEN);
  int SW_YFS = GetSystemMetrics(SM_CYSCREEN);
  hWnd = CreateWindowEx(NULL,
             "WndCls",
             "Demo of Button Control",
             WS_OVERLAPPEDWINDOW,
             0,
             0,
             SW_XFS,
             SW_YFS-25,
             NULL,
             NULL,
             hInstance,
             NULL);
  if(!hWnd) return FALSE;
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
?
  hCtlButton[0] = CreateWindowEx( NULL, "BUTTON", "自动复选框(方框)",
                  WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX,
                  10,
                  10,
                  200,
                  30,
                  hWnd,
                  (HMENU)IDE_AUTOCHECKBOX,
                  hInstance,
                  NULL);
  hCtlButton[1] = CreateWindowEx( NULL,"BUTTON",
                  "自动复选框(园框)",
                  WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON,
                  10, 40,200, 30,
                  hWnd,
                  (HMENU)IDE_AUTORADIOBUTTON,
                  hInstance,
                  NULL);
  hCtlButton[2] = CreateWindowEx( NULL,"BUTTON",
                  "自动复选框(园框)",
                  WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON,
                  10,70, 200,30,
                  hWnd,
                  (HMENU)IDE_AUTORADIOBUTTON,
                  hInstance,
                  NULL);
  hCtlButton[3] = CreateWindowEx( NULL,"BUTTON",
                  "三态复选框(方框)",
                  WS_CHILD|WS_VISIBLE|BS_AUTO3STATE,
                  10,100,200,30,
                  hWnd,
                  (HMENU)IDE_AUTO3STATE,
                  hInstance,
                  NULL);
  hCtlButton[4] = CreateWindowEx(NULL,"BUTTON",
                  "复选框(方框)",
                  WS_CHILD|WS_VISIBLE|BS_CHECKBOX,
                  10,130,200,30,
                  hWnd,
                  (HMENU)IDE_CHECKBOX,
                  hInstance,
                  NULL);
  hCtlButton[5] = CreateWindowEx(NULL,"BUTTON",
                  “下压式按钮”,
                  WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
                  10,160,200,30,
                  hWnd,
                  (HMENU)IDE_DEFPUSHBUTTON,
                  hInstance,
                  NULL);
  hCtlButton[6] = CreateWindowEx(NULL,"BUTTON",
                  “下压式按钮”,
                  WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
                  10,190,200,30,
                  hWnd,
                  (HMENU)IDE_PUSHBUTTON,
                  hInstance,
                  NULL);
  hCtlButton[7] = CreateWindowEx(NULL,"BUTTON",
                  “复选框(园框)”,
                  WS_CHILD|WS_VISIBLE|BS_RADIOBUTTON,
                  10,220,200,30,
                  hWnd,
                  (HMENU)IDE_RADIOBUTTON,
                  hInstance,
                  NULL);
  MSG msg;

  while(GetMessage(&msg,NULL,0,0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
  switch(message)
  {
    case WM_DESTROY:
    PostQuitMessage(0);
    break;

    default:
    return DefWindowProc(hWnd,message,wParam,lParam);
  }
  return 0;
}