Qt自定义无边框窗口技术选型测试

1 篇文章 0 订阅

实现无边框窗口很容易,直接setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint)即可。虽然这种方式有弊端:无法通过拖拽窗口到屏幕边缘实现窗口最大化或半屏显示等WIN10原生窗口操作。

很想了解Chrome怎么实现的,但没有找到具体的代码或详细的说明,如果有大神可以指点一下最好。

测试下来,有三种方式:

1. 最传统的FramelessWindow,用widget做成假的标题栏和边框,样式可以利用qt做,最简单稳定的,我最后还是选择这个,推荐大家使用。缺点是不支持拖放标题栏或边框实现窗口最大化等WIN10窗口操作。

2. 通过响应WM_NCPAINT消息,自己绘制非用户区,实现比较麻烦,还发现半透明边框的实现有问题,还要考虑不同系统标题栏的高度,一会贴测试代码。

3. 通过响应WM_NCCALCSIZE消息,修改非用户区的尺寸或直接隐藏非用户区,相对方案1的好处是原生支持WIN10利用非用户区进行窗口操作,缺点是发现在集成显卡上显示内嵌浏览器时显示不正常。

Qt版本5.9.2,利用方法一时自己响应2个WINDOWS消息:
WM_NCHITTEST: 分别处理最大化和正常显示时鼠标指针在窗体的位置。
WM_NCLBUTTONDBLCLK: 处理双击标题栏时窗口最大化。系统默认是全屏,会导致菜单无法显示。

重绘标题栏的测试代码贴一下,主要问题是,半透明边框下面的窗口区域是白色时,看起来还可以。如果下面窗口区域是黑色,半透明边框就呈现出不透明的效果,一番挣扎后放弃研究了。

RECT winRect, winClientRect;
HWND hwnd = (HWND)winId();
::GetWindowRect(hwnd, &winRect);
::GetClientRect(hwnd, &winClientRect);
HDC hwdc = ::GetWindowDC(hwnd);
LONG lStyle = ::GetWindowLongW(hwnd, GWL_STYLE);

POINT ptTopLeft = {winClientRect.left, winClientRect.top};
POINT ptBottomRight = {winClientRect.right, winClientRect.bottom};

::ClientToScreen(hwnd, &ptTopLeft);
::ClientToScreen(hwnd, &ptBottomRight);

winClientRect.left = ptTopLeft.x - winRect.left;
winClientRect.right = ptBottomRight.x - winRect.left;
winClientRect.top = ptTopLeft.y - winRect.top;
winClientRect.bottom = ptBottomRight.y - winRect.top;

auto winWidth = winRect.right - winRect.left;
auto winHeight = winRect.bottom - winRect.top;

HRGN hRgnOuter = ::CreateRectRgn(0, 0, winWidth, winHeight);
HRGN hRgnInner = ::CreateRectRgnIndirect(&winClientRect);
HRGN hRgnCombine = ::CreateRectRgn(0, 0, winWidth, winHeight);
::CombineRgn(hRgnCombine, hRgnOuter, hRgnInner, RGN_DIFF);
::SelectClipRgn(hwdc, hRgnCombine);

QPixmap pix(winWidth, winHeight);
pix.fill(QColor(0,255,0,0));
QPainter paint(&pix);
QRect rc(0, 0, winWidth, winHeight);

int xFrame = winClientRect.left;
int yFrame = winHeight - winClientRect.bottom;
int captionHeight = winClientRect.top;

//paint.fillRect(rc, QColor(255, 0, 0, 0));
QLinearGradient grad(0, 0, 0, captionHeight);
grad.setColorAt(0, QColor(0,0,0,0));
grad.setColorAt(0.7, QColor(0,0,0,0));
grad.setColorAt(0.9, QColor(255,255,255,20));
grad.setColorAt(1, QColor(255,255,255,40));
paint.fillRect(QRect(xFrame, 0, winWidth-xFrame*2, captionHeight), grad);

BITMAPINFO bmpInfo;
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = winWidth;
bmpInfo.bmiHeader.biHeight = -winHeight;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biSizeImage = 0;
bmpInfo.bmiHeader.biXPelsPerMeter = 0;
bmpInfo.bmiHeader.biYPelsPerMeter = 0;
bmpInfo.bmiHeader.biClrUsed = 0;
bmpInfo.bmiHeader.biClrImportant = 0;

HDC hdc = ::CreateCompatibleDC(hwdc);
HBITMAP hBmp = ::CreateCompatibleBitmap(hwdc, winWidth, winHeight);

auto img = pix.toImage().convertToFormat(QImage::Format_ARGB32);
auto imgData = img.constBits();
::SetDIBits(hdc, hBmp, 0, winHeight, imgData, &bmpInfo, DIB_RGB_COLORS);
qDebug() << QString("%1,%2,%3,%4")
        .arg(imgData[0]).arg(imgData[1]).arg(imgData[2]).arg(imgData[3]);

::SelectObject(hdc, hBmp);
::BitBlt(hwdc, 0, 0, winWidth, winHeight, hdc, 0, 0, SRCCOPY);
::DeleteDC(hdc);
::DeleteObject(hBmp);

::DeleteObject(hRgnOuter);
::DeleteObject(hRgnInner);
::DeleteObject(hRgnCombine);
::ReleaseDC(hwnd, hwdc);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值