#include "framelesswindow.h"#include <QApplication>#include <QPoint>#include <QSize>#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")CFramelessWindow::CFramelessWindow(QWidget *parent): QMainWindow(parent),m_titlebar(Q_NULLPTR),m_borderWidth(5),m_bJustMaximized(false),m_bResizeable(true){// setWindowFlag(Qt::Window,true);// setWindowFlag(Qt::FramelessWindowHint, true);// setWindowFlag(Qt::WindowSystemMenuHint, true);// setWindowFlag() is not avaliable before Qt v5.9, so we should use setWindowFlags insteadsetWindowFlags(windowFlags() | Qt::Window | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);setResizeable(m_bResizeable);}void CFramelessWindow::setResizeable(bool resizeable){bool visible = isVisible();m_bResizeable = resizeable;if (m_bResizeable){setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint);// setWindowFlag(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() laterHWND 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);// setWindowFlag(Qt::WindowMaximizeButtonHint,false);HWND hwnd = (HWND)this->winId();DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);::SetWindowLong(hwnd, GWL_STYLE, style & ~WS_MAXIMIZEBOX & ~WS_CAPTION);}//保留一个像素的边框宽度,否则系统不会绘制边框阴影////we better left 1 piexl width of border untouch, so OS can draw nice shadow around itconst MARGINS shadow = { 1, 1, 1, 1 };DwmExtendFrameIntoClientArea(HWND(winId()), &shadow);setVisible(visible);}void CFramelessWindow::setResizeableAreaWidth(int width){if (1 > width) width = 1;m_borderWidth = width;}void CFramelessWindow::setTitleBar(QWidget* titlebar){m_titlebar = titlebar;if (!titlebar) return;connect(titlebar, SIGNAL(destroyed(QObject*)), this, SLOT(onTitleBarDestroyed()));}void CFramelessWindow::onTitleBarDestroyed(){if (m_titlebar == QObject::sender()){m_titlebar = Q_NULLPTR;}}void CFramelessWindow::addIgnoreWidget(QWidget* widget){if (!widget) return;if (m_whiteList.contains(widget)) return;m_whiteList.append(widget);}bool CFramelessWindow::nativeEvent(const QByteArray &eventType, void *message, long *result){//Workaround for known bug -> check Qt forum : https://forum.qt.io/topic/93141/qtablewidget-itemselectionchanged/13#if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))MSG* msg = *reinterpret_cast<MSG**>(message);#elseMSG* msg = reinterpret_cast<MSG*>(message);#endifswitch (msg->message){case WM_NCCALCSIZE:{NCCALCSIZE_PARAMS& params = *reinterpret_cast<NCCALCSIZE_PARAMS*>(msg->lParam);if (params.rgrc[0].top != 0)params.rgrc[0].top -= 1;//this kills the window frame and title bar we added with WS_THICKFRAME and WS_CAPTION*result = WVR_REDRAW;return true;}case WM_NCHITTEST:{*result = 0;const LONG border_width = m_borderWidth;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 borderif (x >= winrect.left && x < winrect.left + border_width){*result = HTLEFT;}//right borderif (x < winrect.right && x >= winrect.right - border_width){*result = HTRIGHT;}}if(resizeHeight){//bottom borderif (y < winrect.bottom && y >= winrect.bottom - border_width){*result = HTBOTTOM;}//top borderif (y >= winrect.top && y < winrect.top + border_width){*result = HTTOP;}}if(resizeWidth && resizeHeight){//bottom left cornerif (x >= winrect.left && x < winrect.left + border_width &&y < winrect.bottom && y >= winrect.bottom - border_width){*result = HTBOTTOMLEFT;}//bottom right cornerif (x < winrect.right && x >= winrect.right - border_width &&y < winrect.bottom && y >= winrect.bottom - border_width){*result = HTBOTTOMRIGHT;}//top left cornerif (x >= winrect.left && x < winrect.left + border_width &&y >= winrect.top && y < winrect.top + border_width){*result = HTTOPLEFT;}//top right cornerif (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 areaif (!m_titlebar) return false;//support highdpidouble 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;} //end case WM_NCHITTESTcase WM_GETMINMAXINFO:{if (::IsZoomed(msg->hwnd)) {RECT frame = { 0, 0, 0, 0 };AdjustWindowRectEx(&frame, WS_OVERLAPPEDWINDOW, FALSE, 0);//record frame area datadouble dpr = this->devicePixelRatioF();m_frames.setLeft(abs(frame.left)/dpr+0.5);m_frames.setTop(abs(frame.bottom)/dpr+0.5);m_frames.setRight(abs(frame.right)/dpr+0.5);m_frames.setBottom(abs(frame.bottom)/dpr+0.5);QMainWindow::setContentsMargins(m_frames.left()+m_margins.left(), \m_frames.top()+m_margins.top(), \m_frames.right()+m_margins.right(), \m_frames.bottom()+m_margins.bottom());m_bJustMaximized = true;}else {if (m_bJustMaximized){QMainWindow::setContentsMargins(m_margins);m_frames = QMargins();m_bJustMaximized = false;}}return false;}default:return QMainWindow::nativeEvent(eventType, message, result);}}void CFramelessWindow::setContentsMargins(const QMargins &margins){QMainWindow::setContentsMargins(margins+m_frames);m_margins = margins;}void CFramelessWindow::setContentsMargins(int left, int top, int right, int bottom){QMainWindow::setContentsMargins(left+m_frames.left(),\top+m_frames.top(), \right+m_frames.right(), \bottom+m_frames.bottom());m_margins.setLeft(left);m_margins.setTop(top);m_margins.setRight(right);m_margins.setBottom(bottom);}QMargins CFramelessWindow::contentsMargins() const{QMargins margins = QMainWindow::contentsMargins();margins -= m_frames;return margins;}void CFramelessWindow::getContentsMargins(int *left, int *top, int *right, int *bottom) const{QMainWindow::getContentsMargins(left,top,right,bottom);if (!(left&&top&&right&&bottom)) return;if (isMaximized()){*left -= m_frames.left();*top -= m_frames.top();*right -= m_frames.right();*bottom -= m_frames.bottom();}}QRect CFramelessWindow::contentsRect() const{QRect rect = QMainWindow::contentsRect();int width = rect.width();int height = rect.height();rect.setLeft(rect.left() - m_frames.left());rect.setTop(rect.top() - m_frames.top());rect.setWidth(width);rect.setHeight(height);return rect;}void CFramelessWindow::showFullScreen(){if (isMaximized()){QMainWindow::setContentsMargins(m_margins);m_frames = QMargins();}QMainWindow::showFullScreen();}#endif //Q_OS_WIN
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。