如何在绘制自定义标题(框架)时在alt +标签切换器中绘制标题?

时间:2013-02-21 03:21:01

标签: windows gdi paint

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

    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 +标签切换器中制作标题?

1 个答案:

答案 0 :(得分:2)

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

有两种方法可以实现这一点,一种是使用Win9x Win32Api中的传统DrawCaption,另一种是使用更新鲜的“主题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);
}

生成的窗口如下所示:

screenshot of resulting window

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

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

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

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

祝你好运,我希望这有助于确定

旁注:我正在运行Windows8并且不确定为什么标题绘制例程忽略了我的主题......也许我忘了指令