windows程序设计——子视窗控制项

我们以一个窗口作为消息处理的主体,除了鼠标、键盘、定时器外,窗口中的子窗口发送的消息也可作为一种输入。当子窗口的自身处理消息,在必要时给父窗口发送消息,相当于父窗口的的高阶输入设备,这个称为"子视窗控制项"。常见的有:按钮、核取方块、编辑方块、清单方块、下拉式清单方块、字串标签和卷动列等,windows为这些基本项目都编写了默认的处理代码,我们只需要在主窗口中获取并处理(WM_COMMAND)消息就好了。

按钮是一类子视窗,使用方法如下:

/*----------------------------------------
   BTNLOOK.C -- Button Look Program
                (c) Charles Petzold, 1998
  ----------------------------------------*/

#include <windows.h>

//定义按钮的风格和文本信息结构,并初始化
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 ("RADIOBUTTON"),     //单选按钮,不常用
     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])

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

//建立窗口框架
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("BtnLook") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     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 ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Button Look"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     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 HWND  hwndButton[NUM] ; //子窗口句柄
     static RECT  rect ;
     static TCHAR szTop[]    = TEXT ("message            wParam       lParam"),
                  szUnd[]    = TEXT ("_______            ______       ______"),
                  szFormat[] = TEXT ("%-16s%04X-%04X    %04X-%04X"),
                  szBuffer[50] ;
     static int   cxChar, cyChar ;
     HDC          hdc ;
     PAINTSTRUCT  ps ;
     int          i ;
     
     switch (message)
     {
     case WM_CREATE : //创建窗口的时候建立子窗体(各种风格的按钮)
          // 获取字体大小,函数GetDialogBaseUnits只在对话框中起作用正常窗体还用的GetTextMetrics
          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, //子视窗ID
                                   ((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, lstrlen (szTop)) ;
          TextOut (hdc, 24 * cxChar, cyChar, szUnd, lstrlen (szUnd)) ;
          
          EndPaint (hwnd, &ps) ;
          return 0 ;
          
     case WM_DRAWITEM : //子窗口自绘消息
     case WM_COMMAND : //响应子视窗消息
          //令窗口在rect中向上滚动cyChar
          ScrollWindow (hwnd, 0, -cyChar, &rect, &rect) ;
          //获取dc,并选入SYSTEM_FIXED_FONT字体
          hdc = GetDC (hwnd) ;
          SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
          //在最后一行输出消息类型和参数
          TextOut (hdc, 24 * cxChar, cyChar * (rect.bottom / cyChar - 1),
                   szBuffer,
                   wsprintf (szBuffer, szFormat,
                         message == WM_DRAWITEM ? TEXT ("WM_DRAWITEM") : TEXT ("WM_COMMAND"),
                         HIWORD (wParam), LOWORD (wParam),
                         HIWORD (lParam), LOWORD (lParam))) ;
          //释放DC,并刷新界面
          ReleaseDC (hwnd, hdc) ;
          ValidateRect (hwnd, &rect) ;
          break ;
          
     case WM_DESTROY : //销毁窗口
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}
子视窗想父窗口发送WM_COMMAND消息,结果如下:

通知码说明如下:



而父窗口也可以向子窗口发送信息,来控制或获得子窗口,消息如下:


父窗口中通常使用下列方法来控制子窗口:

//通过句柄获取id
id = GetWindowLong (hwndChild, GWL_ID) ;
id = GetDlgCtrlID (hwndChild) ;
//通过id获取句柄
hwndChild = GetDlgItem (hwndParent, id) ;
//模拟按下按钮和不再按下
SendMessage (hwndButton, BM_SETSTATE, 1, 0) ;
SendMessage (hwndButton, BM_SETSTATE, 0, 0) ;
//发送选中和不再选中信息(单选,复选)
SendMessage (hwndButton, BM_SETCHECK, 1, 0) ;
SendMessage (hwndButton, BM_SETCHECK, 0, 0) ;
//获取是否选中
iCheck = (int) SendMessage (hwndButton, BM_GETCHECK, 0, 0) ;
//获得和设置子窗口的文本信息
SetWindowText (hwnd, pszString) ;
iLength = GetWindowText (hwnd, pszBuffer, iMaxLength) ;
iLength = GetWindowTextLength (hwnd) ;
//设置和获得是否可见
ShowWindow (hwndChild, SW_SHOWNORMAL) ;
ShowWindow (hwndChild, SW_HIDE) ;
IsWindowVisible (hwndChild) ;
//设置和获得是否可用
EnableWindow (hwndChild, FALSE) ;
EnableWindow (hwndChild, TRUE) ;
IsWindowEnabled (hwndChild) ;
//设置焦点
SetFocus (hwnd) ;
//设置背景和文字颜色
SetBkColor (hdc, GetSysColor (COLOR_BTNFACE)) ;
SetTextColor (hdc, GetSysColor (COLOR_WINDOWTEXT)) ;
虽然没什么用处但是可以通过响应WM_CTLCOLORBTN消息来改变背景和文字的颜色,更通常的做法是使用BS_OWNERDRAW风格的按钮在drawitem中自己绘制:

/*---------------------------------------------
   OWNDRAW.C -- Owner-Draw Button Demo Program
                (c) Charles Petzold, 1998
  ---------------------------------------------*/

#include <windows.h>

//定义两个窗口ID
#define ID_SMALLER      1
#define ID_LARGER       2
//按钮宽高为字体的宽高8倍和4倍
#define BTN_WIDTH        (8 * cxChar)
#define BTN_HEIGHT       (4 * cyChar)

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

HINSTANCE hInst ;
//建立框架
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("OwnDraw") ;
     MSG          msg ;
     HWND         hwnd ;
     WNDCLASS     wndclass ;
     
     hInst = hInstance ;
     
     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  = szAppName ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Owner-Draw Button Demo"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ; 
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

//画黑色三角形
void Triangle (HDC hdc, POINT pt[])
{
     SelectObject (hdc, GetStockObject (BLACK_BRUSH)) ;
     Polygon (hdc, pt, 3) ;
     SelectObject (hdc, GetStockObject (WHITE_BRUSH)) ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HWND      hwndSmaller, hwndLarger ;
     static int       cxClient, cyClient, cxChar, cyChar ;
     int              cx, cy ;
     LPDRAWITEMSTRUCT pdis ;
     POINT            pt[3] ;
     RECT             rc ;
     
     switch (message)
     {
     case WM_CREATE :
          //字体宽高
          cxChar = LOWORD (GetDialogBaseUnits ()) ;
          cyChar = HIWORD (GetDialogBaseUnits ()) ;
          
          // 创建两个BS_OWNERDRAW风格的按钮
          hwndSmaller = CreateWindow (TEXT ("button"), TEXT (""),
                                      WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
                                      0, 0, BTN_WIDTH, BTN_HEIGHT,
                                      hwnd, (HMENU) ID_SMALLER, hInst, NULL) ;
          
          hwndLarger  = CreateWindow (TEXT ("button"), TEXT (""),
                                      WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
                                      0, 0, BTN_WIDTH, BTN_HEIGHT,
                                      hwnd, (HMENU) ID_LARGER, hInst, NULL) ;
          return 0 ;
          
     case WM_SIZE :
          //获取窗体大小
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
          
          // 把按钮设置到最中心
          MoveWindow (hwndSmaller, cxClient / 2 - 3 * BTN_WIDTH  / 2,
                                   cyClient / 2 -     BTN_HEIGHT / 2,
                      BTN_WIDTH, BTN_HEIGHT, TRUE) ;
          
          MoveWindow (hwndLarger,  cxClient / 2 +     BTN_WIDTH  / 2,
                                   cyClient / 2 -     BTN_HEIGHT / 2,
                      BTN_WIDTH, BTN_HEIGHT, TRUE) ;
          return 0 ;
          
     case WM_COMMAND :
          GetWindowRect (hwnd, &rc) ;
          
          // 判断点击的是那个窗口来决定放大还是缩小
          switch (wParam)
          {
          case ID_SMALLER :
               rc.left   += cxClient / 20 ;
               rc.right  -= cxClient / 20 ;
               rc.top    += cyClient / 20 ;
               rc.bottom -= cyClient / 20 ;
               break ;
               
          case ID_LARGER :
               rc.left   -= cxClient / 20 ;
               rc.right  += cxClient / 20 ;
               rc.top    -= cyClient / 20 ;
               rc.bottom += cyClient / 20 ;
               break ;
          }
          //改变窗口大小
          MoveWindow (hwnd, rc.left, rc.top, rc.right  - rc.left,
                            rc.bottom - rc.top, TRUE) ;
          return 0 ;
          
     case WM_DRAWITEM : //BS_OWNERDRAW风格的自绘消息
          pdis = (LPDRAWITEMSTRUCT) lParam ;
          
          //填充背景和画边框
          FillRect (pdis->hDC, &pdis->rcItem,
                    (HBRUSH) GetStockObject (WHITE_BRUSH)) ;
          
          FrameRect (pdis->hDC, &pdis->rcItem,
                     (HBRUSH) GetStockObject (BLACK_BRUSH)) ;
          
          //获取子窗口的宽度
          cx = pdis->rcItem.right  - pdis->rcItem.left ;
          cy = pdis->rcItem.bottom - pdis->rcItem.top  ;
          
          switch (pdis->CtlID)
          {
          case ID_SMALLER : //若是缩小按钮
               pt[0].x = 3 * cx / 8 ;  pt[0].y = 1 * cy / 8 ;
               pt[1].x = 5 * cx / 8 ;  pt[1].y = 1 * cy / 8 ;
               pt[2].x = 4 * cx / 8 ;  pt[2].y = 3 * cy / 8 ;
               
               Triangle (pdis->hDC, pt) ;
               
               pt[0].x = 7 * cx / 8 ;  pt[0].y = 3 * cy / 8 ;
               pt[1].x = 7 * cx / 8 ;  pt[1].y = 5 * cy / 8 ;
               pt[2].x = 5 * cx / 8 ;  pt[2].y = 4 * cy / 8 ;
               
               Triangle (pdis->hDC, pt) ;
               
               pt[0].x = 5 * cx / 8 ;  pt[0].y = 7 * cy / 8 ;
               pt[1].x = 3 * cx / 8 ;  pt[1].y = 7 * cy / 8 ;
               pt[2].x = 4 * cx / 8 ;  pt[2].y = 5 * cy / 8 ;
               
               Triangle (pdis->hDC, pt) ;
               
               pt[0].x = 1 * cx / 8 ;  pt[0].y = 5 * cy / 8 ;
               pt[1].x = 1 * cx / 8 ;  pt[1].y = 3 * cy / 8 ;
               pt[2].x = 3 * cx / 8 ;  pt[2].y = 4 * cy / 8 ;
               
               Triangle (pdis->hDC, pt) ;
               break ;
               
          case ID_LARGER : //若是放大按钮
               pt[0].x = 5 * cx / 8 ;  pt[0].y = 3 * cy / 8 ;
               pt[1].x = 3 * cx / 8 ;  pt[1].y = 3 * cy / 8 ;
               pt[2].x = 4 * cx / 8 ;  pt[2].y = 1 * cy / 8 ;
               
               Triangle (pdis->hDC, pt) ;
               
               pt[0].x = 5 * cx / 8 ;  pt[0].y = 5 * cy / 8 ;
               pt[1].x = 5 * cx / 8 ;  pt[1].y = 3 * cy / 8 ;
               pt[2].x = 7 * cx / 8 ;  pt[2].y = 4 * cy / 8 ;
               
               Triangle (pdis->hDC, pt) ;
               
               pt[0].x = 3 * cx / 8 ;  pt[0].y = 5 * cy / 8 ;
               pt[1].x = 5 * cx / 8 ;  pt[1].y = 5 * cy / 8 ;
               pt[2].x = 4 * cx / 8 ;  pt[2].y = 7 * cy / 8 ;
               
               Triangle (pdis->hDC, pt) ;
               
               pt[0].x = 3 * cx / 8 ;  pt[0].y = 3 * cy / 8 ;
               pt[1].x = 3 * cx / 8 ;  pt[1].y = 5 * cy / 8 ;
               pt[2].x = 1 * cx / 8 ;  pt[2].y = 4 * cy / 8 ;
               
               Triangle (pdis->hDC, pt) ;
               break ;
          }
          
          // Invert the rectangle if the button is selected
          //判断是否按下,若按下则整个按钮设为反色
          if (pdis->itemState & ODS_SELECTED)
               InvertRect (pdis->hDC, &pdis->rcItem) ;
          
          // Draw a focus rectangle if the button has the focus
          // 判断是否有焦点,若有焦点则画焦点矩形
          if (pdis->itemState & ODS_FOCUS)
          {
               pdis->rcItem.left   += cx / 16 ;
               pdis->rcItem.top    += cy / 16 ;
               pdis->rcItem.right  -= cx / 16 ;
               pdis->rcItem.bottom -= cy / 16 ;
               
               DrawFocusRect (pdis->hDC, &pdis->rcItem) ;
          }
          return 0 ;
          
     case WM_DESTROY :
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}
除了自绘还可以通过SetWindowLong函数来子类化对象:

/*----------------------------------------
   COLORS1.C -- Colors Using Scroll Bars
                (c) Charles Petzold, 1998
  ----------------------------------------*/

#include <windows.h>

//声明窗口处理函数和滚动条消息的处理函数
LRESULT CALLBACK WndProc    (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK ScrollProc (HWND, UINT, WPARAM, LPARAM) ;
//被设为焦点的子窗id,和原先的滚动条回调函数
int     idFocus ;
WNDPROC OldScroll[3] ;

//建立框架
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("Colors1") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     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 = CreateSolidBrush (0) ; //背景为白色
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Color Scroll"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     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 COLORREF crPrim[3] = { RGB (255, 0, 0), RGB (0, 255, 0),
                                   RGB (0, 0, 255) } ; //三原色
     static HBRUSH  hBrush[3], hBrushStatic ; //三个画刷
     static HWND    hwndScroll[3], hwndLabel[3], hwndValue[3], hwndRect ; //滚动条,title,值,方块的子窗口句柄
     static int     color[3], cyChar ;
     static RECT    rcColor ;
     static TCHAR * szColorLabel[] = { TEXT ("Red"), TEXT ("Green"), 
                                       TEXT ("Blue") } ;
     HINSTANCE      hInstance ;
     int            i, cxClient, cyClient ;
     TCHAR          szBuffer[10] ;
     
     switch (message)
     {
     case WM_CREATE : //创建窗口
          hInstance = (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE) ;
          
          // Create the white-rectangle window against which the 
          // scroll bars will be positioned. The child window ID is 9.
		  //创建一个SS_WHITERECT空白的static子窗口
          hwndRect = CreateWindow (TEXT ("static"), NULL,
                                   WS_CHILD | WS_VISIBLE | SS_WHITERECT,
                                   0, 0, 0, 0,
                                   hwnd, (HMENU) 9, hInstance, NULL) ;
          
          for (i = 0 ; i < 3 ; i++)
          {
               // The three scroll bars have IDs 0, 1, and 2, with
               // scroll bar ranges from 0 through 255.
               //创建三个SBS_VERT竖立的滚动条
               hwndScroll[i] = CreateWindow (TEXT ("scrollbar"), NULL,
                                             WS_CHILD | WS_VISIBLE | 
                                             WS_TABSTOP | SBS_VERT,
                                             0, 0, 0, 0, 
                                             hwnd, (HMENU) i, hInstance, NULL) ;
               //设置范围和初始值
               SetScrollRange (hwndScroll[i], SB_CTL, 0, 255, FALSE) ;
               SetScrollPos   (hwndScroll[i], SB_CTL, 0, FALSE) ;
               
               // The three color-name labels have IDs 3, 4, and 5, 
               // and text strings "Red", "Green", and "Blue".
               //创建三个static子控件作为说明
               hwndLabel [i] = CreateWindow (TEXT ("static"), szColorLabel[i],
                                             WS_CHILD | WS_VISIBLE | SS_CENTER,
                                             0, 0, 0, 0, 
                                             hwnd, (HMENU) (i + 3), 
                                             hInstance, NULL) ;
               
               // The three color-value text fields have IDs 6, 7, 
               // and 8, and initial text strings of "0".
               //创建三个static显示各自滚动条所表示的RGB值
               hwndValue [i] = CreateWindow (TEXT ("static"), TEXT ("0"),
                                             WS_CHILD | WS_VISIBLE | SS_CENTER,
                                             0, 0, 0, 0,
                                             hwnd, (HMENU) (i + 6), 
                                             hInstance, NULL) ;
               //将滚动条的处理函数设置为ScrollProc,并将原先的处理函数保存到OldScroll中
               OldScroll[i] = (WNDPROC) SetWindowLong (hwndScroll[i], 
                                             GWL_WNDPROC, (LONG) ScrollProc) ;
               //创建三个原色的画刷
               hBrush[i] = CreateSolidBrush (crPrim[i]) ;
          }
          //创建画刷
          hBrushStatic = CreateSolidBrush (
                              GetSysColor (COLOR_BTNHIGHLIGHT)) ;
          //字体高度
          cyChar = HIWORD (GetDialogBaseUnits ()) ;
          return 0 ;
          
     case WM_SIZE : //窗口大小改变时重设子控件位置
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
          
          SetRect (&rcColor, cxClient / 2, 0, cxClient, cyClient) ;
          
          MoveWindow (hwndRect, 0, 0, cxClient / 2, cyClient, TRUE) ;
          
          for (i = 0 ; i < 3 ; i++)
          {
               MoveWindow (hwndScroll[i],
                           (2 * i + 1) * cxClient / 14, 2 * cyChar,
                           cxClient / 14, cyClient - 4 * cyChar, TRUE) ;
               
               MoveWindow (hwndLabel[i],
                           (4 * i + 1) * cxClient / 28, cyChar / 2,
                           cxClient / 7, cyChar, TRUE) ;
               
               MoveWindow (hwndValue[i],
                           (4 * i + 1) * cxClient / 28, 
                           cyClient - 3 * cyChar / 2,
                           cxClient / 7, cyChar, TRUE) ;
          }
          SetFocus (hwnd) ;
          return 0 ;
          
     case WM_SETFOCUS ://将焦点设置为某个滚动条
          SetFocus (hwndScroll[idFocus]) ;
          return 0 ;
          
     case WM_VSCROLL : //当滚动条滚动时
          //获取子控件id
          i = GetWindowLong ((HWND) lParam, GWL_ID) ;
          //计算滚动条的值
          switch (LOWORD (wParam))
          {
          case SB_PAGEDOWN :
               color[i] += 15 ;
                                             // fall through
          case SB_LINEDOWN :
               color[i] = min (255, color[i] + 1) ;
               break ;
               
          case SB_PAGEUP :
               color[i] -= 15 ;
                                             // fall through
          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 ;
          }
          //设置滚动条位置,并设置static的文本信息
          SetScrollPos  (hwndScroll[i], SB_CTL, color[i], TRUE) ;
          wsprintf (szBuffer, TEXT ("%i"), color[i]) ;
          SetWindowText (hwndValue[i], szBuffer) ;
          //重设方块的背景画刷
          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 : //标题和值static控件的文本和背景颜色
          i = GetWindowLong ((HWND) lParam, GWL_ID) ;
               
          if (i >= 3 && i <= 8)    // static text controls
          {
               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 : //窗口销毁时清理创建的object
          DeleteObject ((HBRUSH)
               SetClassLong (hwnd, GCL_HBRBACKGROUND, (LONG) 
                    GetStockObject (WHITE_BRUSH))) ;
               
          for (i = 0 ; i < 3 ; i++)
               DeleteObject (hBrush[i]) ;
               
          DeleteObject (hBrushStatic) ;
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}
     
LRESULT CALLBACK ScrollProc (HWND hwnd, UINT message, 
                             WPARAM wParam, LPARAM lParam)
{
     int id = GetWindowLong (hwnd, GWL_ID) ;
     //通过键盘来改变焦点
     switch (message)
     {
     case WM_KEYDOWN :
          if (wParam == VK_TAB)
               SetFocus (GetDlgItem (GetParent (hwnd), 
                    (id + (GetKeyState (VK_SHIFT) < 0 ? 2 : 1)) % 3)) ;
          break ;
               
     case WM_SETFOCUS :
          idFocus = id ;
          break ;
     }
     return CallWindowProc (OldScroll[id], hwnd, message, wParam, lParam) ;
}
与static子窗口不同,edit是可以让用户编辑文本信息的控件。edit给父窗口的控件发送的消息说明如下:

而父窗口通过如下接口控制edit:

//剪切,复制,删除,黏贴
SendMessage (hwndEdit, WM_CUT, 0, 0) ;
SendMessage (hwndEdit, WM_COPY, 0, 0) ;
SendMessage (hwndEdit, WM_CLEAR, 0, 0) ;
SendMessage (hwndEdit, WM_PASTE, 0, 0) ;
//获取和设置选择区域
SendMessage (hwndEdit, EM_GETSEL, (WPARAM) &iStart, (LPARAM) &iEnd) ;
SendMessage (hwndEdit, EM_SETSEL, iStart, iEnd) ;
//替换文字
SendMessage (hwndEdit, EM_REPLACESEL, 0, (LPARAM) szString) ;
//取得行数
iCount = SendMessage (hwndEdit, EM_GETLINECOUNT, 0, 0) ;
//取得光标对于行头的编译量
iOffset = SendMessage (hwndEdit, EM_LINEINDEX, iLine, 0) ;
//取得当前行的长度
iLength = SendMessage (hwndEdit, EM_LINELENGTH, iLine, 0) ;
//取得获取当前行到缓冲区
iLength = SendMessage (hwndEdit, EM_GETLINE, iLine, (LPARAM) szBuffer) ;
listbox也是一个常用的控件:

/*----------------------------------------
   ENVIRON.C -- Environment List Box
                (c) Charles Petzold, 1998
  ----------------------------------------*/

#include <windows.h>

#define ID_LIST     1
#define ID_TEXT     2

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

//主函数建立框架
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("Environ") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     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) (COLOR_WINDOW + 1) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Environment List Box"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

//填充listbox
void FillListBox (HWND hwndList) 
{
     int     iLength ;
     TCHAR * pVarBlock, * pVarBeg, * pVarEnd, * pVarName ;
     // 获取环境变量
     pVarBlock = GetEnvironmentStrings () ;  // Get pointer to environment block
     // 拆分字符串
     while (*pVarBlock)
     {
          if (*pVarBlock != '=')   // Skip variable names beginning with '='
          {
               pVarBeg = pVarBlock ;              // Beginning of variable name
               while (*pVarBlock++ != '=') ;      // Scan until '='
               pVarEnd = pVarBlock - 1 ;          // Points to '=' sign
               iLength = pVarEnd - pVarBeg ;      // Length of variable name

               // Allocate memory for the variable name and terminating
               // zero. Copy the variable name and append a zero.

               pVarName = calloc (iLength + 1, sizeof (TCHAR)) ;
               CopyMemory (pVarName, pVarBeg, iLength * sizeof (TCHAR)) ;
               pVarName[iLength] = '\0' ;

               // Put the variable name in the list box and free memory.
               // 添加到listbox中
               SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM) pVarName) ;
               free (pVarName) ;
          }
          while (*pVarBlock++ != '\0') ;     // Scan until terminating zero
     }
     FreeEnvironmentStrings (pVarBlock) ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HWND  hwndList, hwndText ;
     int          iIndex, iLength, cxChar, cyChar ;
     TCHAR      * pVarName, * pVarValue ;

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

          // Create listbox and static text windows.
          
          hwndList = CreateWindow (TEXT ("listbox"), NULL,
                              WS_CHILD | WS_VISIBLE | LBS_STANDARD,
                              cxChar, cyChar * 3,
                              cxChar * 16 + GetSystemMetrics (SM_CXVSCROLL),
                              cyChar * 5,
                              hwnd, (HMENU) ID_LIST,
                              (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
                              NULL) ;
          
          hwndText = CreateWindow (TEXT ("static"), NULL,
                              WS_CHILD | WS_VISIBLE | SS_LEFT,
                              cxChar, cyChar, 
                              GetSystemMetrics (SM_CXSCREEN), cyChar,
                              hwnd, (HMENU) ID_TEXT,
                              (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
                              NULL) ;
          //填充listbox
          FillListBox (hwndList) ;
          return 0 ;
          
     case WM_SETFOCUS :
          SetFocus (hwndList) ;
          return 0 ;
          
     case WM_COMMAND :
          if (LOWORD (wParam) == ID_LIST && HIWORD (wParam) == LBN_SELCHANGE)
          {
               // Get current selection.
               // 获取选中行,选中行的文本长度,根据长度申请内存,获取选中行的文本
               iIndex  = SendMessage (hwndList, LB_GETCURSEL, 0, 0) ;
               iLength = SendMessage (hwndList, LB_GETTEXTLEN, iIndex, 0) + 1 ;
               pVarName = calloc (iLength, sizeof (TCHAR)) ;
               SendMessage (hwndList, LB_GETTEXT, iIndex, (LPARAM) pVarName) ;

               // Get environment string.
               // 获取环境变量内容
               iLength = GetEnvironmentVariable (pVarName, NULL, 0) ;
               pVarValue = calloc (iLength, sizeof (TCHAR)) ;
               GetEnvironmentVariable (pVarName, pVarValue, iLength) ;

               // Show it in window.
               
               SetWindowText (hwndText, pVarValue) ;
               free (pVarName) ;
               free (pVarValue) ;
          }
          return 0 ;

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值