Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
165 views
in Technique[技术] by (71.8m points)

winapi - How do I make a static control with custom width and color?

To change the static's control color and width, I did process the WM_NCPAINT message, but it's not working properly:

  1. the text isn't properly displayed. Should I draw it in this message? When I call SetWindowText(), the new text is properly set, but I still have the issue #2.

  2. after a call to SetWindowText(), the text is set, but the border differs, it's smaller than the one I've draw in the WM_NCPAINT message.

Here's how I'm handling WM_NCPAINT:

case WM_NCPAINT:
{
    PAINTSTRUCT ps;
    HDC dc = BeginPaint(hwnd, &ps);
    RECT rt = {0};
    GetClientRect(hwnd, &rt);
    HPEN pen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
    HPEN holdPen = SelectObject(dc, pen);
    DrawBorder(dc, &rt);
    SelectObject(dc, holdPen);
    EndPaint(hwnd, &ps);
    DeleteObject(pen);
    pen = NULL;
    return 0;
}

When the application starts, the static control border looks like the one I've draw at WM_NCPAINT:

image

But once I call SetWindowText(), for example, from a button click, it looks like this:

image

What am I missing?

Here's full code:

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
    
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
    
#include <windows.h>
#include <Commctrl.h>
#include <crtdbg.h>
#include <strsafe.h>
#include <string.h>
#include <assert.h>
    
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void EnableVisualStyles2(void);
LRESULT CALLBACK ButtonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void SetDefaultFont(HWND hwnd);
void DrawLine(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2);
void DrawBorder(HDC hdc, RECT *rect);
HFONT getSystemDefaultFont(void);
    
WNDPROC oldButtonProc;
HINSTANCE ghInstance;
HFONT hDefaultFont;
HWND btn, btn2;
    
enum 
{
    BTN_ID = 10,
    BTN2_ID,
};
    
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PWSTR pCmdLine, int nCmdShow)
{
    MSG  msg = {0};
    HWND hwnd;
    WNDCLASSW wc = {0};

    wc.lpszClassName = L"Window";
    wc.hInstance     = hInstance;
    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    wc.lpfnWndProc   = WndProc;
    wc.hCursor = LoadCursor(0, IDC_ARROW);

    EnableVisualStyles2();
    if(!RegisterClass(&wc)) {
        return -1;
    }

    int width = 540;
    int height = 460;
    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    int screenHeight = GetSystemMetrics(SM_CYSCREEN);
    int cx = (screenWidth - width) / 2;
    int cy = (screenHeight - height) / 2;
    hwnd = CreateWindowW(wc.lpszClassName, L"Window",
                        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                        cx, cy, width, height, NULL, NULL, 
                        hInstance, NULL);
    ghInstance = hInstance;

    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!IsDialogMessage(hwnd, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    DeleteObject(hDefaultFont);
    return (int) msg.wParam;
}
    
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CREATE:
        {
            btn =
                CreateWindow(L"static", L"+",
                    WS_VISIBLE | WS_CHILD | WS_TABSTOP |
                    SS_NOTIFY | SS_CENTER | SS_CENTERIMAGE,
                    15, 25, 50, 50,
                    hwnd, (HMENU) BTN_ID, NULL, NULL);
            SetDefaultFont(btn);
            oldButtonProc = (WNDPROC) SetWindowLongPtr(btn,
                                        GWLP_WNDPROC,
                                        (LONG_PTR) ButtonProc);
            btn2 = 
                CreateWindow(L"Button", L"Click me!",
                            WS_VISIBLE | WS_CHILD | WS_TABSTOP,
                            15, 100, 70, 25,
                            hwnd, (HMENU) BTN2_ID,
                            NULL, NULL);
            SetDefaultFont(btn2);
        }
        break;
    
        case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
                case BTN_ID:
                {
                    //InvalidateRect(btn, NULL, TRUE);
                    
                    if(IsWindowVisible(btn2))
                    {
                        SetWindowText(btn, L"+");
                        ShowWindow(btn2, SW_HIDE);
                    }
                    else
                    {
                        SetWindowText(btn, L"-");
                        ShowWindow(btn2, SW_SHOW);
                    }
                }
                break;
    
                case BTN2_ID:
                {
                    InvalidateRect(btn, NULL, TRUE);
                    //SetWindowText(btn, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0");
                }
                break;
            }
        }
        break;    
        
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
    
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
    
