欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

手把手教你写产品级QT项目(二)--

时间:2023-04-29
前言

我们今天实现一个无边框,带窗口阴影,可拖拽、伸缩的窗口。

第一步

去除qt窗口的边框、工具栏等属性。我们的窗口的类Window,继承于QWidget这个基础的控件类,然后直接在构造函数内一句函数搞定:

Window::Window(const QSize &initSize, QWidget *parent) : QWidget(parent){// 设置窗口大小 resize(initSize);// 去除边框 setWindowFlags(Qt::Window |Qt::framelessWindowHint);}

在主程序内直接show这个窗口类:

int main(int argc, char **argv){ QApplication app(argc, argv); Window *mainWindow = new Window(QSize(994,650); mainWindow->show(); return app.exec();}

效果如下(桌面背景为白色):

第二步,给它套个阴影

Window::Window(const QSize &initSize, QWidget *parent) : QWidget(parent){ resize(initSize); setWindowFlags(Qt::Window |Qt::framelessWindowHint); HWND hwnd = reinterpret_cast(winId()); LONG style = static_cast( WS_POPUP | WS_CAPTION | (true ? WS_MINIMIZEBOX : 0) | (true ? WS_MAXIMIZEBOX : 0) | WS_THICKframe | WS_CLIPCHILDREN ); ::SetWindowLongPtr(hwnd, GWL_STYLE, style); const MARGINS shadow = {1, 1, 1, 1}; DwmExtendframeIntoClientArea(hwnd, &shadow);}

效果如下:

第三步,加上实现可拖拽、伸缩效果

原理是重写nativeEvent函数,处理windows下的鼠标事件,其实也就是把窗口边界的事件转化为Windows的窗口事件

bool Window::nativeEvent(const QByteArray &eventType, void *message, long *result){if (eventType != "windows_generic_MSG")return false;MSG* msg = reinterpret_cast(message);QWidget* widget = QWidget::find(reinterpret_cast(msg->hwnd));if (!widget)return false;switch (msg->message) {case WM_NCCALCSIZE:{*result = 0;return true;}case WM_NCHITTEST:{const LONG borderWidth = 9;RECT winrect;::GetWindowRect(msg->hwnd, &winrect);long x = GET_X_LPARAM(msg->lParam);long y = GET_Y_LPARAM(msg->lParam);if (m_resizeable && m_freeSizeable){// bottom leftif (x >= winrect.left && x < winrect.left + borderWidth &&y < winrect.bottom && y >= winrect.bottom - borderWidth){*result = HTBOTTOMLEFT;return true;}// bottom rightif (x < winrect.right && x >= winrect.right - borderWidth &&y < winrect.bottom && y >= winrect.bottom - borderWidth){*result = HTBOTTOMRIGHT;return true;}// top leftif (x >= winrect.left && x < winrect.left + borderWidth &&y >= winrect.top && y < winrect.top + borderWidth){*result = HTTOPLEFT;return true;}// top rightif (x < winrect.right && x >= winrect.right - borderWidth &&y >= winrect.top && y < winrect.top + borderWidth){*result = HTTOPRIGHT;return true;}// leftif (x >= winrect.left && x < winrect.left + borderWidth){*result = HTLEFT;return true;}// rightif (x < winrect.right && x >= winrect.right - borderWidth){*result = HTRIGHT;return true;}// bottomif (y < winrect.bottom && y >= winrect.bottom - borderWidth){*result = HTBOTTOM;return true;}// topif (y >= winrect.top && y < winrect.top + borderWidth){*result = HTTOP;return true;}}// 高分屏double dpr = this->devicePixelRatioF();QPoint pos = mapFromGlobal(QPoint(static_cast(x/dpr), static_cast(y/dpr)));// 全区域移动,前提是窗口内没有子控件,有的话需要加入m_ignoreListif (m_fullAreaMoveable){if (!rect().contains(pos)) return false;QWidget *curParent = this;while (1){QWidget* child = curParent->childAt(pos);if (!child){*result = HTCAPTION;return true;}else{// 当鼠标在m_ignoreList列表的窗口子控件内时才能拖动窗口if (m_ignoreList.contains(child)){curParent = child;continue;}elsebreak;}}break;}// 标题栏移动if (!m_titleBar) return false;if (!m_titleBar->rect().contains(pos)) return false;QWidget* child = m_titleBar->childAt(pos);if (!child){*result = HTCAPTION;return true;}return false;}case WM_GETMINMAXINFO:{// 最大化窗口部件位置修正if (::IsZoomed(msg->hwnd)){RECT frame = { 0, 0, 0, 0 };AdjustWindowRectEx(&frame, WS_OVERLAPPEDWINDOW, FALSE, 0);frame.left = abs(frame.left);frame.top = abs(frame.bottom);widget->setContentsMargins(frame.left, frame.top, frame.right, frame.bottom);}else{widget->setContentsMargins(0, 0, 0, 0);}// 限定最小及最大窗口reinterpret_cast(msg->lParam)->ptMinTrackSize.x = minimumWidth();reinterpret_cast(msg->lParam)->ptMinTrackSize.y = minimumHeight();reinterpret_cast(msg->lParam)->ptMaxTrackSize.x = maximumWidth();reinterpret_cast(msg->lParam)->ptMaxTrackSize.y = maximumHeight();*result = ::DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);return true;}default:break;}return QWidget::nativeEvent(eventType, message, result);}// 加入全局拖拽时的控件忽略列表void Window::AddToMoveableIgnoreList(QWidget *widget){m_ignoreList.append(widget);}// 使能全局拖拽void Window::SetFullAreaMoveable(bool enable){m_fullAreaMoveable = enable;}

这样调用窗口

int main(int argc, char **argv){ QApplication app(argc, argv); Window *mainWindow = new Window(QSize(994, 650)); mainWindow->SetFullAreaMoveable(true); mainWindow->SetResizeable(true); mainWindow->show(); return app.exec();}

效果如下:

如有疑问欢迎交流

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。