网站后台管理系统数据库,企业网站的cms,wordpress显示的是文件目录结构,深圳设计公司十大排名如果我们希望一个窗口覆盖用户的整个桌面#xff0c;此时就要考虑用户有多个屏幕的场景#xff08;此窗口要横跨多个屏幕#xff09;#xff0c;由于每个屏幕的分辨率和缩放比例可能是不同的#xff0c;Qt底层在为此窗口设置缩放比例#xff08;DevicePixelRatio#xf…如果我们希望一个窗口覆盖用户的整个桌面此时就要考虑用户有多个屏幕的场景此窗口要横跨多个屏幕由于每个屏幕的分辨率和缩放比例可能是不同的Qt底层在为此窗口设置缩放比例DevicePixelRatio时出了问题。
复现环境 屏幕A最大可用分辨率3840*2160 屏幕A当前设置分辨率2048*1080 屏幕A缩放比例100% 屏幕B最大可用分辨率2560*1440 屏幕B当前设置分辨率2560*1440 屏幕B缩放比例125%
注其他条件不变的情况下只要屏幕A的当前设置分辨率比B小均会出错其他条件不变的情况下只要屏幕A的当缩放比例与B不同亦均会出错。
复现步骤
1、设置窗口跨屏的代码 window-setFlags(window-flags() | Qt::FramelessWindowHint);
auto hwnd (HWND)window-winId();
auto x GetSystemMetrics(SM_XVIRTUALSCREEN);
auto y GetSystemMetrics(SM_YVIRTUALSCREEN);
auto w GetSystemMetrics(SM_CXVIRTUALSCREEN);
auto h GetSystemMetrics(SM_CYVIRTUALSCREEN);
SetWindowPos(hwnd,HWND_TOP, x, y, w, h, SWP_NOZORDER );
PostMessage(hwnd, WM_DISPLAYCHANGE, 0, 0);
2、为用户桌面拍照把这个照片显示在窗口中照片布满整个窗口就能只管的看出此Bug
HDC hScreen GetDC(NULL);
HDC hDC CreateCompatibleDC(hScreen);
HBITMAP hBitmap CreateCompatibleBitmap(hScreen, w, h);
DeleteObject(SelectObject(hDC, hBitmap));
BOOL bRet BitBlt(hDC, 0, 0, w, h, hScreen, x, y, SRCCOPY);
img QImage(w, h, QImage::Format_ARGB32);
BITMAPINFO bmi { sizeof(BITMAPINFOHEADER), (long)w, 0 - (long)h, 1, 32, BI_RGB, (DWORD)w * 4 * h, 0, 0, 0, 0 };
GetDIBits(hDC, hBitmap, 0, h, img.bits(), bmi, DIB_RGB_COLORS);
DeleteDC(hDC);
DeleteObject(hBitmap);
ReleaseDC(NULL, hScreen);注这段代码中img就是拍照后得到的QImage对象如何把图像渲染到窗口中的代码就不写了。
这是出错时的样子
如你所见左边屏幕的内容已经侵入右边屏幕去了
这是正常时的样子 问题影响范围
这个问题自 Qt5.x.x 到前天刚发布的 Qt6.8.2 一直存在。
无论是 Qt Widgets 窗口还是 Qt Quick 窗口都有这个问题。
解决方案思路
如果是 Qt Widgets窗口 那么你就直接用系统API来创建窗口 hwnd CreateWindowEx(exStyle,
LScreenCapture, LScreenCapture,
style,x, y, w, h,
NULL, NULL, hinstance,
NULL);
然后把 QImage 渲染到这个原生窗口中
if (img.isNull()) return;
HDC hdc GetDC(hwnd);
auto compDC CreateCompatibleDC(NULL);
auto bitmap CreateCompatibleBitmap(hdc, w, h);
DeleteObject(SelectObject(compDC, bitmap));BITMAPINFO info { sizeof(BITMAPINFOHEADER), w, 0 - h, 1, 32, BI_RGB, w * 4 * h, 0, 0, 0, 0 };
SetDIBits(hdc, bitmap, 0, h, img.bits(), info, DIB_RGB_COLORS);
BLENDFUNCTION blend { .BlendOp{AC_SRC_OVER}, .SourceConstantAlpha{255}, .AlphaFormat{AC_SRC_ALPHA} };
POINT pSrc { 0, 0 };
SIZE sizeWnd { w, h };
UpdateLayeredWindow(hwnd, hdc, NULL, sizeWnd, compDC, pSrc, NULL, blend, ULW_ALPHA);
ReleaseDC(hwnd, hdc);DeleteDC(compDC);
DeleteObject(bitmap);
然后所有的绘图操作都在这个QImage上进行。
如果是 Qt Quick 窗口那么就要用 QQuickRenderControl 来把QML内容渲染到原生窗口中了代码过于复杂这里就不贴了详情请参考https://doc.qt.io/qt-6/qquickrendercontrol.html
总之就是不要让Qt帮我创建窗口。