《Windows API每日一练》8.3 scrollbar控件

在第三章SYSMETS2.C实例中,我们是通过CreateWindow函数创建窗口的参数窗口样式中添加垂直或水平滚动条。本节我们将讲述作为子窗口控件的滚动条。

本节必须掌握的知识点:

        滚动条类

        滚动条控件和着色

8.3.1 滚动条类

窗口滚动条与滚动条控件的异同

滚动条子窗口控件可以出现在父窗口客户区的任何地方。可以使用预定义的“滚动条”窗口类和两种滚动条样式SBS_VERT 和SBS_HORZ之一来创建子窗口滚动条控件。

不同于按钮控件,滚动条控件不发送 WM_COMMAND消息到父窗口。它们就像窗口滚动条一样发送WM_VSCROLL和 WM_HSCROLL消息。在处理滚动条消息时,可以用IParam参数区分窗口滚动条和滚动条控件。如果IParam参数等于0,就说明它是窗口滚动条;如果等于滚动条窗口句柄,就说明它是滚动条控件。wParam参数的高位字和低位字部分对于窗口滚动条和滚动条控件的含义是一样的。

与窗口滚动条有一个固定的宽度不同,Windows会通过CreateWindow调用(或之后的 MoveWindow调用)中指定的矩形尺寸来调整滚动条控件的尺寸。你可以产生长而窄的滚动 条控件或短而粗的滚动条控件。

如果想创建和窗口滚动条具有相同尺寸的滚动条控件,则可以使用GetSystemMetrics 获得水平滚动条的高度:

GetSyscemMetrics (SM_CYHSCROLL) ;

或者获得垂直滚动条的宽度:

GetSystemMetrics (SM_CXVSCROLL);

滚动条窗口样式标识符 SBS_LEFTALIGN,SBS_RIGHTALIGN,SBS_TOPALIGN 和 SBS_BOTTOMALIGN都为滚动条提供标准尺寸。不过它们只适用于对话框中的滚动条。 可以使用与用于窗口滚动条同样的函数来设置滚动条控件的范围和位置:

SeCScrollRange (hwndScroll, SB_CTL, iMin, iMax, bRedraw) ;

SetScrollPos (hwndScroll, SB_CTL, iPos, bRedraw) ;

SetScrollInfo (hwndScroll, SB_CTL, &si, bRedraw);

区别在于,窗口滚动条会使用主窗口的句柄作为第一个参数,SB_VERT或SB_HORZ作 为第二个参数。

更神奇的是,名为COLOR_SCROLLBAR的系统颜色不再对滚动条起作用。滚动条两端的按钮及滑块的颜色将基于COLOR_BTNFACE,COLOR_BTNHILIGHT ,COLOR_BTNSHADOW,COLOR_BTNTEXT (给小箭头用),COLOR_DKSHADOW 以及 COLOR_BTNLIGHT。在两端按钮之间的大片区域则基于COLOR_BTNFACE和 COLOR_BTNHIGHLIGHT 的某种组合。

如果你俘获了 WM_CTLCOLORSCROLLBAR消息,就可以从这个消息返回一个画刷来修改原来的颜色。

窗口滚动条

滚动条控件

消息

发送WM_VSCROLLWM_HSCROLL消息。不发送WM_COMMAND消息。wParam参数的意义是一样的。lParam:当消息来自窗口滚动条时为NULL,来自滚动条控件时为滚动条的句柄。

宽度或高度

固定大小

//水平滚动条高度

GetSysMetricsSM_CYHSCROLL;

//垂直滚动条宽度

GetSysMetricsSM_CYVSCROLL

1、大小、位置均可设定;

2、在CreateWindowMoveWindow函数中指定,大小可自定义。

窗口样式

WS_VSCROLL:垂直滚动条(在窗口右侧)

WS_HSCROLL:水平滚动条(在窗口下方)

可用滚动条样式和尺寸

SBS_VERTSBS_HORZ

S SBS_TOPALIGN  BS_BOTTOMALIGNSBS_LEFTALIGNSBS_RIGHTALIGN等。

调用函数

的参数

SetScrollInfo(hwnd,SB_VERT,

&si,bRedraw);

SetScrollInfo(hwndScroll,SB_CTL,

&si,bRedraw);