LRESULT CALLBACK ButtonProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_NCPAINT:
        {
            PAINTSTRUCT ps;
            HDC dc = BeginPaint(hwnd, &ps);
            RECT rt = {0};
            GetClientRect(hwnd, &rt);
            HPEN pen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
            HPEN holdPen = SelectObject(dc, pen);
            DrawBorder(dc, &rt);
            SelectObject(dc, holdPen);
            EndPaint(hwnd, &ps);
            DeleteObject(pen);
            pen = NULL;
            return 0;
        }
    }
    
    return CallWindowProc(oldButtonProc, hwnd, msg, wParam, lParam);
}
    
void EnableVisualStyles2(void)
{
    TCHAR dir[MAX_PATH] = {0};
    GetSystemDirectory(dir, sizeof(dir) / sizeof(*dir));
    
    ACTCTX actCtx = {0};
    actCtx.cbSize = sizeof(ACTCTX);
    actCtx.dwFlags =  ACTCTX_FLAG_RESOURCE_NAME_VALID |
                      ACTCTX_FLAG_SET_PROCESS_DEFAULT |
                      ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
    actCtx.lpSource = L"shell32.dll";
    actCtx.lpAssemblyDirectory = dir;
    actCtx.lpResourceName = (LPCTSTR) 124;
    ULONG_PTR cookie = FALSE;
    HANDLE h = CreateActCtx(&actCtx);
    assert(h != INVALID_HANDLE_VALUE);
    assert(ActivateActCtx(h, &cookie));
}
    
HFONT getSystemDefaultFont(void)
{
    if(!hDefaultFont)
    {
        // get system default font
        NONCLIENTMETRICS ncm;
        ncm.cbSize = sizeof(NONCLIENTMETRICS);
        SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
        hDefaultFont = CreateFontIndirect(&ncm.lfMessageFont);
    }
    return hDefaultFont;
}
    
void SetDefaultFont(HWND hwnd)
{
    SendMessage(hwnd, WM_SETFONT, (WPARAM)getSystemDefaultFont(), FALSE);
}
    
void DrawLine(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2)
{
    MoveToEx(hdc, x1, y1, NULL);
    LineTo(hdc, x2, y2);
}
    
void DrawBorder(HDC hdc, RECT *rect)
{
    DrawLine(hdc, rect->left, rect->top, rect->left, rect->bottom);
    DrawLine(hdc, rect->left, rect->top, rect->right, rect->top);
    DrawLine(hdc, rect->right, rect->top, rect->right, rect->bottom);
    DrawLine(hdc, rect->left, rect->bottom, rect->right, rect->bottom);
}
question from:https://stackoverflow.com/questions/66053453/how-do-i-make-a-static-control-with-custom-width-and-color

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your static control does not have a transparent background, so when you call the SetWindowText function, the static control partially covers the external lines you draw.

You can add the following code in WndProc:

case WM_CTLCOLORSTATIC:
{
    HDC hdcStatic = (HDC)wParam;
    SetBkMode(hdcStatic, TRANSPARENT);
    return (LRESULT)GetStockObject(NULL_BRUSH);
}

But this code tells the static control to draw the text without a background color and not to repaint the background. So the new text is drawn on top of the old text instead of on a fresh background.You can refer to this thread to try to solve it.

Of course, you can also extend the boundary of the straight line when drawing a straight line (you do not need to process the WM_CTLCOLORSTATIC message), as shown in the following code:

void DrawBorder(HDC hdc, RECT* rect)
{
    DrawLine(hdc, rect->left - 3, rect->top - 3, rect->left - 3, rect->bottom + 3) ;
    DrawLine(hdc, rect->left - 3, rect->top - 3, rect->right + 3, rect->top - 3);
    DrawLine(hdc, rect->right + 3, rect->top - 3, rect->right + 3, rect->bottom + 3);
    DrawLine(hdc, rect->left - 3, rect->bottom + 3, rect->right + 3, rect->bottom + 3);
}

This is the modified effect:

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...