第9章 子窗口控件_9.1-9.3按钮类、控件颜色、静态类

(1)子窗口控件:①子窗口,其parent为父窗口句柄;②子窗口状态发生变化时,会处理鼠标和键盘消息,并且通知其父窗口。可分为自定义子窗口控件和标准的子窗口控件(如按钮)

(2)子窗口控件的使用场合

  ①在对话框里使用最广——有内在机制支持Tab和光标移动键来转移焦点。

②在窗口表面直接使用:没内在机制支持Tab键和光标移动键来移动焦点到另一个控件;

对于自定义的控件,当单击子窗口时,父窗口会得到焦点。但对于标准子窗口控件,单击时会自动获得焦点(估计子窗口过程内部在WM_LBUTTONDOWN中实现了SetFocus(hwnd)了)。不管是哪类子窗口,都可以得到输入焦点,但一旦得到焦点,它自己无法把输入焦点交回给其父窗口。(可以通过窗口子类化来达到目的)。

(3)子窗口的销毁:在父窗口销毁的同时,会自动销毁子窗口,程序不必自己处理。

9.1 按钮类

9.1.1 创建子窗口:CreateWindow各参数设置

参数

备注

lpClassName

Text(“button”)

预定义的名称,不可更改

lpWindowName

button[i].szText

按钮上显示的文本

dwStyle

WS_CHILE|WS_VISIBLE|button[i].style

x

cxChar

相对于父窗口客户区左上角

y

cyChar*(1+2*i)

相对于父窗口客户区左上角

nWidth

20*xChar

nHeight

7*yChar/4

hWndParent

Hwnd

hMenu

(HMENU)i

子窗口ID,每个窗口唯一

hInstance

((LPCREATESTRUCT)lParam)->hInstance

WM_CREATE的lParam指向一个CREATESTRUCT结构,可从中获得hInstance句柄

lpParam

NULL

额外参数

★获取hInstance的4种方法:

  ①设置全局变量hInst,在WinMain函数中 hInst = hInstance;

②hInstance =GetWindowLong(hwnd,GWL_INSTANCE);

③在WM_CREATE消息中从lParam中获取:hInstance = ((LPCREATESTRUCT)lParam)->hInstance

④hInstance =GetModuleHandle(NULL);

9.1.2 子窗口传递信息给父窗口

(1)子窗口过程获取父窗口句柄的方法:hwndParent =GetParent(hwnd);

(2)子窗口向父窗口过程发送消息:SendMessage(hwndParent,message,wParam,lParam);

      ★注意发送自定义消息时:message可以是大于等于WM_USER的任何值。

              wParam:可设为子窗口ID。

              lParam:可设置额外的信息。

(3)单击按钮,子窗口会向父窗口发送WM_COMMAND消息。各参数如下

参数

备注

lParam

子窗口句柄

wParam

LOWORD(wParam) :子窗口ID

HIWORD(wParam):通知码

通知码以BN_开头,表示消息传输的方向是给父窗口的通知消息。

BN_CLICKED                   (0)

释放鼠标时发生

BN_PAINT                     (1)

为过时的按钮样式BS_USERBUTTON所用(己被BS_OWNERDRAW和另一套通知机制取代)

BN_HILITE或BN_PUSHED        (2)

BN_UNHILITE或BN_UNPUSHED    (3)

BN_DISABLE                   (4)

BN_DOUBLECLICKED或BN_DBLCLK (5)

仅用于BS_RADIOBUTTON、BS_AUTORADIOBUTTON和BS_OWNERDRAW或BS_NOTIFY的按钮使用

BN_SETFOCUS                  (6)

仅用于BS_NOTIFY样式的按钮

BN_KILLFOCUS                 (7)

9.1.3 父窗口传递信息给子窗口:按钮消息以BM_开头(不是WM_开头的)

(1)获取子窗口ID或子窗口句柄或方法

     ①id = GetWindowLong(hwndChild,GWL_ID)或 id =GetDlgCtrlID(hwndChild)

②hwndChild = GetDlgItem(hwndParent,id);

(2)SentMessage的message(消息)设置

按钮消息

备注