自动键盘接口

滚动条控件还可以处理按键信息,但前提是它们拥有输入焦点。下表显示了键盘光标是如何转换为滚动条消息的。

光标键

滚动条消息wParam

Home

SB_TOP

End

SB_BOTTOM

PageUp

SB_PAGEUP

PageDown

SB_PAGEDOWN

←或↑

SB_LINEUP

→或↓

SB_LINEDOWN

事实上,SB_TOP和SB_BOTTOM这两个滚动条消息只能通过键盘产生。如果你想让滚动条控件在鼠标单击滚动条时取得输入焦点,必须在CreateWindow函数的窗口类参数中加入WS_TABSTOP标识符。当滚动条获得输入焦点时,滚动条滑块上会显示一个闪烁的灰色块。

为了给滚动条提供完整的键盘接口,需要做更多的工作。首先,WndProc窗口过程必须专门提供滚动条所需要的输入焦点。为此,它会处理WM_SETFOCUS消息,这是父窗口得到输入焦点时接收到的消息。WndProc只需把输入焦点给其中一个滚动条:

SetFocus (hwndScroll[idFocus]);

这里的idFocus是一个全局变量。

但还需要一些方法通过键盘把输入焦点从一个滚动条移到另一个,最好是使用Tab键。 这样做会有一定难度,因为一旦滚动条获得输入焦点,它就会处理所有的按键信息。但是滚动条关心的只有光标键,它会忽视Tab键。解决这个问题的出路在于使用“窗口子类” 这一技术。

8.3.2 第52练:滚动条控件和着色

/*------------------------------------------------------------------

052  WIN32 API 每日一练

     第52个例子COLORS1.C:滚动条控件和着色

     CallWindowProc 函数

     SetWindowLong函数

     SetClassLong函数

     GetDlgItem 函数

     WM_CTLCOLORSCROLLBAR消息

     WM_CTLCOLORSTATIC 消息

     WM_SYSCOLORCHANGE消息

(c) www.bcdaren.com, 2020

----------------------------------------------------------------*/

#include <windows.h>

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

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

int idFocus;

WNDPROC OldScroll[3];

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

    PSTR szCmdLine, int iCmdShow)

{

    static TCHAR szAppName[] = TEXT("Colors1");

    (略)

    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;

    static int color[3], cyChar; //三个滚动条当前的颜色值

    static RECT rcColor;

    static TCHAR * szColorLabel[] = { TEXT("Red"), EXT("Green"),TEXT("Blue") };

    HINSTANCE hInstance;

    int i, cxClient, cyClient;

    TCHAR szBuffer[10];

    switch (message)

    {

    case WM_CREATE:

        hInstance = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);//获取进程句柄

        //创建白色矩形静态窗口控件ID:9--用来存放3个滚动条,可以隐掉后测试

        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++) //生成3个滚动条控件

        {

            //创建三个滚动条,范围0-255,ID分别为0,1,2

//WS_TABSTOP标识符:当滚动条获得输入焦点时,

//滚动条滑块上会显示一个闪烁的灰色块。

            hwndScroll[i] = CreateWindow(TEXT("scrollbar"), NULL,

                WS_CHILD | WS_VISIBLE |

                WS_TABSTOP | SBS_VERT//垂直滚动条窗口类

                0, 0, 0, 0,

                hwnd, (HMENU)i, hInstance, NULL);

            //SB_CTL检索滚动条控件的位置

//设置滚动条控件的滚动范围

            SetScrollRange(hwndScroll[i], SB_CTL, 0, 255, FALSE);

            SetScrollPos(hwndScroll[i], SB_CTL, 0, FALSE); //滚动滑块位置

            //3个颜色名称为"Red"、"Green"、"Blue"的静态文本框,ID分别为3,4,5

            hwndLabel[i] = CreateWindow(TEXT("static"), szColorLabel[i],

                WS_CHILD | WS_VISIBLE | SS_CENTER, //将文本居中

                0, 0, 0, 0,

                hwnd, (HMENU)(i + 3),

                hInstance, NULL);

            //3个表示颜色值得静态文本框,初始值为"0",IDs 6, 7, and 8

            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[i] = (WNDPROC)SetWindowLong(hwndScroll[i],

                GWL_WNDPROC, (LONG)ScrollProc);

            //创建3个画刷

            hBrush[i] = CreateSolidBrush(crPrim[i]);

        }

        //创建静态文本背景画刷,3D 显示元素的高亮颜色

        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);

        //设置滚动条在主窗口大小和位置:宽cxClient/14,高cyClient -4*cyChar;

        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;

            //继续执行

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

        case SB_PAGEUP: color[i] -= 15;

            // 继续执行

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

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

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

        case SB_THUMBPOSITION:

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

        defaultbreak;

        }

        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); //重绘窗口,TRUE擦除背景

        //UpdateWindow(hwnd);//立即更新,不需要送入消息队列

        return 0;

        //将要绘制控件时滚动条控件消息:

//wParam:滚动条控件的设备上下文的句柄DC,lParam:滚动条句柄

    case WM_CTLCOLORSCROLLBAR:

        //返回画刷句柄,用来修改三个滚动条内部的颜色

        i = GetWindowLong((HWND)lParam, GWL_ID);//获取控件ID

//必须将句柄返回给画刷。 系统使用画刷绘制滚动条控件的背景。

        return (LRESULT)hBrush[i];

   //将要绘制时,静态控件消息---设定静态文本的颜色

    case WM_CTLCOLORSTATIC:

        i = GetWindowLong((HWND)lParam, GWL_ID); //获取窗口ID

        if (i >= 3 && i <= 8) // 6个static text controls ID:3~8

        {

            //设置静态文本颜色

            SetTextColor((HDC)wParam, crPrim[i % 3]);

//设置系统颜色为背景色

            SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNHIGHLIGHT));

            return (LRESULT)hBrushStatic;

        }

        break;

        //更改系统颜色

    case WM_SYSCOLORCHANGE:

        DeleteObject(hBrushStatic);//删除画刷

//重新创建画刷

        hBrushStatic = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT));

        return 0;

    case WM_DESTROY:

        //创建新的白色画刷,把句柄存入到窗口类中然后删除旧的画刷

        DeleteObject((HBRUSH)

            SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)

                GetStockObject(WHITE_BRUSH)));

        for (i = 0; i < 3; 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),//包含控件的对话框的句柄

           //追踪SHIFT键,改变TAB键切换的顺序:

           //按下SHIFT <0:2,1,0;未按下>0:0,1,2

            (id + (GetKeyState(VK_SHIFT) < 0 ? 2 : 1)) % 3));

        break;

    case WM_SETFOCUS:

        idFocus = id;

        break;

    }

    //调用子窗口旧的窗口过程

    return CallWindowProc(OldScroll[id], hwnd, message, wParam, lParam);

}

/******************************************************************************

CallWindowProc 函数:子窗口类过程返回旧窗口过程

LRESULT CallWindowProcA(

  WNDPROC lpPrevWndFunc,

  HWND    hWnd,

  UINT    Msg,

  WPARAM  wParam,

  LPARAM  lParam

);

*******************************************************************************

SetWindowLong函数:设置子窗口类过程

LONG SetWindowLongA(

  HWND hWnd,

  int  nIndex,//设置窗口过程的新地址

  LONG dwNewLong//新窗口过程

);

*******************************************************************************

SetClassLong函数:将指定偏移量处的指定32位(long)值替换到指定窗口所属类的额外类存储器或WNDCLASSEX结构中。

DWORD SetClassLongA(

  HWND hWnd,   //窗口的句柄,间接地,窗口所属的类。

  int  nIndex, //将要被替换的值。

  LONG dwNewLong//替换值

);

注意  此函数已被SetClassLongPtr函数取代。要编写与Windows 32位和64位版本兼容的代码,请使用SetClassLongPtr。

*******************************************************************************

GetDlgItem 函数用于获取对话框模板中标识符(ID)对应的子窗口句柄。

HWND GetDlgItem(

  HWND hDlg,    //对话框的窗口句柄

  int  nIDDlgItem//子窗口的标识符(ID)

);

返回值:对应标识符的子窗口的句柄(HWND)。

*******************************************************************************

WM_CTLCOLORSCROLLBAR消息:发送滚动条控件消息至父窗口

wParam:DC,lParam:滚动条句柄,

//必须返回画笔句柄

WM_CTLCOLORSTATIC 消息:发送静态控件消息至父窗口

WM_SYSCOLORCHANGE消息:更改系统颜色设置后,会将WM_SYSCOLORCHANGE消息发送到所有顶级窗口

*/

       运行结果:

