如何在非客户区域绘制时保持控制框响应

时间:2013-05-31 00:42:45

标签: c++ image qt nonclient-area

我正在使用以下代码绘制在窗口的非客户区域扩展的图像。代码有效,但控制框(最小化,最大化和关闭按钮)保持无响应,单击时没有任何反应。如何在非客户区绘制,让我的控制盒响应?

这是我在Windows 7上运行的应用的截图: My app

我的代码:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    WTA_OPTIONS ops;
    ops.dwFlags = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
    ops.dwMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
    SetWindowThemeNonClientAttributes(winId(), ops.dwMask, ops.dwFlags);

    MARGINS margins = {-1};
    DwmExtendFrameIntoClientArea(winId(), &margins);
}

bool MainWindow::winEvent(MSG *pMessage, long *result)
{
    HWND hWnd = pMessage->hwnd;
    UINT message = pMessage->message;
    WPARAM wParam = pMessage->wParam;
    LPARAM lParam = pMessage->lParam;

    DwmDefWindowProc(hWnd, message, wParam, lParam, NULL);

    if(message == WM_PAINT)
    {
        HDC hDC = GetWindowDC(hWnd);
        PaintCustomCaption(hWnd, hDC);
        DeleteDC(hDC);
        return true;
    }

    if(message == WM_NCCALCSIZE) return true;

    if(message == WM_NCHITTEST) return true;

    return QWidget::winEvent(pMessage, result);
}

QPixmap pixmap;

void MainWindow::PaintCustomCaption(HWND hWnd, HDC hdc)
{
    RECT rcClient;
    GetClientRect(hWnd, &rcClient);

    HDC hdcPaint = CreateCompatibleDC(hdc);

    HDC hdcRes = CreateCompatibleDC(hdc);

    if (pixmap.isNull()) pixmap = QPixmap("png.png");

    HBITMAP hBmpRes = pixmap.toWinHBITMAP(QPixmap::PremultipliedAlpha);

    SIZE szBmpRes;
    BITMAP rBitmap;
    GetObject(hBmpRes, sizeof (BITMAP), &rBitmap);
    szBmpRes.cx = rBitmap.bmWidth;
    szBmpRes.cy = rBitmap.bmHeight;

    HBITMAP hOldBmpRes = (HBITMAP)SelectObject(hdcRes, hBmpRes);

    if (hdcPaint)
    {
        int cx = rcClient.right - rcClient.left;
        int cy = rcClient.bottom - rcClient.top;

        BITMAPINFO dib = {0};
        dib.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
        dib.bmiHeader.biWidth           = cx;
        dib.bmiHeader.biHeight          = -cy;
        dib.bmiHeader.biPlanes          = 1;
        dib.bmiHeader.biBitCount        = 32;
        dib.bmiHeader.biCompression     = BI_RGB;

        HBITMAP hbm = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);

        if (hbm)
        {
            HBITMAP hbmOld = (HBITMAP)SelectObject(hdcPaint, hbm);
            BitBlt(hdcPaint, 0, 0, cx, cy, hdcRes, 0, 0, SRCCOPY);
            BitBlt(hdc, 0, 0, cx, cy, hdcPaint, 0, 0, SRCCOPY);
            SelectObject(hdcPaint, hbmOld);
            DeleteObject(hbm);
        }
        DeleteDC(hdcPaint);
    }
    SelectObject(hdcRes, (HBITMAP)hOldBmpRes);
    DeleteObject(hBmpRes);
    DeleteDC(hdcRes);
}

1 个答案:

答案 0 :(得分:0)

经过多次尝试后,我将其写入代码以绘制在Qt窗口的非客户区域扩展的图像,并在Windows 7下进行测试。

结果截图:

screenshot

相关代码:

在.pro文件中:

LIBS += -lGdi32
LIBS += -lUser32
LIBS += -lDwmApi
LIBS += -lUxTheme

在标题文件中:

#include <dwmapi.h>

#define LEFTEXTENDWIDTH 8
#define RIGHTEXTENDWIDTH 8
#define BOTTOMEXTENDWIDTH 20
#define TOPEXTENDWIDTH 161

private slots:
    void PaintCustomCaption(HWND hWnd, HDC hdc);
    LRESULT HitTestNCA(HWND hWnd, LPARAM lParam);

protected:
    bool winEvent(MSG *pMessage, long *result);

private:
    QPixmap pixmap;

最后在cpp文件中:

