Как сохранить блок управления отзывчивым, когда рисуете в не клиентской области

Я использую следующий код, чтобы нарисовать изображение, которое выходит за пределы области моего окна. Код работает, но блок управления (кнопки «Свернуть», «Развернуть» и «Закрыть») остается без ответа, при нажатии ничего не происходит. Как нарисовать в области, не являющейся клиентом, чтобы мой блок управления отзывчивым?

Вот скриншот моего приложения, работающего на Windows 7:
Мое приложение

И мой код:

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

0

Решение

После нескольких попыток я написал это в коде, чтобы нарисовать изображение, которое распространяется на не клиентскую область окна Qt, протестировано под Windows 7.

Скриншот результата:

Скриншот

И соответствующий код:

В файле .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];
}
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]