图8-5 滚动条控件

 

总结

实例COLORS1.C在一个白色静态文本框内绘制了3个滚动条控件,此外还绘制了6个静态文本控件显示RGB颜色及颜色值。在主窗口客户区的左侧绘制一个矩形,使用3个滚动条控件的RGB值创建一个画刷,填充矩形背景。

此外,还根据3个滚动条控件的值(0~255)分别创建3个画刷,设置3个静态文本颜色,创建一个高亮系统颜色画刷作为静态文本控件的背景色。

实例COLORS1.C还创建了一个窗口子类,定义了一个新的滚动条子窗口控件过程,用于处理键盘接口TAB键,切换焦点窗口。

主窗口过程对于WM_CREATE消息的处理。首先创建一个存放3个滚动条控件的静态文本框。接着创建3个滚动条控件,并将滚动条滚动范围设置为0~255,与RGB颜色值对应。初始滚动条滑块位置为0。然后在滚动条控件的上方和下方分别创建3个静态文本控件,用于显示RGB颜色和颜色值。最后调用SetWindowLong函数设置滚动条控件新的窗口过程ScrollProc,并返回Windows预定义的滚动条控件默认窗口过程,存入OldScroll[i]数组。接着创建一个静态文本背景画刷,并获取对话框字体的高。

WM_SIZE消息的处理:调用SetRect函数在主窗口右侧绘制一个矩形框。调用MoveWindow函数调整静态文本框控件和滚动条控件的大小。

WM_SETFOUCUS消息处理:调用SetFocus函数将当前idFocus滚动条控件设为焦点窗口。

WM_VSCROLL消息处理:调用GetWindowLong函数获取滚动条控件ID,并依据wParam

参数低字值调整滚动条滑块位置。滑块位置即颜色值,修改3个静态文本颜色值,并以此生成新画刷填充主窗口右侧矩形背景色。

WM_CTLCOLORSCROLLBAR消息处理:将要绘制滚动条控件时接收此消息,该消息的wParam:滚动条控件的设备上下文的句柄DC;lParam:滚动条句柄。调用GetWindowLong依据滚动条控件句柄获取滚动条控件ID,并返回画刷return (LRESULT)hBrush[ID];

WM_CTLCOLORSTATIC消息处理:将要绘制静态文本控件时接收此消息,调用GetWindowLong依据静态文本控件句柄获取控件ID,并更新静态文本颜色和颜色值。

WM_SYSCOLORCHANGE消息处理:如果更改系统颜色,则删除旧静态文本背景画刷,重新依据系统颜色生成新的静态文本背景画刷。

WM_DESTROY消息处理:删除创建的新GDI画刷对象。

窗口子类

滚动条控件的窗口过程在Windows内部。但是你可以调用GetWindowLong来获取这 个窗口过程的地址,使用GWL_WNDPROC标识符作为参数即可。此外,还可以通过调用SetWindowLong,为滚动条设置一个新的窗口过程。这种技术被称为“窗口子类”。它的功能非常强大。它可以让你连接到已有的窗口过程,在你的程序中处理一些消息,并将其他消息传递给旧的窗口过程。

在COLORS1中,能初步处理滚动条消息的窗口过程名为ScroMProc,它列在 C0L0RS1.C文件的结束部分。由于COLORS1中的ScrollProc是一个被Windows调用的函数,因此它必须被定义成CALLBACK类型。

对这三个滚动条中的每一个COLORS1都使用SetWindowLong来设置新的滚动条窗口过程的地址,同时获得现有滚动条窗口过程的地址:

OldScroll[i] = (WNDPROC) SetWindowLong (hwndScroll[i),

GWL_VMDPROC,(LONG) ScrollProc));

现在,ScrollProc获得了 Windows发送给COLORS1程序中三个滚动条的所有消息(当然不包括在其他程序中的滚动条)。当它收到Tab或Shift-Tab击键信息后,此ScrollProc 窗口过程只需更改输入焦点到下一个(或前一个)滚动条即可。它使用CallWindowProc来调 用旧的滚动条窗口过程。

