首页| 论坛| 消息
主题:更加“Native”的方式实现无边框可拖动调整大小的阴影窗口
nyyzpp发表于 2014-03-03 00:09
Qt Version:Qt5.2.1
Platform:windows 7
实现目的:网上很多类似的教程,但最终都会产生或多或少的负面作用,例如窗口闪烁、需要自定义最大化方法显示方法(就需要使用多个变量来存储窗口状态)、计算调整窗口的边界在哪(逻辑过程复杂,并且需要和窗口拖动一起判断)等等,也许还会面临更多问题,这里不一一列出。为了能够更加“native”的方式去实现无边框可以拖动和调整大小的阴影窗口,查阅各种资料(主要参考msdn library),小有成果,切不敢独享。
实现过程:
1. 去除边框,是背景透明:this->setWindowFlags(Qt::FramelessWindowHint);
this->setAttribute(Qt::WA_TranslucentBackground);
背景透明的目的是为了能够重画阴影窗口
2. 重载paintEvent函数:void QShadowDialog::paintEvent(QPaintEvent *)
{
Q_D(QShadowDialog);
QSize verticalShadowSize = QSize(d->shadowSize, this->height() - d->shadowSize*2);
QSize horizontalShadowSize = QSize(this->width() - shadowSize()*2, d->shadowSize);
QSize cornerShadowSize = QSize(d->shadowSize, d->shadowSize);

QRect leftRectangle= QRect(QPoint(0, d->shadowSize), verticalShadowSize);
QRect leftTopRectangle = QRect(QPoint(0, 0), cornerShadowSize);
QRect topRectangle = QRect(QPoint(d->shadowSize, 0), horizontalShadowSize);
QRect rightTopRectangle= QRect(QPoint(this->width() - d->shadowSize, 0), cornerShadowSize);
QRect rightRectangle = QRect(QPoint(this->width() - d->shadowSize, d->shadowSize), verticalShadowSize);
QRect rightBottomRectangle = QRect(QPoint(this->width() - d->shadowSize, this->height() - d->shadowSize), cornerShadowSize);
QRect bottomRectangle= QRect(QPoint(d->shadowSize, this->height() - d->shadowSize), horizontalShadowSize);
QRect leftBottomRectangle= QRect(QPoint(0, this->height() - d->shadowSize), cornerShadowSize);

QPainter painter(this);
painter.drawPixmap(leftRectangle,d->shadowPixmapList[0].scaled(verticalShadowSize));
painter.drawPixmap(leftTopRectangle, d->shadowPixmapList[1].scaled(cornerShadowSize));
painter.drawPixmap(topRectangle, d->shadowPixmapList[2].scaled(horizontalShadowSize));
painter.drawPixmap(rightTopRectangle,d->shadowPixmapList[3].scaled(cornerShadowSize));
painter.drawPixmap(rightRectangle, d->shadowPixmapList[4].scaled(verticalShadowSize));
painter.drawPixmap(rightBottomRectangle, d->shadowPixmapList[5].scaled(cornerShadowSize));
painter.drawPixmap(bottomRectangle,d->shadowPixmapList[6].scaled(horizontalShadowSize));
painter.drawPixmap(leftBottomRectangle,d->shadowPixmapList[7].scaled(cornerShadowSize));

painter.setPen(Qt::NoPen);
painter.setBrush(Qt::white);
painter.drawRect(d->shadowSize, d->shadowSize, this->width() - d->shadowSize*2, this->height() - d->shadowSize*2);
}这里是为了画出阴影背景,可以参考之前360实现的代码,并非来自本人的成果。

3.响应系统消息,重载nativeEvent(Qt4.x中,应该重载winEvent)
这里开始跟网上的大多教程不一致了,网上大多教程叫你使用mouseMoveEvent,mousePressEvent和mouseReleaseEvent,但是这样做会产生很多副作用,具体什么副作用,上面有列出。于是从其他想法入手,查找资料发现网上一个WPF的实现,于是突发奇想,Qt也可以响应WM_消息,为何不从这里入手,把窗口移动、调整大小的工作交给操作系统处理呢?于是就有了下列代码:
bool QShadowDialog::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
Q_UNUSED(eventType)
Q_D(QShadowDialog);

MSG* param = static_cast(message);
switch (param->message) {
case WM_NCHITTEST: {
HWND hWnd = (HWND)this->winId();
int x = GET_X_LPARAM(param->lParam) - this->geometry().x();
int y = GET_Y_LPARAM(param->lParam) - this->geometry().y();

//! [1] 指定标题栏区域
if (this->childAt(x, y)) {
return false;
}
else {
*result = HTCAPTION;
}
//! [1]

//! [2] 如果窗口最大化了,则不支持resize
if (IsZoomed(hWnd)) return true;
if (!d->resizable) return true;
//! [2]

if (x > 0 && x < d->shadowSi
附件: QtWidgetsExtend.rar (17 K) 下载次数:207
下一页 (1/3)
回帖(11):
11楼:
10楼:给力帖子 顶
9楼:看起来很不错

全部回帖(11)»
最新回帖
收藏本帖
发新帖