BM_GETCHECK      (0x00F0)

单击或复选框按钮

BM_SETCHECK      (0x00F1)

BM_GETSTATE      (0x00F2)

返回

BST_CHECKED:被单击

BST_FOCUS:具有输入焦点

BST_PUSHED:按住鼠标

……

BM_SETSTATE      (0x00F3)

BM_CLICK         (0x00F4)

模拟按钮单击

BM_GETIMAGE      (0x00F5)

BM_SETIMAGE      (0x00F6)

9.1.4 按钮

(1)按键按钮的最佳视觉高度:字符高度的7/4。宽度:文本宽度 + 2个字符宽度。

(2)模拟按键按钮的状态

①按住状态:SendMessage(hwndButton,BM_SETSTATE,1,0);

②正常状态:SendMessage(hwndButton,BM_SETSTATE,0,0);

9.1.5 复选框

样式

状态

BS_CHECKBOX

1、SendMessage(hwndButton,BM_SETCHECK,1,0); //选中

2、SendMessage(hwndButton,BM_SETCHECK,0,0); //取消选中

3、SendMessage((HWND)lParam,BM_SETCHECK,(WPARAM)   //切换

!SendMessage((HWND)lParam,BM_GETCHECK,0,0),0);

BS_AUTOCHECKBOX

1、自动切换

2、获取状态:iCheck = (int)SendMessage(hwndButton,BM_GETCHECK,0,0);

BS_3STATE

SendMessage(hwndButton,BM_SETCHECK,2,0); //第3种状态

BS_AUTO3STATE

//自动切换

(1)宽度和高度:最低高度——1个字符的高度,最小宽度——字符数+2个字符的宽度。

(2)复选框中的文本位置及文本对齐

 

9.1.6 单选按钮——第二次单击时,不会状态切换,其状态保持不变

(1)BS_AUTORADIOBUTTON:

(2)BS_RADIOBUTTON:父窗口收到WM_COMMAND消息时,可以

选中单选按钮:SendMessage(hwndButton,BM_SETCHECK,1,0);

取消选中:    SendMessage(hwndButton,BM_SETCHECK,0,0);

9.1.7 组合框(Group Boxes)——不发送WM_COMMAND消息,也不接收鼠标和键盘消息。

9.1.8 改变按钮文本

(1)设置文本:SetWindowText(hwnd,pszString);

(2)获取文本: iLength = GetWindowTextLength(hwnd);//先获取文本长度

GetWindowText(hwnd,pszBuffer,iLength);//获取文本到指定缓冲区
 9.1.9 可见的按钮和启用的按钮

(1)显示子窗口:ShowWindow(hwndChild,SW_SHOWNORMAL); //窗口类没WS_VISIBLE时不显示。

(2)判断窗口可见性:IsWindowVisible(hwndChild);

(3)启用或禁用:EnableWindow(hwndChild,TRUE)或EnableWindow(hwndChild,FALSE);

(4)子窗口是否被启动:IsWindowEnabled(hwndChild);

 9.1.10 按钮或输入焦点

(1)单击鼠标时,按钮会自动得到焦点,键盘消息发往子窗口(即按钮的内部窗口过程)

①子窗口只对空格键做出响应(类似鼠标单击)

②父窗口失去对键盘处理的控制——解决方法就是窗口子类化

(2)当焦点从父窗口向子窗口转移时的消息顺序

①WM_KILLFOCUS发往父窗口,wParam为要获得焦口的窗口句柄。

②WM_SETFOCUS发往子窗口,wParam为失去焦点的窗口句柄。

(3)阻止子窗口获得输入焦点

方法1

方法2

case WM_KILLFOCUS:

      //NUM为子窗口的数目

      for (int i = 0; i < NUM;i++)

      {   //wParam为要获取焦点的窗口句柄

           if (hwndChild[i] == (HWND)wParam)

          {

                SetFocus(hwnd);

               break;

           }

      }

      return 0;

case WM_KILLFOCUS:

      //要获得焦点的是子窗口,则抢回焦点

      if (hwnd == GetParent((HWND)wParam))

      SetFocus(hwnd);//父窗口抢回焦点

      return 0;