背景着色

在COLORS1定义它的窗口类时,给它的客户区指定了一个黑色的背景画刷:

wndclass.hbrBackground = CreateSolidBrush (0);

当你更改COLORS1的滚动条设置时,程序必须创建一个新的画刷,并把新画刷句柄存入窗口类的结构中。正如我们使用GetWindowLong和SetWindowLong来获取和设置滚动 条窗口过程一样,我们可以使用GetClassWord和SetClassWord来获取和设置这个画刷的句柄。

你可以创建新的画刷,把句柄存入到窗口类结构中,然后删除旧的画刷:

DeleteObject ((HBRUSH)

              SetClassLong (hwnd, GCL_HBRBACKGROUND, (LONG)

                     CreaceSolidBrush (RGB (colort[0], color[1], color[2]))));

下一次Windows重新给窗口背景着色的时候,Windows将使用这个新画刷。如果要强制 Windows擦除背景,我们可以让客户区的右半部分失效:

InvalidateRect (hwnd, &rcColor, TRUE);

函数的第三个参数输入TRUE(非零值),表明我们希望在窗口重绘之前擦除背景。

InvalidateRect函数会让Windows把WM_PAINT消息放在窗口过程的消息队列中。由于WM_PAINT消息属于低优先级消息。因此,如果你仍然在移动鼠标或光标键,此消息将不会立即被处理。另一种情况是,如果你希望窗口在颜色修改后立即更新,则可以在 InvalidateRect函数被调用后调用下面的函数:

UpdateWindow (hwnd);

不过,这个函数可能会拖慢键盘和鼠标处理速度。

COLORS1的WndProc函数不直接处理WM_PAINT消息,而是将它传递给 DefWindowProc函数。WM_PAINT消息在Windows中的默认处理方式仅仅是调用 BeginPaint和EndPaint来使窗口有效。因为我们在InvalidateRect中指定旧背景应该被删除,所以调用BeginPaint会使Windows产生一条WM_ERASEBKGND(擦除背景)消息。 WndProc也会忽略此消息。Windows会对该消息进行处理,它使用窗口类指定的画刷来擦除这个客户区的背景。

通常情况下,在终止程序前进行清理总是一个不错的好主意,因此在处理 WM_DESTROY消息时,DeleteObject被再次调用:

DeleteObject ((HBRUSH)

       SetClassLong (hwnd, GCL_HBRBACKGROUND,

              (LONG) GetStockObject (WHITE_BRUSH)));

给滚动条和静态文本着色

在COLORS1中,三个滚动条内部和六个文本框中文本的颜色分别被着色为红色、绿色和蓝色。滚动条的着色是通过处理WM_CTLCOLORSCROLLBAR消息来完成的。

在WndProc中,为三个画刷句柄定义了一个静态数组:

static HBRUSH hBrush [3];

在处理WM_CREATE的过程中,创建了这三个画刷:

for (i = 0;i < 3; i++)

hBrush[0] = CreateSolidBrush (crPrim [i]) ;

在这里crPrim数组中包含三个基色的RGB值。在处理WM_CTLCOLORSCROLLBAR

时,窗口过程返回三个画刷中的一个:

case WM_CTLCOLORSCROLLBAR:

i = GetWindowLong ((HWND) IParam, GWL_ID);

             return (LRESULT) hBrush [i];

这些画刷必须在处理WM_DESTROY消息期间被销毁:

for (i =0; i < 3; i++)

       DeleteObject (hBrush [i]));

类似地,静态文本框中文本的着色是通过处理WM_CTLCOLORSTATIC消息和调用 SetTextCoIor函数完成的。文本的背景通过调用SetBkColor设置为系统颜色 COLOR_BTNHIGHLIGHT。这会导致文本的背景与滚动条后面的静态矩形控件具有相同的颜色。对于静态文本控件,这种文本的背景颜色只应用于字符串中每个字符背后的矩形框,而不是控件窗口的整个宽度。要做到这一点,窗口过程必须返回一个COLOR_BTNHIGHLIGHT颜色的画刷句柄。这个被称为hBrushStatic的画刷是在 WM_CREATE处理期间产生的,并在WM_DESTROY消息处理期间被销毁。

