zoukankan      html  css  js  c++  java
  • 第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,在那里会转换为客户区的鼠标消息。

  • 相关阅读:
    【Linux 内核网络协议栈源码剖析】数据包发送
    【Linux 内核网络协议栈源码剖析】connect 函数剖析(一)
    【Henu ACM Round#14 C】Duff and Weight Lifting
    【Henu ACM Round#14 B】Duff in Love
    【Henu ACM Round#14 A】Vitaly and Night
    【Henu ACM Round #13 E】Spy Syndrome 2
    【Henu ACM Round #13 F】Fibonacci-ish
    【Henu ACM Round #13 D】A Trivial Problem
    【Henu ACM Round #13 C】 Ebony and Ivory
    【Henu ACM Round #13 B】Spider Man
  • 原文地址:https://www.cnblogs.com/5iedu/p/4658941.html
Copyright © 2011-2022 走看看