【BtnLook程序】

 效果图:

 

/*------------------------------------------------------------
BTNLOOK.C -- Button Look Program
(c) Charles Petzold, 1998
------------------------------------------------------------*/
#include <windows.h>
struct
{
    int iStyle;    //按钮样式
    TCHAR* szText; //显示文本
}
button[] =
{
    BS_DEFPUSHBUTTON, 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("AutoRadioButton"),
    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,                  // window class name
        TEXT("Button Look"), // window caption
        WS_OVERLAPPEDWINDOW,        // window style
        CW_USEDEFAULT,              // initial x position
        CW_USEDEFAULT,              // initial y position
        CW_USEDEFAULT,              // initial x size
        CW_USEDEFAULT,              // initial y size
        NULL,                       // parent window handle
        NULL,                       // window menu handle
        hInstance,                  // program instance handle
        NULL);                     // creation parameters

    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)
{
    HDC         hdc;
    PAINTSTRUCT ps;
    static HWND hwndButton[NUM];
    static int cxChar, cyChar;
    static TCHAR szTop[] = TEXT("message            wParam       lParam"),
        szUnd[] = TEXT("_______            ______       ______"),
        szFormat[] = TEXT("%-16s%04X-%04X    %04X-%04X"),
        szBuffer[50];
    static RECT rect;
    switch (message)
    {
    case WM_CREATE:
        cxChar = LOWORD(GetDialogBaseUnits());//对话框基本单位,
        cyChar = HIWORD(GetDialogBaseUnits());//为系统字体字符的平均宽度和高度
        //创建NUM个按钮
        for (int i = 0; i < NUM; i++)
        {
            hwndButton[i] = CreateWindow(
                TEXT("button"),
                button[i].szText,
                WS_VISIBLE | WS_CHILD | button[i].iStyle,
                cxChar, cyChar*(1 + 2 * i), //每个按钮高度为7/4*cyChar,加1/4间隔,得2*cyChar
                20 * 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_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,
            message == WM_DRAWITEM ? TEXT("WM_DRAWITEM") :
            TEXT("WM_COMMAND"),
            HIWORD(wParam), LOWORD(wParam),
            HIWORD(lParam), LOWORD(lParam)));
        ReleaseDC(hwnd, hdc);
        ValidateRect(hwnd, &rect); //因为ScrollWindow会将生无效区,
        //而ValidateRect会将无效区有效化,阻止发送WM_PAINT消息。
        //如果注释掉ValidateRect,将引起不断的重绘。
        return 0;
    case WM_PAINT:
        /*
        1、窗口句柄(HWND)都是由操作系统内核管理的,系统内部有一个z-order序列,记录着当前从屏幕底部
        (假象的从屏幕到眼睛的方向),到屏幕最高层的一个窗口句柄的排序,这个排序不关注父窗口还
        是子窗口。当任意一个窗口接受到WM_PAINT消息产生重绘,更新区绘制完成以后,就搜索它的前面
        的一个窗口,如果此窗口的范围和更新区有交集,就向这个发送wm_paint消息,周而复始,直到执
        行到顶层窗口才算完成。
        2、主窗口接受WM_PAINT绘制完成后,会引起更新区上所有子窗口的重绘(所有子窗口也是从底到外排序的)
        3、子窗口无效不会引起父窗口重绘。父窗口无效,如果父窗口(没有WS_CLIPCHILDREN属性)收到WM_PAINT,
        则所有子窗口都会在父窗口处理WM_PAINT之后收到WM_PAINT重绘消息。当然,如果父窗口带有属性
        WS_CLIPCHILDREN,则不会引起子窗口重绘。
        */
        //以下将客户区刷白,因子窗口范围与无效区有交集,会导致子窗口重绘,因此本例中WM_DRAWITEM会被触发,
        //而WM_DRAWITEM过程中的SrollWindow会引起WM_PAINT,可在WM_DRAWITEM里,将无效区有效化,阻止
        //ScrollWindow引发的WM_PAINT,从而防止死循环。
        InvalidateRect(hwnd, NULL, TRUE);//因为在WM_COMMAND过程中绘制的内容,在WM_PAINT中无法重绘出来,
        //为防止主窗口被遮挡,再移开时,出现WM_COMMMAND中会制的无法重现,
        //最省事的做法是,那些内容全部不要了。
        hdc = BeginPaint(hwnd, &ps);     //将无效区有效化,阻止重复发送WM_PAINT消息。
        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_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

9.2 控件和颜色

(1)29种系统颜色:GetSysColor(SetSysColor)

常量索引值

注册表键值

默认RGB值

COLOR_SCROLLBAR

Scrollbar

C0-C0-C0

COLOR_BACKGROUND

Background

00-80-80

COLOR_ACTIVECAPTION

ActiveTile

00-00-80

COLOR_INACTIVECAPTION

InactiveTitle

80-80-80

COLOR_MENU

Menu

C0-C0-C0

COLOR_WINDOW

Window

FF-FF-FF

COLOR_WINDOWFRAME

WindowFrame

00-00-00

COLOR_MENUTEXT

MenuText

C0-C0-C0

COLOR_WINDOWTEXT

WindowText

00-00-00

COLOR_CAPTIONTEXT

TitleText

FF-FF-FF

COLOR_ACTIVEBORDER

ActiveBorder

C0-C0-C0

COLOR_INACTIVEBORDER

InactiveBorder

C0-C0-C0

COLOR_APPWORKSPACE

AppWorkspace

80-80-80

COLOR_HIGHLIGHT

Highlight

00-00-80

COLOR_HIGHLIGHTTEXT

HighlightText

FF-FF-FF

COLOR_BTNFACE

ButtonFace

C0-C0-C0

COLOR_BTNSHADOW

ButtonShadow

80-80-80

COLOR_GRAYTEXT

GrayText

80-80-80

COLOR_BTNTEXT

ButtonText

00-00-00

COLOR_INACTIVECAPTIONTEXT

InactiveTitleText

C0-C0-C0

COLOR_BTNHIGHLIGHT

ButtonHighlight

FF-FF-FF

COLOR_3DDKSHADOW

ButtonDkShadow

00-00-00

COLOR_3DLIGHT

ButtonLight

C0-C0-C0

COLOR_INFOTEXT

InfoText

00-00-00

COLOR_INFOBK

InfoWindow

FF-FF-FF

[没有标识符,使用值25]

ButtonAlternateFace

B8-B4-B8

COLOR_HOTLIGHT

HotTrackingColor

00-00-FF

COLOR_GRADIENTACTIVECAPTION

GradientActiveTitle

00-00-80

COLOR_GRADIENTINACTIVECAPTION

GradientInactiveTitle

80-80-80

(2)使用举例

    ①将客户区背景色设为COLOR_BTNFACE

wndClass.hbrBackground=(HBRUSH)(COLOR_BTNFACE + 1);

//注意:hbrBackground值很低时,指的是系统颜色,而不是实际的句柄。+1是为了防止NULL。

②TextOut显示的文本和其背景颜色

  SetBkColor(hdc,GetSysColor(COLOR_BTNFACE));

  SetTextColor(hdc,GetSysColor(COLOR_WINDOWTEXT));

(3)用户更改系统颜色,会发送WM_SYSCOLORCHANGE消息

     caseWM_SYSCOLORCHANGE:InvalidateRect(hwnd,NULL,TRUE);break;

9.2.2 按钮的颜色

颜色

说明

COLOR_BTNFACE

按钮主表面颜色或其他按钮的背景颜色

COLOR_BTNSHADOW

按钮右侧和底部的阴影颜色

COLOR_BTNTEXT

对按键按钮而言的,为上面的文本颜色

COLOR_WINDOWTEXT

其他控件的文本颜色

9.2.3 WM_CTLCOLORBTN消息:当子窗口即将重绘其客户区时,发送其给父窗口

wParam

按钮的设备环境句柄

lParam

按钮的窗口句柄

(1)只要按钮按钮和自绘按钮会发送WM_CTLCOLORBTN消息

(2)自绘按钮由父窗口过程来负责绘制

(3)处理WM_CTLCOLORBTN消息时,可以

①SetTextColor:设置文本颜色

②SetBkColor设置文本背景颜色

③返回子窗口的画刷句柄

9.2.4 自绘按钮Owner-Draw Button

(1)按钮风格

BS_ICON、BS_BITMAP

显示为一个图标或位图,可使用BM_SETIMAGE消息

BS_OWNERDRAW

可完全控制的绘制

(2)WM_DRAWITEM消息中的lParam参数——DRAWITEMSTRUCT结构

成员

常见值

备注

CtlType

ODT_BUTTON:  按钮控件

ODT_COMBOBOX:组合框控件

ODT_LISTBOX: 列表框控件

ODT_LISTVIEW:列表视图控件

ODT_MENU:    菜单项

ODT_STATIC:  静态文本控件

ODT_TAB:     Tab控件

控件类型

CtlID

自绘控件ID,而对于菜单项则不需要使用该成员

itemID

菜单项ID

itemAction

ODA_DRAWENTIRE:要整个控件被绘制,设置该值

ODA_FOCUS: 要在获得或失去焦点时被绘制。

ODA_SELECT:要在选中状态改变时被绘制。

指定绘制行为,其取值可以为右边中所示值的一个或者多个的联合

itemState

ODS_CHECKED:要菜单被选中,可设置该值

ODS_COMBOBOXEDIT:只绘制组合框中选择区域

ODS_DEFAULT:默认值

ODS_DISABLED:禁用控件

ODS_FOCUS:控件需要焦点,则该置该值

ODS_GRAYED:控件被灰色

ODS_SELECTED:选中的菜单项

……

所绘项的可见状态

hwndItem

自绘控件的窗口句柄;如果自绘的对象时菜单项,则表示包含该菜单项的菜单句柄。

hDC

指定了绘制操作所使用的设备环境

rcItem

指定了将被绘制的矩形区域

itemData

(3)自绘按钮坐标

 
 

(4)DrawFocusRect函数用来绘制虚线矩形

(5)DRAWITEMSTRUCT结构中的设备环境的状态必须保持原样,被选入hdc的GDI对象必须设置回原有的不被选中的状态。
【OwnerDraw程序】
效果图

 

/*------------------------------------------------------------
OWNDRAW.C -- Owner-Draw Button Demo Program
(c) Charles Petzold, 1998
------------------------------------------------------------*/
#include <windows.h>
#define ID_SMALLER 1
#define ID_LARGER  2
#define BTN_WIDTH  (8 * cxChar)
#define BTN_HEIGHT (4 * cyChar)
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("OwnDraw");
    HWND         hwnd;
    MSG          msg;
    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 = NULL;
    wndclass.lpszClassName = szAppName;
    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
            szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,                  // window class name
        TEXT("Owner-Draw Button Demo"), // window caption
        WS_OVERLAPPEDWINDOW,        // window style
        CW_USEDEFAULT,              // initial x position
        CW_USEDEFAULT,              // initial y position
        CW_USEDEFAULT,              // initial x size
        CW_USEDEFAULT,              // initial y size
        NULL,                       // parent window handle
        NULL,                       // window menu handle
        hInstance,                  // program instance handle
        NULL);                     // creation parameters

    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 cxClient, cyClient, cxChar, cyChar;
    DRAWITEMSTRUCT*  pdis;
    int cx, cy;
    POINT pt[3];
    RECT rc;

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

        //创建自绘PushButtons
        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 (LOWORD(wParam))
        {
            //每次10%放大或缩小窗口
        case ID_SMALLER:
            rc.left += cxClient / 20; //左边缩小5%
            rc.right -= cxClient / 20; //左边缩小5%
            rc.top += cyClient / 20; //上边缩小5%
            rc.bottom -= cyClient / 20; //下边缩小5%
            break;
        case ID_LARGER:
            rc.left -= cxClient / 20; //左边扩大5%
            rc.right += cxClient / 20; //左边扩大5%
            rc.top -= cyClient / 20; //上边扩大5%
            rc.bottom += cyClient / 20; //下边扩大5%
            break;
        }
        MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
        return 0;
    case WM_DRAWITEM:
        pdis = (LPDRAWITEMSTRUCT)lParam;
        //画白色矩形和黑色边框
        FillRect(pdis->hDC, &pdis->rcItem, GetStockObject(WHITE_BRUSH));
        FrameRect(pdis->hDC, &pdis->rcItem, 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 = 4 * cx / 8; pt[0].y = 5 * cy / 8;
            pt[1].x = 5 * cx / 8; pt[1].y = 7 * cy / 8;
            pt[2].x = 3 * cx / 8; pt[2].y = 7 * cy / 8;
            Triangle(pdis->hDC, pt);
            //左边的三角形
            pt[0].x = 1 * cx / 8; pt[0].y = 3 * cy / 8;
            pt[1].x = 3 * cx / 8; pt[1].y = 4 * cy / 8;
            pt[2].x = 1 * cx / 8; pt[2].y = 5 * cy / 8;
            Triangle(pdis->hDC, pt);
            //右边的三角形
            pt[0].x = 5 * cx / 8; pt[0].y = 4 * cy / 8;
            pt[1].x = 7 * cx / 8; pt[1].y = 3 * cy / 8;
            pt[2].x = 7 * cx / 8; pt[2].y = 5 * cy / 8;
            Triangle(pdis->hDC, pt);
            break;
        case ID_LARGER:
            //上边的三角形
            pt[0].x = 4 * cx / 8; pt[0].y = 1 * cy / 8;
            pt[1].x = 5 * cx / 8; pt[1].y = 3 * cy / 8;
            pt[2].x = 3 * cx / 8; pt[2].y = 3 * 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 = 1 * cx / 8; pt[0].y = 4 * cy / 8;
            pt[1].x = 3 * cx / 8; pt[1].y = 3 * cy / 8;
            pt[2].x = 3 * cx / 8; pt[2].y = 5 * cy / 8;
            Triangle(pdis->hDC, pt);
            //右边的三角形
            pt[0].x = 5 * cx / 8; pt[0].y = 3 * cy / 8;
            pt[1].x = 7 * cx / 8; pt[1].y = 4 * cy / 8;
            pt[2].x = 5 * cx / 8; pt[2].y = 5 * cy / 8;
            Triangle(pdis->hDC, pt);
            break;
        }
        //选中时,反转矩形
        if (pdis->itemState & ODS_SELECTED)
            InvertRect(pdis->hDC, &pdis->rcItem);
        //按钮获得焦点时画虚线框
        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);
}