程序在WM_CREATE消息处理期间产生COLOR_BTNHIGHLIGHT颜色的画刷,并在程序生命周期中使用它。但这样我们会碰到一个小问题。如果C0L0R_BTNHIGHL1GHT 颜色在程序运行过程中被改变了,静态矩形的颜色会改变,文本背景颜色会改变,但整个文本窗口控件的背景仍将保持原有的COLOR_BTNHIGHLIGHT颜色。

为解决这一问题,COLORS 1在处理WM_SYSCOLORCHANGE消息时简单地用新颜色重新创建hBrushStatic。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/40800.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Linux环境下搭建Redis服务结合内网穿透实现通过GUI工具远程管理数据库

文章目录 前言1. 安装Docker步骤2. 使用docker拉取redis镜像3. 启动redis容器4. 本地连接测试4.1 安装redis图形化界面工具4.2 使用RDM连接测试 5. 公网远程访问本地redis5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Li…

mysql 9 新特新

mysql9新特性 新特性Audit Log NotesC API NotesCharacter Set SupportCompilation NotesComponent NotesConfiguration NotesData Dictionary NotesData Type NotesDeprecation and Removal NotesEvent Scheduler NotesJavaScript ProgramsOptimizer NotesPerformance Schema …

Spring中的事件监听器使用学习

一、什么是Spring中的事件监听机制&#xff1f; Spring框架中的事件监听机制是一种设计模式&#xff0c;它允许你定义和触发事件&#xff0c;同时允许其他组件监听这些事件并在事件发生时作出响应。这种机制基于观察者模式&#xff0c;提供了一种松耦合的方式来实现组件间的通信…

CTF实战:从入门到提升

CTF实战&#xff1a;从入门到提升 &#x1f680;前言 没有网络安全就没有国家安全&#xff0c;网络安全不仅关系到国家整体信息安全&#xff0c;也关系到民生安全。近年来&#xff0c;随着全国各行各业信息化的发展&#xff0c;网络与信息安全得到了进一步重视&#xff0c;越…

XAML 框架横向对比

多年来&#xff0c;基于 XAML 的 UI 框架有了很大的发展。下面的图表很好地证明了这个观点。XAML UI 框架的三大巨头&#xff1a;Avalonia UI、Uno Platform 和 .NET MAUI 都支持跨平台的应用。事实上&#xff0c;除了 Avalonia UI&#xff0c;对跨平台 XAML 的需求是它们发展的…

【深度学习】图形模型基础(5):线性回归模型第四部分:预测与贝叶斯推断

1.引言 贝叶斯推断超越了传统估计方法&#xff0c;它包含三个关键步骤&#xff1a;结合数据和模型形成后验分布&#xff0c;通过模拟传播不确定性&#xff0c;以及利用先验分布整合额外信息。本文将通过实际案例阐释这些步骤&#xff0c;展示它们在预测和推断中的挑战和应用。…

Unity 使用AVProMovieCapture实现Game视图屏幕录制

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity 使用AVProMovieCapture实现Game视图屏幕录制 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心…

【云计算】公有云、私有云、混合云、社区云、多云

公有云、私有云、混合云、社区云、多云 1.云计算的形态1.1 公有云1.2 私有云1.3 混合云1.4 社区云1.5 多云1.5.1 多云和混合云之间的关系1.5.2 多云的用途1.5.3 影子 IT 和多云1.5.4 优缺点 2.不同云形态的对比 1.云计算的形态 张三⾃⼰在家做饭吃&#xff0c;这是 私有云&…

【扩散模型】LCM LoRA:一个通用的Stable Diffusion加速模块

潜在一致性模型&#xff1a;[2310.04378] Latent Consistency Models: Synthesizing High-Resolution Images with Few-Step Inference (arxiv.org) 原文&#xff1a;Paper page - Latent Consistency Models: Synthesizing High-Resolution Images with Few-Step Inference (…

ELK优化之Filebeat部署

目录 1.安装配置Nginx 2.安装 Filebeat 3.设置 filebeat 的主配置文件 4.修改Logstash配置 5.启动配置 6.kibana验证 主机名ip地址主要软件es01192.168.9.114ElasticSearches02192.168.9.115ElasticSearches03192.168.9.116ElasticSearch、Kibananginx01192.168.9.113ng…

