赞
踩
我们知道QWidget等设置了this->setWindowFlags(Qt::FramelessWindowHint);
后无法移动和调整大小,但实际项目中是需要窗口能够调整大小的。所以以实现FrameLess弹窗调整大小及移动弹窗需求,并且在Windows 10上有Aero效果。
先看一下效果:
大部分参考这个github。然后自己修改了一下,因为github上面的,在设置了qss后怎么也实现不了窗口圆角以阴影。下面修改版的代码可以实现圆角,但也没有阴影,只能在Widget中自己实现阴影了。
如果不需要圆角,github上面的也是会自带阴影的。不用下面的调整版实现方案。
#ifndef AEROMAINWINDOW_H #define AEROMAINWINDOW_H #include <QMainWindow> class AeroMainWindow : public QMainWindow { Q_OBJECT public: explicit AeroMainWindow(QWidget *parent = nullptr); ~AeroMainWindow(); //设置是否可以通过鼠标调整窗口大小 //if resizeable is set to false, then the window can not be resized by mouse //but still can be resized programtically void setResizeable(bool resizeable=true); bool isResizeable(){return m_bResizeable;} //设置可调整大小区域的宽度,在此区域内,可以使用鼠标调整窗口大小 //set border width, inside this aera, window can be resized by mouse void setResizeableAreaWidth(int width = 5); protected: //设置一个标题栏widget,此widget会被当做标题栏对待 //set a widget which will be treat as SYSTEM titlebar void setTitleBar(QWidget* titlebar); //在标题栏控件内,也可以有子控件如标签控件“label1”,此label1遮盖了标题栏,导致不能通过label1拖动窗口 //要解决此问题,使用addIgnoreWidget(label1) //generally, we can add widget say "label1" on titlebar, and it will cover the titlebar under it //as a result, we can not drag and move the MainWindow with this "label1" again //we can fix this by add "label1" to a ignorelist, just call addIgnoreWidget(label1) void addIgnoreWidget(QWidget* widget); bool nativeEvent(const QByteArray &eventType, void *message, long *result); void resizeEvent(QResizeEvent *event); public slots: private slots: void onTitleBarDestroyed(); private: QWidget *m_titleBar; QList<QWidget*> m_whiteList; int m_borderWidth; bool m_bResizeable; }; #endif // AEROMAINWINDOW_H
#include "aeromainwindow.h" #include <QGraphicsDropShadowEffect> #include <QDesktopServices> #include <QUrl> #include <QGridLayout> #include <QStyle> #include <QDebug> #include <QPushButton> #ifdef Q_OS_WIN #include <windows.h> #include <WinUser.h> #include <windowsx.h> #include <dwmapi.h> #include <objidl.h> // Fixes error C2504: 'IUnknown' : base class undefined #include <gdiplus.h> #include <GdiPlusColor.h> #pragma comment (lib,"Dwmapi.lib") // Adds missing library, fixes error LNK2019: unresolved external symbol __imp__DwmExtendFrameIntoClientArea #pragma comment (lib,"user32.lib") #endif AeroMainWindow::AeroMainWindow(QWidget *parent) : QMainWindow(parent), m_titleBar(Q_NULLPTR), m_borderWidth(5), m_bResizeable(true) { this->setAttribute(Qt::WA_TranslucentBackground);//设置窗口背景透明 this->setWindowFlags(Qt::FramelessWindowHint); //设置无边框窗口 this->setResizeable(true); } AeroMainWindow::~AeroMainWindow() { } void AeroMainWindow::setResizeable(bool resizeable) { bool visible = isVisible(); m_bResizeable = resizeable; if (m_bResizeable) { setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint); //此行代码可以带回Aero效果,同时也带回了标题栏和边框,在nativeEvent()会再次去掉标题栏 // //this line will get titlebar/thick frame/Aero back, which is exactly what we want //we will get rid of titlebar and thick frame again in nativeEvent() later HWND hwnd = (HWND)this->winId(); DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); ::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION); } else { setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint); HWND hwnd = (HWND)this->winId(); DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); ::SetWindowLong(hwnd, GWL_STYLE, style & ~WS_MAXIMIZEBOX & ~WS_CAPTION); } //保留一个像素的边框宽度,否则系统不会绘制边框阴影 const MARGINS shadow = { 1, 1, 1, 1 }; DwmExtendFrameIntoClientArea(HWND(winId()), &shadow); setVisible(visible); } void AeroMainWindow::setResizeableAreaWidth(int width) { if (1 > width) width = 1; m_borderWidth = width; } void AeroMainWindow::setTitleBar(QWidget* titlebar) { m_titleBar = titlebar; if (!titlebar) return; connect(titlebar, SIGNAL(destroyed(QObject*)), this, SLOT(onTitleBarDestroyed())); } void AeroMainWindow::onTitleBarDestroyed() { if (m_titleBar == QObject::sender()) { m_titleBar = Q_NULLPTR; } } void AeroMainWindow::addIgnoreWidget(QWidget* widget) { if (!widget) return; if (m_whiteList.contains(widget)) return; m_whiteList.append(widget); } bool AeroMainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) { MSG* msg = (MSG *)message; switch (msg->message) { case WM_NCCALCSIZE: { //this kills the window frame and title bar we added with //WS_THICKFRAME and WS_CAPTION *result = 0; return true; } // WM_NCCALCSIZE case WM_NCHITTEST: { *result = 0; const LONG border_width = m_borderWidth; //in pixels RECT winrect; GetWindowRect(HWND(winId()), &winrect); long x = GET_X_LPARAM(msg->lParam); long y = GET_Y_LPARAM(msg->lParam); if(m_bResizeable) { bool resizeWidth = minimumWidth() != maximumWidth(); bool resizeHeight = minimumHeight() != maximumHeight(); if(resizeWidth) { //left border if (x >= winrect.left && x < winrect.left + border_width) { *result = HTLEFT; } //right border if (x < winrect.right && x >= winrect.right - border_width) { *result = HTRIGHT; } } if(resizeHeight) { //bottom border if (y < winrect.bottom && y >= winrect.bottom - border_width) { *result = HTBOTTOM; } //top border if (y >= winrect.top && y < winrect.top + border_width) { *result = HTTOP; } } if(resizeWidth && resizeHeight) { //bottom left corner if (x >= winrect.left && x < winrect.left + border_width && y < winrect.bottom && y >= winrect.bottom - border_width) { *result = HTBOTTOMLEFT; } //bottom right corner if (x < winrect.right && x >= winrect.right - border_width && y < winrect.bottom && y >= winrect.bottom - border_width) { *result = HTBOTTOMRIGHT; } //top left corner if (x >= winrect.left && x < winrect.left + border_width && y >= winrect.top && y < winrect.top + border_width) { *result = HTTOPLEFT; } //top right corner if (x < winrect.right && x >= winrect.right - border_width && y >= winrect.top && y < winrect.top + border_width) { *result = HTTOPRIGHT; } } } if (0 != *result) return true; //*result still equals 0, that means the cursor locate OUTSIDE the frame area //but it may locate in titlebar area if (!m_titleBar) return false; //support highdpi double dpr = this->devicePixelRatioF(); QPoint pos = m_titleBar->mapFromGlobal(QPoint(x/dpr,y/dpr)); if (!m_titleBar->rect().contains(pos)) return false; QWidget* child = m_titleBar->childAt(pos); if (!child) { *result = HTCAPTION; return true; } else { if (m_whiteList.contains(child)) { *result = HTCAPTION; return true; } } return false; } // WM_NCHITTEST default: return QMainWindow::nativeEvent(eventType, msg, result); } } void AeroMainWindow::resizeEvent(QResizeEvent *event) { if (m_titleBar) m_titleBar->setGeometry(QRect(0, 0, this->rect().width(), m_titleBar->rect().height())); QMainWindow::resizeEvent(event); }
生成一个类,继承上面的类。然后实现下面的内容。很简单:
#include "testmainwindow.h" #include "ui_testmainwindow.h" TestMainWindow::TestMainWindow(QWidget *parent) : AeroMainWindow(parent), ui(new Ui::TestMainWindow) { ui->setupUi(this); QWidget *titleBar = new QWidget(this); titleBar->setGeometry(QRect(0, 0, this->rect().width(), 25)); this->setTitleBar(titleBar); this->setStyleSheet("background-color: red;\ border-radius: 8px;"); } TestMainWindow::~TestMainWindow() { delete ui; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。