9.3 静态类

(1)创建:CreateWindow中的参数——“static”

(2)静态窗口的样式

样式

说明

SS_BLACKRECT/SS_BLACKFRAME

填充矩形或画边框,分别对应的系统颜色为COLOR_3DDSHADOW、COLOR_BTNSHADOW、COLOR_BTNHIGHLIGHT。在CreateWindow调用的窗口文本字段将被忽略(因为被填充了)。坐标是相对于父窗口的

SS_GRAYRECT / SS_GRAYRECT

SS_WHITERECT/SS_WHITEFRAME

SS_ETCHEDHORZ

用白色和灰色,建立一个边框,并将顶端边框设置为浮雕风格

SS_ETCHEDVERT

用白色和灰色,建立一个边框,并将左侧边框设置为浮雕风格

SS_ETCHEDFRAME

建立一个浮雕边框(阴影边框)

SS_LEFT

文本的对齐方式,相应的文本由CreateWindow的文本参数指定,可通过SetWindowsText修改。窗口过程内部使用DrawText函数带DT_WORDBREAK、DT_NOCLIP、DT_EXPANDTABS参数来显文本

SS_RIGHT

SS_CENTER

SS_ICON

作为子窗口控件时,该样式是无意义的。

SS_USERITEM

(3)消息

  ①不接受鼠标和键盘输入,也不向父窗口发送WM_COMMAND消息

  ②单击时子窗口捕获WM_NCHITTEST,并返回HTTRANSPARENT,导致Windows向底层窗口发送相同的WM_NCHITTEST消息,通常父窗口将该消息传给DefWindowProc,在那里会转换为客户区的鼠标消息。

原文地址:https://www.cnblogs.com/5iedu/p/4658941.html