Redis---9---集群(cluster)

将新增的6387节点&#xff08;空槽号&#xff09;作为master节点加入原集群 Redis—9—集群&#xff08;cluster&#xff09; 是什么 定义 ​ 由于数据量过大&#xff0c;单个Master复制集难以承担&#xff0c;因此需要对多个复制集进行集群&#xff0c;形成水平扩展每个复…

5个实用的文章生成器,高效输出优质文章

在自媒体时代&#xff0c;优质内容的持续输出是吸引读者、提升影响力的关键。然而&#xff0c;对于许多自媒体创作者来说&#xff0c;频繁的创作难免会遭遇灵感枯竭、创作不出文章的困扰。此时&#xff0c;文章生成器便成为了得力的助手。文章生成器的优势能够快速自动生成高质…

代码随想录算法训练营第13天|二叉树的递归遍历、二叉树的迭代遍历、二叉树的统一迭代法、102.二叉树的层序遍历

打卡Day13 1.理论基础2.二叉树的递归遍历3.二叉树的迭代遍历3.二叉树的统一迭代法4.102.二叉树的层序遍历扩展107. 二叉树的层序遍历 II199.二叉树的右视图637.二叉树的层平均值429.N叉树的层序遍历515.在每个树行中找最大值116.填充每个节点的下一个右侧节点指针117. 填充每个…

如何保证接口幂等性

如何保证接口幂等性 1、幂等性是什么&#xff1f; 接口幂等性是指用户对于同一操作发起的一次请求或者多次请求的结果是一致的&#xff0c;不会因为多次点击而产生了不同的结果。 2、使用幂等性的场景有哪些&#xff1f; 页面点击保存按钮时&#xff0c;不小心快速点了两次…

上万组风电,光伏,用户负荷数据分享

上万组风电&#xff0c;光伏&#xff0c;用户负荷数据分享 可用于风光负荷预测等研究 获取链接&#x1f517; https://pan.baidu.com/s/1izpymx6R3Y8JsFdx42rL0A 提取码&#xff1a;381i 获取链接&#x1f517; https://pan.baidu.com/s/1izpymx6R3Y8JsFdx42rL0A 提取…

一行代码用git新建分支

1.在本地创建分支 dev git branch dev2.切换分支 git checkout devwebstorm操作如下&#xff1a; 3.推送新分支到远程 git push --set-upstream origin 分支名webstorm操作如下&#xff1a;提交代码的时候会自动推送到远程 4.到git上面可以看看刚刚推送的内容 dev多推送…

Proxmox VE 8虚拟机直通USB磁盘

作者&#xff1a;田逸&#xff08;fromyz&#xff09; 今天有个兄弟发消息&#xff0c;咨询怎么让插在服务器上的U盾被Proxmox VE上的虚拟机识别。在很久很久以前&#xff0c;我尝试过在Proxmox VE 5以前的版本创建windows虚拟机&#xff0c;并把插在Proxmox VE宿主机上的银行U…

Android ViewPostImeInputStage输入事件处理

InputDispatcher向InputChannel使用socket写入输入事件&#xff0c;触发InputEventReceiver调用来接收输入事件。 ViewPostImeInputStage处理view控件的事件 frameworks/base/core/java/android/view/InputEventReceiver.java dispatchInputEvent frameworks/base/core/jav…

SwinTransformer的相对位置索引的原理以及源码分析

文章目录 1. 理论分析2. 完整代码 引用&#xff1a;参考博客链接 1. 理论分析 根据论文中提供的公式可知是在 Q Q Q和 K K K进行匹配并除以 d \sqrt d d ​ 后加上了相对位置偏执 B B B。 A t t e n t i o n ( Q , K , V ) S o f t m a x ( Q K T d B ) V \begin{aligned} &…

绝了,华为伸缩摄像头如何突破影像边界?

自华为Pura70 Ultra超聚光伸缩镜头诞生以来&#xff0c;备受大家的关注&#xff0c;听说这颗镜头打破了传统手机的摄像头体积与镜头的设计&#xff0c;为我们带来了不一样的拍照体验。 智能手机飞速发展的今天&#xff0c;影像功能已经成为我们衡量一款手机性能的重要指标。想…