• 第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,在那里会转换为客户区的鼠标消息。

  • 相关阅读:
    228. Summary Ranges
    227. Basic Calculator II
    224. Basic Calculator
    222. Count Complete Tree Nodes
    223. Rectangle Area
    221. Maximal Square
    220. Contains Duplicate III
    219. Contains Duplicate II
    217. Contains Duplicate
    Java编程思想 4th 第4章 控制执行流程
  • 原文地址:https://www.cnblogs.com/5iedu/p/4658941.html
Copyright © 2020-2023  润新知