2

我需要绘制一个自定义标题栏,我自己在其中绘制窗口标题。

    HDC hdc = GetWindowDC(hwnd);
    if (hdc && prepareTitleBarDC(getWidth(), 27)) {
        SetWindowText(hwnd, _T(""));
        DefWindowProc(hwnd, WM_NCPAINT, wParam, lParam);
        m_titleBar->setSize(getWidth(), 27);
        m_titleBar->setBkColor(SkColorSetARGB(0x00, 0x00, 0x00, 0x00));
        m_titleBar->paintEvent(m_pTitleBarDC);
        FnSkBitmap::SaveSkBitmap(m_pTitleBarDC->canvas(), L"e:\\titlebar.bmp");

        HDC hdcPaint = CreateCompatibleDC(hdc);
        HBITMAP hbm = CreateCompatibleBitmap(hdc, getWidth(), 27);
        SelectObject(hdcPaint, hbm);
        FnSkBitmap::DrawSkBitmap(m_pTitleBarDC->bitmap(), hdcPaint);
        BLENDFUNCTION bfn = {0};
        bfn.BlendOp = AC_SRC_OVER;
        bfn.BlendFlags = 0;
        bfn.SourceConstantAlpha = 255;
        bfn.AlphaFormat = AC_SRC_ALPHA;
        AlphaBlend(hdc, 0, 0, getWidth(), 27, hdcPaint, 0, 0, getWidth(), 27, bfn);
    }
    ReleaseDC(hwnd, hdc);
    return 0;

并且使用AlphaBlend和自己混合标准框架,但是如果我使用SetWindowText(_T("")),那么Alt+Tab切换器中的标题就消失了。

我尝试处理 WM_GETTEXT 消息并返回标题字符串,但失败了。我怎样才能自己绘制标题文本,但仍然在 alt+tab 切换器中制作标题?

4

1 回答 1

2

由于您已经在绘制“自定义标题栏”,因此没有理由使用实际窗口的文本实际绘制它

有两种方法可以做到这一点,一种是使用传统DrawCaption的 Win9x Win32Api,另一种是使用更新鲜的“主题 api”

这是一个同时使用两者的示例:

#include <Windows.h>
#include <Uxtheme.h>
#include <vssym32.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

const LPCWSTR WINDOW_CLASS = L"Test Window Class";
const LPCWSTR WINDOW_CAPTION = L"This is my test window";
const LPCWSTR CUSTOM_CAPTION = L"Custom Caption Text";

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    WNDCLASSEX wndClassEx = {};

    wndClassEx.lpszClassName = WINDOW_CLASS;
    wndClassEx.hInstance = hInstance;
    wndClassEx.lpfnWndProc = WindowProc;
    wndClassEx.cbSize = sizeof(wndClassEx);
    wndClassEx.hCursor = (HCURSOR) LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
    wndClassEx.style = CS_DBLCLKS | CS_DROPSHADOW;

    ATOM registeredClass = RegisterClassEx(&wndClassEx);

    HWND hwnd = CreateWindowEx(
        0,
        WINDOW_CLASS,
        WINDOW_CAPTION,
        WS_SYSMENU,

        200, 200, 500, 300,

        NULL, // parent
        NULL, // menu
        hInstance,
        NULL // extra
        );

    if (hwnd == NULL)
    {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_LBUTTONDBLCLK:
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);

            // fill the window with a color
            HBRUSH hbrush = CreateSolidBrush(RGB(33, 33, 33));
            FillRect(hdc, &ps.rcPaint, hbrush);
            DeleteObject(hbrush);

            // get a drawing area
            RECT rect = {};
            GetClientRect(hwnd, &rect);
            rect.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYEDGE) * 2;

            // draw a simple win9x style caption (switch out the window text while drawing)
            SetWindowText(hwnd, CUSTOM_CAPTION);
            DrawCaption(hwnd, hdc, &rect, DC_GRADIENT | DC_TEXT | DC_ACTIVE | DC_ICON);
            SetWindowText(hwnd, WINDOW_CAPTION);

            // use theme framework
            HTHEME htheme = OpenThemeData(hwnd, L"Window");

            // move downwards and then use new APIs for size
            rect.top += rect.bottom + 20;
            rect.bottom = rect.top + GetThemeSysSize(htheme, SM_CYSIZE) + GetThemeSysSize(htheme, SM_CXPADDEDBORDER) * 2;

            // draw the background
            DrawThemeBackground(htheme, hdc, WP_CAPTION, CS_ACTIVE, &rect, &ps.rcPaint);

            // load the caption font and save the old one
            LOGFONTW captionfont = {};
            GetThemeSysFont(htheme, TMT_CAPTIONFONT, &captionfont);
            HFONT newfont = CreateFontIndirect(&captionfont);
            HGDIOBJ oldfont = SelectObject(hdc, newfont);

            // center the font and draw
            rect.top += GetThemeSysSize(htheme, SM_CXPADDEDBORDER);
            DrawThemeTextEx(htheme, hdc, WP_CAPTION, CS_ACTIVE, CUSTOM_CAPTION, -1, DT_CENTER, &rect, NULL);

            // cleanup fonts
            SelectObject(hdc, oldfont);
            DeleteObject(newfont);

            // adjust draw location, load icon and draw
            rect.left += GetThemeSysSize(htheme, SM_CXPADDEDBORDER) * 2;
            rect.top += GetThemeSysSize(htheme, SM_CXPADDEDBORDER);
            HICON icon = (HICON) LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
            DrawIconEx(hdc, rect.left, rect.top, icon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL);


            // close theme
            CloseThemeData(htheme);

            EndPaint(hwnd, &ps);

        }
        return 0;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

结果窗口如下所示:

结果窗口的屏幕截图

您可以看到 2 个“自定义绘制”标题栏显示自定义文本,而不是窗口上的文本。

快速浏览一下代码会告诉您,使用自定义例程尝试主题窗口标题比传统的要困难得多。当然,权衡是它给了你更多的控制权。您还会注意到,在使用旧方法时,我切换了窗口文本以使其显示我想要的内容。此外,您需要记住,遗留方法在如何从与窗口关联的样式中绘制自己的队列中,如果您的窗口样式没有图标,即使您指定它也不会绘制...

这些技术中的任何一种都可以实现您的目标。如果我切换此代码以不绘制多个标题栏并摆脱由窗口样式创建的默认标题栏,结果将如下所示:

显示结果的屏幕截图 你可以在这里看到任务开关如何仍然显示实际的窗口文本,我的“自定义”标题栏看起来像真正的交易......

祝你好运,我希望这会有所帮助-ck

附带说明:我正在运行 Windows8,但不确定为什么标题绘制例程忽略了我的主题......也许我忘记了一个指令

于 2013-04-10T20:43:54.377 回答