bool MainWindow::winEvent(MSG *pMessage, long *result)
{
    HWND hWnd = pMessage->hwnd;
    UINT message = pMessage->message;
    WPARAM wParam = pMessage->wParam;
    LPARAM lParam = pMessage->lParam;

    bool retvalue = false;
    LRESULT lRet = 0;

    DwmDefWindowProc(hWnd, message, wParam, lParam, &lRet);

    if (message == WM_ACTIVATE)
    {
        MARGINS margins;

        margins.cxLeftWidth = LEFTEXTENDWIDTH;
        margins.cxRightWidth = RIGHTEXTENDWIDTH;
        margins.cyBottomHeight = BOTTOMEXTENDWIDTH;
        margins.cyTopHeight = TOPEXTENDWIDTH;

        WTA_OPTIONS ops;
        ops.dwFlags = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
        ops.dwMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
        SetWindowThemeNonClientAttributes(hWnd, ops.dwMask, ops.dwFlags);

        DwmExtendFrameIntoClientArea(hWnd, &margins);

        lRet = 0;
        retvalue = false;
    }

    if(message == WM_PAINT)
    {
        HDC hDC = GetWindowDC(hWnd);
        PaintCustomCaption(hWnd, hDC);
        DeleteDC(hDC);
        lRet = 0;
        retvalue = true;
    }

    if(message == WM_NCCALCSIZE)
    {
        lRet = 0;
        retvalue = true;
    }

    if(message == WM_NCHITTEST)
    {
        lRet = HitTestNCA(hWnd, lParam);
        DwmDefWindowProc(hWnd, message, wParam, lParam, &lRet);
        retvalue = true;
    }

    *result = lRet;
    if(retvalue) return true;

    return QWidget::winEvent(pMessage, result);
}

void MainWindow::PaintCustomCaption(HWND hWnd, HDC hdc)
{
    RECT rcClient;
    GetClientRect(hWnd, &rcClient);

    HDC hdcPaint = CreateCompatibleDC(hdc);

    HDC hdcRes = CreateCompatibleDC(hdc);

    if (pixmap.isNull()) pixmap = QPixmap("png.png");

    HBITMAP hBmpRes = pixmap.toWinHBITMAP(QPixmap::PremultipliedAlpha);

    SIZE szBmpRes;
    BITMAP rBitmap;
    GetObject(hBmpRes, sizeof (BITMAP), &rBitmap);
    szBmpRes.cx = rBitmap.bmWidth;
    szBmpRes.cy = rBitmap.bmHeight;

    HBITMAP hOldBmpRes = (HBITMAP)SelectObject(hdcRes, hBmpRes);

    if (hdcPaint)
    {
        int cx = rcClient.right - rcClient.left;
        int cy = rcClient.bottom - rcClient.top;

        BITMAPINFO dib = {0};
        dib.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
        dib.bmiHeader.biWidth           = cx;
        dib.bmiHeader.biHeight          = -cy;
        dib.bmiHeader.biPlanes          = 1;
        dib.bmiHeader.biBitCount        = 32;
        dib.bmiHeader.biCompression     = BI_RGB;

        HBITMAP hbm = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);

        if (hbm)
        {
            HBITMAP hbmOld = (HBITMAP)SelectObject(hdcPaint, hbm);
            BitBlt(hdcPaint, 0, 0, cx, cy, hdcRes, 0, 0, SRCCOPY);
            BitBlt(hdc, 0, 0, cx, cy, hdcPaint, 0, 0, SRCCOPY);
            SelectObject(hdcPaint, hbmOld);
            DeleteObject(hbm);
        }
        DeleteDC(hdcPaint);
    }
    SelectObject(hdcRes, (HBITMAP)hOldBmpRes);
    DeleteObject(hBmpRes);
    DeleteDC(hdcRes);
}

LRESULT MainWindow::HitTestNCA(HWND hWnd, LPARAM lParam)
{
    POINT ptMouse = {(int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)};

    RECT rcWindow;
    GetWindowRect(hWnd, &rcWindow);

    RECT rcFrame = { 0 };
    AdjustWindowRectEx(&rcFrame, WS_OVERLAPPEDWINDOW & ~WS_CAPTION, FALSE, NULL);

    USHORT uRow = 1;
    USHORT uCol = 1;
    bool fOnResizeBorder = false;

    if (ptMouse.y >= rcWindow.top && ptMouse.y < rcWindow.top + TOPEXTENDWIDTH)
    {
        fOnResizeBorder = (ptMouse.y < (rcWindow.top - rcFrame.top));
        uRow = 0;
    }
    else if (ptMouse.y < rcWindow.bottom && ptMouse.y >= rcWindow.bottom - BOTTOMEXTENDWIDTH)
    {
        uRow = 2;
    }

    if (ptMouse.x >= rcWindow.left && ptMouse.x < rcWindow.left + LEFTEXTENDWIDTH)
    {
        uCol = 0;
    }
    else if (ptMouse.x < rcWindow.right && ptMouse.x >= rcWindow.right - RIGHTEXTENDWIDTH)
    {
        uCol = 2;
    }

    LRESULT hitTests[3][3] =
    {
        { HTTOPLEFT,    fOnResizeBorder ? HTTOP : HTCAPTION,    HTTOPRIGHT },
        { HTLEFT,       HTNOWHERE,     HTRIGHT },
        { HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT },
    };

    return hitTests[uRow][uCol];
}