├── .gitignore ├── README.md ├── bin ├── libTest.exe └── libTest.pdb ├── common.pri ├── lib ├── FramelessWindow.exp ├── FramelessWindow.lib ├── FramelessWindowd.exp ├── FramelessWindowd.ilk ├── FramelessWindowd.lib ├── FramelessWindowd.pdb ├── libFramelessWindow.so.1 ├── libFramelessWindow.so.1.0 └── libFramelessWindow.so.1.0.0 ├── libFramelessWindow ├── FramelessWindow_Global.h ├── MuCursorPosCalculator.cpp ├── MuCursorPosCalculator.h ├── MuCustomWindow.cpp ├── MuCustomWindow.h ├── MuFramelessHelper.cpp ├── MuFramelessHelper.h ├── MuFramelessHelperPrivate.h ├── MuShadowWidget.cpp ├── MuShadowWidget.h ├── MuShadowWindow.h ├── MuTitleBar.cpp ├── MuTitleBar.h ├── MuWidgetData.cpp ├── MuWidgetData.h ├── MuWinDWMAPI.cpp ├── MuWinDWMAPI.h ├── MuWinTitlebar.cpp ├── MuWinTitlebar.h ├── MuWinWindow.cpp ├── MuWinWindow.h ├── images.qrc ├── images │ ├── closeBtnBlack_16.png │ ├── closeBtnWhite_16.png │ ├── errorRed_48.png │ ├── informationBlue_48.png │ ├── logo.jpg │ ├── maximizeBtnBlack_16.png │ ├── maximizeBtnWhite_16.png │ ├── minimizeBtnBlack_16.png │ ├── minimizeBtnWhite_16.png │ ├── questionBlue_48.png │ ├── restoreBlack_16.png │ ├── restoreWhite_16.png │ ├── successGreen_48.png │ ├── warningYellow_48.png │ └── winwindow │ │ ├── 1.jpg │ │ ├── close.png │ │ ├── maximize.png │ │ ├── minimize.png │ │ └── restore.png ├── libFramelessWindow.pri └── libFramelessWindow.pro ├── libTest ├── AeroClientWidget.ui ├── MainWindow.cpp ├── MainWindow.h ├── MainWindow.ui ├── StyleSheetHelper.h ├── images.qrc ├── images │ ├── closeBtn32_Gray.png │ ├── closeBtn32_White.png │ ├── closeBtnBlack_16.png │ ├── closeBtnWhite_16.png │ ├── errorRed_48.png │ ├── informationBlue_48.png │ ├── logo.jpg │ ├── maxBtn32_Gray.png │ ├── maxBtn32_White.png │ ├── maximizeBtnBlack_16.png │ ├── maximizeBtnWhite_16.png │ ├── minBtn32_Gray.png │ ├── minBtn32_White.png │ ├── minimizeBtnBlack_16.png │ ├── minimizeBtnWhite_16.png │ ├── questionBlue_48.png │ ├── restoreBlack_16.png │ ├── restoreBtn32_Gray.png │ ├── restoreBtn32_White.png │ ├── restoreWhite_16.png │ ├── successGreen_48.png │ └── warningYellow_48.png ├── libTest.pro ├── main.cpp ├── qss.qrc └── style.qss ├── projectFramelessWindow.pro └── samples ├── AeroWindow.png ├── CustomDialog.png ├── CustomInformationMessagBox.png ├── CustomSuccessMessageBox.png ├── CustomWindow.png ├── scaleAndMove_noRubber.gif └── scaleAndMove_withRubber.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | *.txt 13 | *.Debug 14 | *.Release 15 | 16 | # Qt-es 17 | bin/ 18 | /.qmake.cache 19 | /.qmake.stash 20 | bin/ 21 | *.pro.user 22 | *.pro.user.* 23 | *.qbs.user 24 | *.qbs.user.* 25 | *.moc 26 | moc_*.cpp 27 | moc_*.h 28 | qrc_*.cpp 29 | ui_*.h 30 | Makefile* 31 | *build-* 32 | 33 | # QtCreator 34 | 35 | *.autosave 36 | 37 | # QtCtreator Qml 38 | *.qmlproject.user 39 | *.qmlproject.user.* 40 | 41 | # QtCtreator CMake 42 | CMakeLists.txt.user* 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FramelessWindow-Qt 2 | 自定义无边框窗体,对话框和提示框,添加边框阴影,同时支持Winndows和Ubuntu系统。Windows系统下支持部分Aero效果。 3 | 4 | FlyWM_ 5 | GitHub: https://github.com/FlyWM 6 | CSDN: https://blog.csdn.net/a844651990 7 | 8 | # 使用方法 9 | 1. 只需要包含头文件 MuCustomWindow.h 即可。 10 | 2. 设置客户区域的widget调用函数 void setClientWidget(QWidget *client)或者调用QLayout* clientLayout()函数去添加自己需要的widget。 11 | 3. 获取标题栏MuTitleBar *titleBar() const,然后可以获取标题栏的各个部分。 12 | 4. 如果想要在标题栏添加选项,可以调用titleBar()->customWidget()获取出去按钮、图标和标题之外的widget。 13 | 14 | 15 | # 效果图: 16 | ### Window 17 | ![image](https://github.com/FlyWM/FramelessWindow-Qt/blob/master/samples/CustomWindow.png) 18 | 19 | ### Dialog 20 | ![image](https://github.com/FlyWM/FramelessWindow-Qt/blob/master/samples/CustomDialog.png) 21 | 22 | ### Information MessageBox 23 | ![image](https://github.com/FlyWM/FramelessWindow-Qt/blob/master/samples/CustomInformationMessagBox.png) 24 | 25 | ### Success MessageBox 26 | ![image](https://github.com/FlyWM/FramelessWindow-Qt/blob/master/samples/CustomSuccessMessageBox.png) 27 | 28 | ### Aero Window 目前只支持最大化和还原时的动态效果 29 | ![image](https://github.com/FlyWM/FramelessWindow-Qt/blob/master/samples/AeroWindow.png) 30 | 31 | ### 拖动窗口变大,不带橡皮筋效果 32 | ![image](https://github.com/FlyWM/FramelessWindow-Qt/blob/master/samples/scaleAndMove_noRubber.gif) 33 | 34 | ### 拖动窗口变大,带橡皮筋效果 35 | ![image](https://github.com/FlyWM/FramelessWindow-Qt/blob/master/samples/scaleAndMove_withRubber.gif) 36 | -------------------------------------------------------------------------------- /bin/libTest.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/bin/libTest.exe -------------------------------------------------------------------------------- /bin/libTest.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/bin/libTest.pdb -------------------------------------------------------------------------------- /common.pri: -------------------------------------------------------------------------------- 1 | #--------------------------------------------- 2 | # 自定义无边框窗体、对话框和提示框 3 | # 4 | # common.pri 5 | # 工程文件 libFramelessWindow 和 libTest 通用 pri 文件 6 | # 7 | # FlyWM_ 8 | # GitHub: https://github.com/FlyWM 9 | # CSDN: https://blog.csdn.net/a844651990 10 | # 11 | #--------------------------------------------- 12 | 13 | # bin 目录 14 | PROJECT_BINDIR = $$PWD/bin 15 | 16 | # lib目录 17 | PROJECT_LIBDIR = $$PWD/lib 18 | -------------------------------------------------------------------------------- /lib/FramelessWindow.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/lib/FramelessWindow.exp -------------------------------------------------------------------------------- /lib/FramelessWindow.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/lib/FramelessWindow.lib -------------------------------------------------------------------------------- /lib/FramelessWindowd.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/lib/FramelessWindowd.exp -------------------------------------------------------------------------------- /lib/FramelessWindowd.ilk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/lib/FramelessWindowd.ilk -------------------------------------------------------------------------------- /lib/FramelessWindowd.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/lib/FramelessWindowd.lib -------------------------------------------------------------------------------- /lib/FramelessWindowd.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/lib/FramelessWindowd.pdb -------------------------------------------------------------------------------- /lib/libFramelessWindow.so.1: -------------------------------------------------------------------------------- 1 | libFramelessWindow.so.1.0.0 -------------------------------------------------------------------------------- /lib/libFramelessWindow.so.1.0: -------------------------------------------------------------------------------- 1 | libFramelessWindow.so.1.0.0 -------------------------------------------------------------------------------- /lib/libFramelessWindow.so.1.0.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/lib/libFramelessWindow.so.1.0.0 -------------------------------------------------------------------------------- /libFramelessWindow/FramelessWindow_Global.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * FramelessWindow_Global.h 5 | * 6 | * FlyWM_ 7 | * GitHub: https://github.com/FlyWM 8 | * CSDN: https://blog.csdn.net/a844651990 9 | * 10 | */ 11 | 12 | #ifndef FRAMELESSWINDOW_GLOBAL_H 13 | #define FRAMELESSWINDOW_GLOBAL_H 14 | 15 | #include 16 | 17 | #if defined(FRAMELESSWINDOW_LIBRARY) 18 | # define FRAMELESSWINDOWSHARED_EXPORT Q_DECL_EXPORT 19 | #else 20 | # define FRAMELESSWINDOWSHARED_EXPORT Q_DECL_IMPORT 21 | #endif 22 | 23 | #endif // FRAMELESSWINDOW_GLOBAL_H 24 | -------------------------------------------------------------------------------- /libFramelessWindow/MuCursorPosCalculator.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuCursorPosCalculator.cpp 5 | * 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include "MuCursorPosCalculator.h" 16 | 17 | /** 18 | * @brief MuCursorPosCalculator::m_nBorderWidth 19 | * \warning 20 | * 如果是WinAeroWindow,那么m_nBorderWidth的大小需要和 21 | * titleBar的rigtMargin一致,不然会造成拖放和关闭按钮的冲突 22 | */ 23 | int MuCursorPosCalculator::m_nBorderWidth = 5; 24 | 25 | int MuCursorPosCalculator::m_nTitleHeight = 30; 26 | int MuCursorPosCalculator::m_nShadowWidth = 0; 27 | 28 | MuCursorPosCalculator::MuCursorPosCalculator() 29 | { 30 | reset(); 31 | } 32 | 33 | void MuCursorPosCalculator::reset() 34 | { 35 | m_bOnEdges = false; 36 | m_bOnLeftEdge = false; 37 | m_bOnRightEdge = false; 38 | m_bOnTopEdge = false; 39 | m_bOnBottomEdge = false; 40 | m_bOnTopLeftEdge = false; 41 | m_bOnBottomLeftEdge = false; 42 | m_bOnTopRightEdge = false; 43 | m_bOnBottomRightEdge = false; 44 | } 45 | 46 | void MuCursorPosCalculator::recalculate(const QPoint &gMousePos, const QRect &frameRect) 47 | { 48 | int globalMouseX = gMousePos.x(); 49 | int globalMouseY = gMousePos.y(); 50 | 51 | int frameX = frameRect.x(); 52 | int frameY = frameRect.y(); 53 | 54 | int frameWidth = frameRect.width(); 55 | int frameHeight = frameRect.height(); 56 | 57 | // 边框边缘触发光标变化 58 | // 59 | m_bOnLeftEdge = (globalMouseX >= frameX - m_nBorderWidth && 60 | globalMouseX <= frameX + m_nBorderWidth); 61 | m_bOnRightEdge = (globalMouseX >= frameX + frameWidth - m_nBorderWidth && 62 | globalMouseX <= frameX + frameWidth + m_nBorderWidth); 63 | m_bOnTopEdge = (globalMouseY >= frameY - m_nBorderWidth && 64 | globalMouseY <= frameY + 5); 65 | m_bOnBottomEdge = (globalMouseY >= frameY + frameHeight - m_nBorderWidth && 66 | globalMouseY <= frameY + frameHeight + m_nBorderWidth); 67 | 68 | m_bOnTopLeftEdge = m_bOnTopEdge && m_bOnLeftEdge; 69 | m_bOnBottomLeftEdge = m_bOnBottomEdge && m_bOnLeftEdge; 70 | m_bOnTopRightEdge = m_bOnTopEdge && m_bOnRightEdge; 71 | m_bOnBottomRightEdge = m_bOnBottomEdge && m_bOnRightEdge; 72 | 73 | m_bOnEdges = m_bOnLeftEdge || m_bOnRightEdge || m_bOnTopEdge || m_bOnBottomEdge; 74 | } 75 | -------------------------------------------------------------------------------- /libFramelessWindow/MuCursorPosCalculator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuCursorPosCalculator.h 5 | * 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef MUCURSORPOSCALCULATOR_H 14 | #define MUCURSORPOSCALCULATOR_H 15 | 16 | /** 17 | * @brief The CursorPosCalculator class 18 | * 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角 19 | */ 20 | class QPoint; 21 | class QRect; 22 | class MuCursorPosCalculator 23 | { 24 | public: 25 | explicit MuCursorPosCalculator(); 26 | void reset(); 27 | void recalculate(const QPoint &gMousePos, const QRect &frameRect); 28 | 29 | public: 30 | bool m_bOnEdges : true; 31 | bool m_bOnLeftEdge : true; 32 | bool m_bOnRightEdge : true; 33 | bool m_bOnTopEdge : true; 34 | bool m_bOnBottomEdge : true; 35 | bool m_bOnTopLeftEdge : true; 36 | bool m_bOnBottomLeftEdge : true; 37 | bool m_bOnTopRightEdge : true; 38 | bool m_bOnBottomRightEdge : true; 39 | 40 | static int m_nBorderWidth; 41 | static int m_nTitleHeight; 42 | static int m_nShadowWidth; 43 | }; 44 | 45 | #endif // MuCURSORPOSCALCULATOR_H 46 | -------------------------------------------------------------------------------- /libFramelessWindow/MuCustomWindow.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuCustomWindow.cpp 5 | * 自定义无边框窗体、对话框和提示框的实现文件,主要API实现文件 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "MuCustomWindow.h" 18 | 19 | #ifdef Q_OS_WIN32 20 | #include 21 | #include "MuWinDWMAPI.h" 22 | #endif 23 | 24 | #ifdef Q_CC_MSVC 25 | #pragma comment(lib, "user32.lib") 26 | #endif 27 | 28 | MuCustomWindow::MuCustomWindow(QWidget *parent) 29 | : MuShadowWindow(true, 20, parent) 30 | { 31 | if (parent != nullptr) { 32 | setWindowTitle(parent->windowTitle()); 33 | setWindowIcon(parent->windowIcon()); 34 | } else { 35 | this->setWindowTitle("Custom Window"); 36 | this->setWindowIcon(QIcon(":/images/logo.jpg")); 37 | } 38 | resize(800, 600); 39 | } 40 | 41 | #ifdef Q_OS_WIN32 42 | /* 43 | * ----------------------------- 44 | * |MuWinAeroShadowWindow | 45 | * | ------------------------- | 46 | * | |m_pContainerWidget | | 47 | * | | --------------------- | | 48 | * | | |titleBar | | | 49 | * | | --------------------- | | 50 | * | | --------------------- | | 51 | * | | |m_pClientWidget | | | 52 | * | | | | | | 53 | * | | | | | | 54 | * | | --------------------- | | 55 | * | ------------------------- | 56 | * ----------------------------- 57 | */ 58 | MuWinAeroShadowWindow::MuWinAeroShadowWindow(QWidget *parent) 59 | :QWidget(parent) 60 | { 61 | setWindowFlags(Qt::FramelessWindowHint); 62 | setContentsMargins(0, 0, 0, 0); 63 | resize(800, 600); 64 | setWindowIcon(QIcon(":/images/logo.jpg")); 65 | 66 | m_pContainerWidget = new QWidget(this); 67 | m_pContainerLayout = new QVBoxLayout(m_pContainerWidget); 68 | m_pContainerLayout->setContentsMargins(0, 0, 0, 0); 69 | m_pContainerLayout->setSpacing(0); 70 | 71 | m_titleBar = new MuTitleBar(this, this, this, true); 72 | installEventFilter(m_titleBar); 73 | m_pClientWidget = new QWidget(this); 74 | m_pClientLayout = new QVBoxLayout(m_pClientWidget); 75 | 76 | QVBoxLayout *pRootLayout = new QVBoxLayout(this); 77 | pRootLayout->setContentsMargins(0, 0, 0, 0); 78 | pRootLayout->addWidget(m_pContainerWidget); 79 | 80 | m_pContainerLayout->addWidget(m_titleBar); 81 | m_pContainerLayout->addWidget(m_pClientWidget); 82 | 83 | m_pHelper = new MuFramelessHelper(this); 84 | m_pHelper->setShadowWidth(0); 85 | m_pHelper->activateOn(this, this); 86 | m_pHelper->setTitleHeight(m_titleBar->height()); 87 | m_pHelper->setWidgetResizable(true); 88 | m_pHelper->setWidgetMovable(true); 89 | 90 | bool enabled = QtWin::isCompositionEnabled(); 91 | if (enabled) { 92 | HWND hwnd = (HWND)this->winId(); 93 | DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); 94 | ::SetWindowLong(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION); 95 | QtWin::extendFrameIntoClientArea(this, 1, 1, 1, 1); 96 | } 97 | } 98 | 99 | void MuWinAeroShadowWindow::setTitleBarHeight(int height) 100 | { 101 | if (height < 0) 102 | return; 103 | 104 | m_titleBar->setFixedHeight(height); 105 | m_pHelper->setTitleHeight(height); 106 | } 107 | 108 | 109 | void MuWinAeroShadowWindow::setClientWidget(QWidget *client) 110 | { 111 | if (client == nullptr) 112 | return; 113 | 114 | m_pContainerLayout->removeWidget(m_pClientWidget); 115 | m_pClientWidget->deleteLater(); 116 | m_pClientLayout->deleteLater(); 117 | m_pClientLayout = nullptr; 118 | m_pClientWidget = client; 119 | m_pContainerLayout->addWidget(m_pClientWidget); 120 | } 121 | 122 | bool MuWinAeroShadowWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) 123 | { 124 | MSG* msg = (MSG *)message; 125 | switch (msg->message) { 126 | case WM_NCCALCSIZE: { 127 | // this kills the window frame and title bar we added with WS_THICKFRAME and WS_CAPTION 128 | *result = 0; 129 | return true; 130 | } 131 | default: 132 | return QWidget::nativeEvent(eventType, message, result); 133 | } 134 | } 135 | #endif 136 | 137 | 138 | 139 | MuCustomDialog::MuCustomDialog(QWidget *parent) 140 | : MuShadowWindow(false, 10, parent) 141 | { 142 | if (parent != nullptr) { 143 | setWindowIcon(parent->windowIcon()); 144 | } else { 145 | this->setWindowIcon(QIcon(":/images/logo.jpg")); 146 | } 147 | this->setWindowTitle("Custom Dialog"); 148 | resize(400, 300); 149 | setResizable(false); 150 | titleBar()->setMinimumVisible(false); 151 | titleBar()->setMaximumVisible(false); 152 | setModal(false); 153 | } 154 | 155 | 156 | QHash MuCustomMessageBox::m_buttonsStyleSheet; 157 | QString MuCustomMessageBox::m_titleStyleSheet; 158 | MuCustomMessageBox::MuCustomMessageBox(QWidget *parent, 159 | const QString &title, 160 | const QString &text, 161 | QMessageBox::StandardButtons buttons, 162 | QMessageBox::StandardButton defaultButton) 163 | : MuShadowWindow(false, 10, parent) 164 | { 165 | if (parent != nullptr) { 166 | setWindowIcon(parent->windowIcon()); 167 | } else { 168 | this->setWindowIcon(QIcon(":/images/logo.jpg")); 169 | } 170 | this->setWindowTitle(title); 171 | 172 | setResizable(false); 173 | titleBar()->setMinimumVisible(false); 174 | titleBar()->setMaximumVisible(false); 175 | 176 | m_pButtonBox = new QDialogButtonBox(this); 177 | m_pButtonBox->setStandardButtons(QDialogButtonBox::StandardButtons(int(buttons))); 178 | setDefaultButton(defaultButton); 179 | 180 | m_pIconLabel = new QLabel(this); 181 | m_pLabel = new QLabel(this); 182 | initStyle(); 183 | 184 | QPixmap pixmap(":/Images/information"); 185 | m_pIconLabel->setPixmap(pixmap); 186 | m_pIconLabel->setFixedSize(35, 35); 187 | m_pIconLabel->setScaledContents(true); 188 | 189 | m_pLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); 190 | m_pLabel->setObjectName("messageTextLabel"); 191 | m_pLabel->setOpenExternalLinks(true); 192 | m_pLabel->setText(text); 193 | 194 | QWidget *pClientWidget = new QWidget(this); 195 | m_pGridLayout = new QGridLayout(pClientWidget); 196 | m_pGridLayout->addWidget(m_pIconLabel, 0, 0, 2, 1, Qt::AlignTop); 197 | m_pGridLayout->addWidget(m_pLabel, 0, 1, 2, 1); 198 | m_pGridLayout->addWidget(m_pButtonBox, m_pGridLayout->rowCount(), 0, 1, m_pGridLayout->columnCount()); 199 | m_pGridLayout->setSizeConstraint(QLayout::SetNoConstraint); 200 | m_pGridLayout->setHorizontalSpacing(10); 201 | m_pGridLayout->setVerticalSpacing(10); 202 | m_pGridLayout->setContentsMargins(10, 10, 10, 10); 203 | clientLayout()->addWidget(pClientWidget); 204 | 205 | translateUI(); 206 | 207 | 208 | connect(m_pButtonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(onButtonClicked(QAbstractButton*))); 209 | } 210 | 211 | QAbstractButton *MuCustomMessageBox::clickedButton() const 212 | { 213 | return m_pClickedButton; 214 | } 215 | 216 | QMessageBox::StandardButton MuCustomMessageBox::standardButton(QAbstractButton *button) const 217 | { 218 | return (QMessageBox::StandardButton)m_pButtonBox->standardButton(button); 219 | } 220 | 221 | void MuCustomMessageBox::setDefaultButton(QPushButton *button) 222 | { 223 | if (!m_pButtonBox->buttons().contains(button)) 224 | return; 225 | 226 | m_pDefaultButton = button; 227 | button->setDefault(true); 228 | button->setFocus(); 229 | } 230 | 231 | void MuCustomMessageBox::setDefaultButton(QMessageBox::StandardButton button) 232 | { 233 | setDefaultButton(m_pButtonBox->button(QDialogButtonBox::StandardButton(button))); 234 | } 235 | 236 | void MuCustomMessageBox::setTitle(const QString &title) 237 | { 238 | setWindowTitle(title); 239 | } 240 | 241 | void MuCustomMessageBox::setText(const QString &text) 242 | { 243 | m_pLabel->setText(text); 244 | } 245 | 246 | void MuCustomMessageBox::setIcon(const QString &icon) 247 | { 248 | m_pIconLabel->setPixmap(QPixmap(icon)); 249 | } 250 | 251 | void MuCustomMessageBox::addWidget(QWidget *pWidget) 252 | { 253 | m_pLabel->hide(); 254 | m_pGridLayout->addWidget(pWidget, 0, 1, 2, 1); 255 | } 256 | 257 | QLabel *MuCustomMessageBox::titleLabel() const 258 | { 259 | return m_pLabel; 260 | } 261 | 262 | QDialogButtonBox *MuCustomMessageBox::buttonBox() const 263 | { 264 | return m_pButtonBox; 265 | } 266 | 267 | QMessageBox::StandardButton MuCustomMessageBox::showInformation(QWidget *parent, 268 | const QString &title, 269 | const QString &text, 270 | QMessageBox::StandardButton buttons) 271 | { 272 | MuCustomMessageBox msgBox(parent, title, text, buttons); 273 | msgBox.setIcon(":/images/informationBlue_48.png"); 274 | if (msgBox.exec() == -1) 275 | return QMessageBox::Cancel; 276 | return msgBox.standardButton(msgBox.clickedButton()); 277 | } 278 | 279 | QMessageBox::StandardButton MuCustomMessageBox::showError(QWidget *parent, 280 | const QString &title, 281 | const QString &text, 282 | QMessageBox::StandardButtons buttons, 283 | QMessageBox::StandardButton defaultButton) 284 | { 285 | MuCustomMessageBox msgBox(parent, title, text, buttons, defaultButton); 286 | msgBox.setIcon(":/images/errorRed_48.png"); 287 | if (msgBox.exec() == -1) 288 | return QMessageBox::Cancel; 289 | return msgBox.standardButton(msgBox.clickedButton()); 290 | } 291 | 292 | QMessageBox::StandardButton MuCustomMessageBox::showSuccess(QWidget *parent, 293 | const QString &title, 294 | const QString &text, 295 | QMessageBox::StandardButtons buttons, 296 | QMessageBox::StandardButton defaultButton) 297 | { 298 | MuCustomMessageBox msgBox(parent, title, text, buttons, defaultButton); 299 | msgBox.setIcon(":/images/successGreen_48.png"); 300 | if (msgBox.exec() == -1) 301 | return QMessageBox::Cancel; 302 | return msgBox.standardButton(msgBox.clickedButton()); 303 | } 304 | 305 | QMessageBox::StandardButton MuCustomMessageBox::showQuestion(QWidget *parent, 306 | const QString &title, 307 | const QString &text, 308 | QMessageBox::StandardButtons buttons, 309 | QMessageBox::StandardButton defaultButton) 310 | { 311 | MuCustomMessageBox msgBox(parent, title, text, buttons, defaultButton); 312 | msgBox.setIcon(":/images/questionBlue_48.png"); 313 | if (msgBox.exec() == -1) 314 | return QMessageBox::Cancel; 315 | return msgBox.standardButton(msgBox.clickedButton()); 316 | } 317 | 318 | QMessageBox::StandardButton MuCustomMessageBox::showWarning(QWidget *parent, 319 | const QString &title, 320 | const QString &text, 321 | QMessageBox::StandardButtons buttons, 322 | QMessageBox::StandardButton defaultButton) 323 | { 324 | MuCustomMessageBox msgBox(parent, title, text, buttons, defaultButton); 325 | msgBox.setIcon(":/images/warningYellow_48.png"); 326 | if (msgBox.exec() == -1) 327 | return QMessageBox::Cancel; 328 | return msgBox.standardButton(msgBox.clickedButton()); 329 | } 330 | 331 | QMessageBox::StandardButton MuCustomMessageBox::showCritical(QWidget *parent, 332 | const QString &title, 333 | const QString &text, 334 | QMessageBox::StandardButtons buttons, 335 | QMessageBox::StandardButton defaultButton) 336 | { 337 | MuCustomMessageBox msgBox(parent, title, text, buttons, defaultButton); 338 | msgBox.setIcon(":/images/warningYellow_48.png"); 339 | if (msgBox.exec() == -1) 340 | return QMessageBox::Cancel; 341 | return msgBox.standardButton(msgBox.clickedButton()); 342 | } 343 | 344 | QMessageBox::StandardButton MuCustomMessageBox::showCheckBoxQuestion(QWidget *parent, 345 | const QString &title, 346 | const QString &text, 347 | QMessageBox::StandardButtons buttons, 348 | QMessageBox::StandardButton defaultButton) 349 | { 350 | MuCustomMessageBox msgBox(parent, title, text, buttons, defaultButton); 351 | msgBox.setIcon(":/images/questionBlue_48.png"); 352 | 353 | QCheckBox *pCheckBox = new QCheckBox(&msgBox); 354 | pCheckBox->setText(text); 355 | msgBox.addWidget(pCheckBox); 356 | if (msgBox.exec() == -1) 357 | return QMessageBox::Cancel; 358 | 359 | QMessageBox::StandardButton standardButton = msgBox.standardButton(msgBox.clickedButton()); 360 | if (standardButton == QMessageBox::Yes) { 361 | return pCheckBox->isChecked() ? QMessageBox::Yes : QMessageBox::No; 362 | } 363 | return QMessageBox::Cancel; 364 | } 365 | 366 | void MuCustomMessageBox::setButtonStyleSheet(QDialogButtonBox::StandardButton button, const QString &styleSheet) 367 | { 368 | m_buttonsStyleSheet[button] = styleSheet; 369 | } 370 | 371 | void MuCustomMessageBox::setTitleStyleSheet(const QString &styleSheet) 372 | { 373 | m_titleStyleSheet = styleSheet; 374 | } 375 | 376 | void MuCustomMessageBox::onButtonClicked(QAbstractButton *button) 377 | { 378 | m_pClickedButton = button; 379 | done(execReturnCode(button)); 380 | } 381 | 382 | int MuCustomMessageBox::execReturnCode(QAbstractButton *button) 383 | { 384 | int nResult = m_pButtonBox->standardButton(button); 385 | return nResult; 386 | } 387 | 388 | void MuCustomMessageBox::translateUI() 389 | { 390 | QPushButton *pYesButton = m_pButtonBox->button(QDialogButtonBox::Yes); 391 | if (pYesButton != nullptr) 392 | pYesButton->setText(tr("Yes")); 393 | 394 | QPushButton *pNoButton = m_pButtonBox->button(QDialogButtonBox::No); 395 | if (pNoButton != nullptr) 396 | pNoButton->setText(tr("No")); 397 | 398 | QPushButton *pOkButton = m_pButtonBox->button(QDialogButtonBox::Ok); 399 | if (pOkButton != nullptr) 400 | pOkButton->setText(tr("Ok")); 401 | 402 | QPushButton *pCancelButton = m_pButtonBox->button(QDialogButtonBox::Cancel); 403 | if (pCancelButton != nullptr) 404 | pCancelButton->setText(tr("Cancel")); 405 | } 406 | 407 | void MuCustomMessageBox::initStyle() 408 | { 409 | QPushButton *pButton = nullptr; 410 | for (auto key : m_buttonsStyleSheet.keys()) { 411 | pButton = m_pButtonBox->button(key); 412 | if (pButton != nullptr) 413 | pButton->setStyleSheet(m_buttonsStyleSheet.value(key)); 414 | } 415 | 416 | titleBar()->titleLabel()->setStyleSheet(m_titleStyleSheet); 417 | } 418 | 419 | -------------------------------------------------------------------------------- /libFramelessWindow/MuCustomWindow.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuCustomWindow.h 5 | * 自定义无边框窗体、对话框和提示框的实现文件,主要API头文件 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef MUCUSTOMWINDOW_H 14 | #define MUCUSTOMWINDOW_H 15 | 16 | #include 17 | #include 18 | #include "MuShadowWindow.h" 19 | 20 | class FRAMELESSWINDOWSHARED_EXPORT MuCustomWindow : public MuShadowWindow 21 | { 22 | public: 23 | explicit MuCustomWindow(QWidget *parent = nullptr); 24 | 25 | protected: 26 | }; 27 | 28 | #ifdef Q_OS_WIN32 29 | /** 30 | * @brief The MuWinAeroShadowWindow class 31 | * 实现Aero部分特效的窗体 32 | */ 33 | class FRAMELESSWINDOWSHARED_EXPORT MuWinAeroShadowWindow : public QWidget 34 | { 35 | Q_OBJECT 36 | public: 37 | explicit MuWinAeroShadowWindow(QWidget *parent = nullptr); 38 | 39 | QWidget *clientWidget() const { return m_pClientWidget; } 40 | QVBoxLayout *clientLayout() const { return m_pClientLayout; } 41 | MuTitleBar *titleBar() const { return m_titleBar; } 42 | void setRubberBandOnMove(bool enable) { m_pHelper->setRubberBandOnMove(enable); } 43 | void setRubberBandOnResize(bool enable) { m_pHelper->setRubberBandOnResize(enable); } 44 | void setTitleBarHeight(int height); 45 | 46 | /** 47 | * @brief setClientWidget 48 | * 设置client替换掉旧的m_pClientWidget 49 | * \warning 50 | * 如果调用了该函数就不能调用clientLayout()函数了,因为m_pClientLayout指针已被释放 51 | * @param client 52 | */ 53 | void setClientWidget(QWidget *client); 54 | 55 | protected: 56 | virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result); 57 | 58 | private: 59 | QWidget *m_pContainerWidget; 60 | QVBoxLayout *m_pContainerLayout; 61 | MuTitleBar *m_titleBar; 62 | QWidget *m_pClientWidget; 63 | QVBoxLayout *m_pClientLayout; 64 | MuFramelessHelper *m_pHelper; 65 | }; 66 | #endif 67 | 68 | class FRAMELESSWINDOWSHARED_EXPORT MuCustomDialog : public MuShadowWindow 69 | { 70 | public: 71 | explicit MuCustomDialog(QWidget *parent = nullptr); 72 | }; 73 | 74 | class QDialogButtonBox; 75 | class FRAMELESSWINDOWSHARED_EXPORT MuCustomMessageBox : public MuShadowWindow 76 | { 77 | Q_OBJECT 78 | public: 79 | explicit MuCustomMessageBox(QWidget *parent = nullptr, 80 | const QString &title = tr("Tip"), 81 | const QString &text = "", 82 | QMessageBox::StandardButtons buttons = QMessageBox::Ok, 83 | QMessageBox::StandardButton defaultButton = QMessageBox::Ok); 84 | 85 | QAbstractButton *clickedButton() const; 86 | QMessageBox::StandardButton standardButton(QAbstractButton *button) const; 87 | 88 | void setDefaultButton(QPushButton *button); 89 | void setDefaultButton(QMessageBox::StandardButton button); 90 | 91 | void setTitle(const QString &title); 92 | void setText(const QString &text); 93 | void setIcon(const QString &icon); 94 | void addWidget(QWidget *pWidget); 95 | 96 | QLabel *titleLabel() const; 97 | 98 | QDialogButtonBox *buttonBox() const; 99 | 100 | static QMessageBox::StandardButton showInformation(QWidget *parent, 101 | const QString &title, 102 | const QString &text, 103 | QMessageBox::StandardButton buttons = QMessageBox::Ok); 104 | 105 | static QMessageBox::StandardButton showError(QWidget *parent, 106 | const QString &title, 107 | const QString &text, 108 | QMessageBox::StandardButtons buttons = QMessageBox::Ok, 109 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); 110 | 111 | static QMessageBox::StandardButton showSuccess(QWidget *parent, 112 | const QString &title, 113 | const QString &text, 114 | QMessageBox::StandardButtons buttons = QMessageBox::Ok, 115 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); 116 | 117 | static QMessageBox::StandardButton showQuestion(QWidget *parent, 118 | const QString &title, 119 | const QString &text, 120 | QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, 121 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); 122 | 123 | static QMessageBox::StandardButton showWarning(QWidget *parent, 124 | const QString &title, 125 | const QString &text, 126 | QMessageBox::StandardButtons buttons = QMessageBox::Ok, 127 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); 128 | 129 | static QMessageBox::StandardButton showCritical(QWidget *parent, 130 | const QString &title, 131 | const QString &text, 132 | QMessageBox::StandardButtons buttons = QMessageBox::Ok, 133 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); 134 | 135 | static QMessageBox::StandardButton showCheckBoxQuestion(QWidget *parent, 136 | const QString &title, 137 | const QString &text, 138 | QMessageBox::StandardButtons buttons, 139 | QMessageBox::StandardButton defaultButton); 140 | 141 | public: 142 | /** 143 | * @brief setButtonStyleSheet 设置MessagBox的Button的样式表 144 | * @param button StandardButton 145 | * @param styleSheet 146 | */ 147 | static void setButtonStyleSheet(QDialogButtonBox::StandardButton button, const QString &styleSheet); 148 | 149 | /** 150 | * @brief setTitleStyleSheet 设置标题栏label的样式表 151 | * @param styleSheet 152 | */ 153 | static void setTitleStyleSheet(const QString &styleSheet); 154 | 155 | private slots: 156 | void onButtonClicked(QAbstractButton *button); 157 | 158 | private: 159 | int execReturnCode(QAbstractButton *button); 160 | void translateUI(); 161 | void initStyle(); 162 | 163 | private: 164 | QLabel *m_pIconLabel; 165 | QLabel *m_pLabel; 166 | QGridLayout *m_pGridLayout; 167 | QDialogButtonBox *m_pButtonBox; 168 | QAbstractButton *m_pClickedButton; 169 | QAbstractButton *m_pDefaultButton; 170 | 171 | // StandardButton, styleSheet 172 | static QHash m_buttonsStyleSheet; 173 | static QString m_titleStyleSheet; 174 | }; 175 | 176 | #endif // MUCUSTOMWINDOW_H 177 | -------------------------------------------------------------------------------- /libFramelessWindow/MuFramelessHelper.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuFramelessHelper.cpp 5 | * 实现了FramelessHelper类。设置窗体是否可移动、缩放、橡皮筋等属性。 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include "MuFramelessHelper.h" 16 | #include "MuFramelessHelperPrivate.h" 17 | #include "MuCursorPosCalculator.h" 18 | 19 | MuFramelessHelper::MuFramelessHelper(QObject *parent) 20 | : QObject(parent) 21 | , d(new MuFramelessHelperPrivate()) 22 | { 23 | d->m_bWidgetMovable = true; 24 | d->m_bWidgetResizable = true; 25 | d->m_bRubberBandOnMove = false; 26 | d->m_bRubberBandOnResize = false; 27 | } 28 | 29 | MuFramelessHelper::~MuFramelessHelper() 30 | { 31 | QList keys = d->m_widgetDataHash.keys(); 32 | int size = keys.size(); 33 | for (int i = 0; i < size; ++i) { 34 | delete d->m_widgetDataHash.take(keys[i]); 35 | } 36 | 37 | delete d; 38 | } 39 | 40 | void MuFramelessHelper::activateOn(QWidget *topLevelWidget, QWidget *shadowContainerWidget) 41 | { 42 | if (!d->m_widgetDataHash.contains(topLevelWidget)) { 43 | MuWidgetData *data = new MuWidgetData(d, topLevelWidget, shadowContainerWidget); 44 | data->setShadowWidth(d->m_nShadowWidth); 45 | d->m_widgetDataHash.insert(topLevelWidget, data); 46 | topLevelWidget->installEventFilter(this); 47 | } 48 | } 49 | 50 | void MuFramelessHelper::removeFrom(QWidget *topLevelWidget) 51 | { 52 | MuWidgetData *data = d->m_widgetDataHash.take(topLevelWidget); 53 | if (data) { 54 | topLevelWidget->removeEventFilter(this); 55 | delete data; 56 | } 57 | } 58 | 59 | void MuFramelessHelper::setWidgetMovable(bool movable) 60 | { 61 | d->m_bWidgetMovable = movable; 62 | } 63 | 64 | void MuFramelessHelper::setWidgetResizable(bool resizable) 65 | { 66 | d->m_bWidgetResizable = resizable; 67 | } 68 | 69 | void MuFramelessHelper::setRubberBandOnMove(bool movable) 70 | { 71 | d->m_bRubberBandOnMove = movable; 72 | QList list = d->m_widgetDataHash.values(); 73 | foreach (MuWidgetData *data, list) { 74 | data->updateRubberBandStatus(); 75 | } 76 | } 77 | 78 | void MuFramelessHelper::setRubberBandOnResize(bool resizable) 79 | { 80 | d->m_bRubberBandOnResize = resizable; 81 | QList list = d->m_widgetDataHash.values(); 82 | foreach (MuWidgetData *data, list) { 83 | data->updateRubberBandStatus(); 84 | } 85 | } 86 | 87 | void MuFramelessHelper::setBorderWidth(uint width) 88 | { 89 | if (width > 0) { 90 | MuCursorPosCalculator::m_nBorderWidth = width; 91 | } 92 | } 93 | 94 | void MuFramelessHelper::setTitleHeight(uint height) 95 | { 96 | if (height > 0) { 97 | MuCursorPosCalculator::m_nTitleHeight = height; 98 | } 99 | } 100 | 101 | void MuFramelessHelper::setShadowWidth(int width) 102 | { 103 | if (width >= 0) { 104 | d->m_nShadowWidth = width; 105 | for (auto key : d->m_widgetDataHash.keys()) { 106 | d->m_widgetDataHash.value(key)->setShadowWidth(d->m_nShadowWidth); 107 | } 108 | } 109 | } 110 | 111 | bool MuFramelessHelper::widgetResizable() const 112 | { 113 | return d->m_bWidgetResizable; 114 | } 115 | 116 | bool MuFramelessHelper::widgetMoable() const 117 | { 118 | return d->m_bWidgetMovable; 119 | } 120 | 121 | bool MuFramelessHelper::rubberBandOnMove() const 122 | { 123 | return d->m_bRubberBandOnMove; 124 | } 125 | 126 | bool MuFramelessHelper::rubberBandOnResize() const 127 | { 128 | return d->m_bRubberBandOnResize; 129 | } 130 | 131 | uint MuFramelessHelper::borderWidth() const 132 | { 133 | return MuCursorPosCalculator::m_nBorderWidth; 134 | } 135 | 136 | uint MuFramelessHelper::titleHeight() const 137 | { 138 | return MuCursorPosCalculator::m_nTitleHeight; 139 | } 140 | 141 | bool MuFramelessHelper::eventFilter(QObject *watched, QEvent *event) 142 | { 143 | switch (event->type()) { 144 | case QEvent::MouseMove: 145 | case QEvent::HoverMove: 146 | case QEvent::MouseButtonPress: 147 | case QEvent::MouseButtonRelease: 148 | case QEvent::Leave: { 149 | MuWidgetData *data = d->m_widgetDataHash.value(static_cast(watched)); 150 | if (data) { 151 | data->handleWidgetEvent(event); 152 | return true; 153 | } 154 | } 155 | default: 156 | return QObject::eventFilter(watched, event); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /libFramelessWindow/MuFramelessHelper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuFramelessHelper.h 5 | * MuFramelessHelper 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef MUFRAMELESSHELPER_H 14 | #define MUFRAMELESSHELPER_H 15 | 16 | #include 17 | #include 18 | #include "MuWidgetData.h" 19 | #include "FramelessWindow_Global.h" 20 | 21 | 22 | class QWdiget; 23 | class MuFramelessHelperPrivate; 24 | class FRAMELESSWINDOWSHARED_EXPORT MuFramelessHelper : public QObject 25 | { 26 | Q_OBJECT 27 | public: 28 | explicit MuFramelessHelper(QObject *parent = nullptr); 29 | ~MuFramelessHelper(); 30 | 31 | /** 32 | * @brief activateOn 激活窗体 33 | * @param topLevelWidget 34 | */ 35 | void activateOn(QWidget *topLevelWidget, QWidget *shadowContainerWidget = nullptr); 36 | 37 | /** 38 | * @brief removeFrom 移除窗体 39 | * @param topLevelWidget 40 | */ 41 | void removeFrom(QWidget *topLevelWidget); 42 | 43 | /** 44 | * @brief setWidgetMovable 设置窗体移动 45 | * @param movable 46 | */ 47 | void setWidgetMovable(bool movable); 48 | 49 | /** 50 | * @brief setWidgetResizable 设置窗体缩放 51 | * @param resizable 52 | */ 53 | 54 | void setWidgetResizable(bool resizable); 55 | /** 56 | * @brief setRubberBandOnMove 设置橡皮筋是否移动 57 | * @param movable 58 | */ 59 | void setRubberBandOnMove(bool movable); 60 | /** 61 | * @brief setRubberBandOnResize 设置橡皮筋是否可以缩放 62 | * @param resizable 63 | */ 64 | void setRubberBandOnResize(bool resizable); 65 | 66 | /** 67 | * @brief setBorderWidth 设置边框的宽度 68 | * @param width unsigned int 69 | */ 70 | void setBorderWidth(uint width); 71 | 72 | /** 73 | * @brief setTitleHeight 设置标题栏高度 74 | * @param height unsigned int 75 | */ 76 | void setTitleHeight(uint height); 77 | 78 | /** 79 | * @brief setShadowWidth 设置边框阴影的宽度,会涉及到在什么位置改变鼠标的形状 80 | * @param width 81 | */ 82 | void setShadowWidth(int width); 83 | 84 | bool widgetResizable() const; 85 | bool widgetMoable() const; 86 | bool rubberBandOnMove() const; 87 | bool rubberBandOnResize() const; 88 | uint borderWidth() const; 89 | uint titleHeight() const; 90 | 91 | protected: 92 | virtual bool eventFilter(QObject *watched, QEvent *event); 93 | 94 | private: 95 | MuFramelessHelperPrivate *d; 96 | }; 97 | 98 | #endif // MUFRAMELESSHELPER_H 99 | -------------------------------------------------------------------------------- /libFramelessWindow/MuFramelessHelperPrivate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuFramelessHelperPrivate.h 5 | * 存储界面对应的数据集合,以及是否可移动、可缩放属性。 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef MUFRAMELESSHELPERPRIVATE_H 14 | #define MUFRAMELESSHELPERPRIVATE_H 15 | 16 | #include 17 | #include 18 | #include "MuWidgetData.h" 19 | 20 | /** 21 | * @brief The FramelessHelperPrivate class 22 | * 存储界面对应的数据集合,以及是否可移动、可缩放属性 23 | */ 24 | class MuFramelessHelperPrivate 25 | { 26 | public: 27 | QHash m_widgetDataHash; 28 | int m_nShadowWidth; 29 | bool m_bWidgetMovable : true; 30 | bool m_bWidgetResizable : true; 31 | bool m_bRubberBandOnResize : true; 32 | bool m_bRubberBandOnMove : true; 33 | }; 34 | 35 | #endif // MUFRAMELESSHELPERPRIVATE_H 36 | -------------------------------------------------------------------------------- /libFramelessWindow/MuShadowWidget.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuShadowWidget.cpp 5 | * 实现边框阴影 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #include 14 | #include "MuShadowWidget.h" 15 | #include 16 | 17 | inline unsigned char MuMakeAlpha(int i, double f, int nSize) 18 | { 19 | if (i == nSize) 20 | f *= 1.2; 21 | // 22 | 23 | double f2 = 1 - cos((double)i / nSize * 3.14 / 2); 24 | // 25 | return int(fabs((i * f) * f2)); 26 | } 27 | QImage MuMakeShadowImage(int shadowSize, bool activated = false, int borderSize = 0) 28 | { 29 | int size = shadowSize * 2 + 10; 30 | QImage image(size, size, QImage::Format_ARGB32); 31 | image.fill(QColor(Qt::black)); 32 | // 33 | double f = activated ? 4.0 : 4.0; 34 | // 35 | QSize szImage = image.size(); 36 | // 37 | //left 38 | for (int y = shadowSize; y < szImage.height() - shadowSize; y++) { 39 | for (int x = 0; x < shadowSize; x++) { 40 | int i = x; 41 | int alpha = MuMakeAlpha(i, f, shadowSize); 42 | image.setPixelColor(x, y, QColor(0, 0, 0, alpha)); 43 | } 44 | } 45 | //right 46 | for (int y = shadowSize; y < szImage.height() - shadowSize; y++) { 47 | for (int x = szImage.width() - shadowSize - 1; x < szImage.width(); x++) { 48 | int i = szImage.width() - x; 49 | int alpha = MuMakeAlpha(i, f, shadowSize); 50 | image.setPixelColor(x, y, QColor(0, 0, 0, alpha)); 51 | } 52 | } 53 | //top 54 | for (int y = 0; y < shadowSize; y++) { 55 | int i = y; 56 | for (int x = shadowSize; x < szImage.width() - shadowSize; x++) { 57 | int alpha = MuMakeAlpha(i, f, shadowSize); 58 | image.setPixelColor(x, y, QColor(0, 0, 0, alpha)); 59 | } 60 | // 61 | } 62 | //bottom 63 | for (int y = szImage.height() - shadowSize - 1; y < szImage.height(); y++) { 64 | int i = szImage.height() - y; 65 | for (int x = shadowSize; x < szImage.width() - shadowSize; x++) { 66 | int alpha = MuMakeAlpha(i, f, shadowSize); 67 | image.setPixelColor(x, y, QColor(0, 0, 0, alpha)); 68 | } 69 | } 70 | // 71 | int parentRoundSize = 3; 72 | // 73 | for (int x = 0; x < shadowSize + parentRoundSize; x++) { 74 | for (int y = 0; y < shadowSize + parentRoundSize; y++) { 75 | int xx = (shadowSize + parentRoundSize) - x; 76 | int yy = (shadowSize + parentRoundSize) - y; 77 | int i = int(sqrt(double(xx * xx + yy * yy))); 78 | i = std::min(shadowSize + parentRoundSize, i); 79 | i -= parentRoundSize; 80 | i = shadowSize - i; 81 | // 82 | int alpha = MuMakeAlpha(i, f, shadowSize); 83 | image.setPixelColor(x, y, QColor(0, 0, 0, alpha)); 84 | } 85 | } 86 | // 87 | for (int x = szImage.width() - shadowSize - parentRoundSize; x < szImage.width(); x++) { 88 | for (int y = 0; y < shadowSize + parentRoundSize; y++) { 89 | int xx = (shadowSize + parentRoundSize) - (szImage.width() - x); 90 | int yy = (shadowSize + parentRoundSize) - y; 91 | int i = int(sqrt(double(xx * xx + yy * yy))); 92 | i = std::min(shadowSize + parentRoundSize, i); 93 | i -= parentRoundSize; 94 | i = shadowSize - i; 95 | // 96 | int alpha = MuMakeAlpha(i, f, shadowSize); 97 | image.setPixelColor(x, y, QColor(0, 0, 0, alpha)); 98 | } 99 | } 100 | // 101 | for (int x = 0; x < shadowSize + parentRoundSize; x++) { 102 | for (int y = szImage.height() - shadowSize - parentRoundSize; y < szImage.height(); y++) { 103 | int xx = (shadowSize + parentRoundSize) - x; 104 | int yy = (shadowSize + parentRoundSize) - (szImage.height() - y); 105 | int i = int(sqrt(double(xx * xx + yy * yy))); 106 | i = std::min(shadowSize + parentRoundSize, i); 107 | i -= parentRoundSize; 108 | i = shadowSize - i; 109 | // 110 | int alpha = MuMakeAlpha(i, f, shadowSize); 111 | image.setPixelColor(x, y, QColor(0, 0, 0, alpha)); 112 | } 113 | } 114 | // 115 | for (int x = szImage.width() - shadowSize - parentRoundSize; x < szImage.width(); x++) { 116 | for (int y = szImage.height() - shadowSize - parentRoundSize; y < szImage.height(); y++) { 117 | int xx = (shadowSize + parentRoundSize) - (szImage.width() - x); 118 | int yy = (shadowSize + parentRoundSize) - (szImage.height() - y); 119 | int i = int(sqrt(double(xx * xx + yy * yy))); 120 | i = std::min(shadowSize + parentRoundSize, i); 121 | i -= parentRoundSize; 122 | i = shadowSize - i; 123 | // 124 | int alpha = MuMakeAlpha(i, f, shadowSize); 125 | image.setPixelColor(x, y, QColor(0, 0, 0, alpha)); 126 | } 127 | } 128 | // 165 129 | // int borderR = 165; 130 | // int borderG = 165; 131 | // int borderB = 165; 132 | int borderR = 165; 133 | int borderG = 165; 134 | int borderB = 165; 135 | // 136 | if (activated) { 137 | borderR = 68; 138 | borderG = 138; 139 | borderB = 255; 140 | // borderR = 0; 141 | // borderG = 0; 142 | // borderB = 0; 143 | } 144 | // 145 | //left 146 | for (int i = 0; i < borderSize; i++) { 147 | for (int y = shadowSize - 1; y < szImage.height() - shadowSize + 1; y++) { 148 | int x = shadowSize - i - 1; 149 | image.setPixelColor(x, y, QColor(borderR, borderG, borderB, 255)); 150 | } 151 | } 152 | //right 153 | for (int i = 0; i < borderSize; i++) { 154 | for (int y = shadowSize - 1; y < szImage.height() - shadowSize + 1; y++) { 155 | int x = szImage.width() - shadowSize - 1 + i + 1; 156 | image.setPixelColor(x, y, QColor(borderR, borderG, borderB, 255)); 157 | } 158 | } 159 | //top 160 | for (int i = 0; i < borderSize; i++) { 161 | for (int x = shadowSize; x < szImage.width() - shadowSize; x++) { 162 | int y = shadowSize - i - 1; 163 | image.setPixelColor(x, y, QColor(borderR, borderG, borderB, 255)); 164 | } 165 | } 166 | //bottom 167 | for (int i = 0; i < borderSize; i++) { 168 | for (int x = shadowSize; x < szImage.width() - shadowSize; x++) { 169 | int y = szImage.height() - shadowSize - 1 + i + 1; 170 | image.setPixelColor(x, y, QColor(borderR, borderG, borderB, 255)); 171 | } 172 | } 173 | // 174 | return image; 175 | } 176 | 177 | bool MuSkin9GridImage::clear() 178 | { 179 | if (!m_img.isNull()) { 180 | m_img = QImage(); 181 | } 182 | return true; 183 | } 184 | 185 | bool MuSkin9GridImage::splitRect(const QRect &rcSrc, QPoint ptTopLeft, QRect *parrayRect, int nArrayCount) 186 | { 187 | Q_ASSERT(nArrayCount == 9); 188 | // 189 | QRect* arrayRect = parrayRect; 190 | // 191 | int nWidth = rcSrc.width(); 192 | int nHeight = rcSrc.height(); 193 | // 194 | if (ptTopLeft.x() <= 0) 195 | return false; 196 | if (ptTopLeft.y() <= 0) 197 | return false; 198 | if (ptTopLeft.x() >= nWidth / 2) 199 | return false; 200 | if (ptTopLeft.y() >= nHeight / 2) 201 | return false; 202 | // 203 | int x1 = rcSrc.left() + 0; 204 | int x2 = rcSrc.left() + ptTopLeft.x(); 205 | int x3 = rcSrc.left() + nWidth - ptTopLeft.x(); 206 | int x4 = rcSrc.left() + nWidth; 207 | // 208 | int y1 = rcSrc.top() + 0; 209 | int y2 = rcSrc.top() + ptTopLeft.y(); 210 | int y3 = rcSrc.top() + nHeight - ptTopLeft.y(); 211 | int y4 = rcSrc.top() + nHeight; 212 | // 213 | arrayRect[0] = QRect(QPoint(x1, y1), QPoint(x2, y2)); 214 | arrayRect[1] = QRect(QPoint(x2 + 1, y1), QPoint(x3, y2)); 215 | arrayRect[2] = QRect(QPoint(x3 + 1, y1), QPoint(x4, y2)); 216 | 217 | arrayRect[3] = QRect(QPoint(x1, y2 + 1), QPoint(x2, y3)); 218 | arrayRect[4] = QRect(QPoint(x2 + 1, y2 + 1), QPoint(x3, y3)); 219 | arrayRect[5] = QRect(QPoint(x3 + 1, y2 + 1), QPoint(x4, y3)); 220 | 221 | arrayRect[6] = QRect(QPoint(x1, y3 + 1), QPoint(x2, y4)); 222 | arrayRect[7] = QRect(QPoint(x2 + 1, y3 + 1), QPoint(x3, y4)); 223 | arrayRect[8] = QRect(QPoint(x3 + 1, y3 + 1), QPoint(x4, y4)); 224 | // 225 | return true; 226 | } 227 | 228 | bool MuSkin9GridImage::setImage(const QImage &image, QPoint ptTopLeft) 229 | { 230 | clear(); 231 | // 232 | m_img = image; 233 | // 234 | int nImageWidth = m_img.width(); 235 | int nImageHeight = m_img.height(); 236 | // 237 | return splitRect(QRect(0, 0, nImageWidth, nImageHeight), ptTopLeft, m_arrayImageGrid, 9); 238 | } 239 | 240 | void MuSkin9GridImage::drawBorder(QPainter *p, QRect rc) const 241 | { 242 | QRect arrayDest[9]; 243 | // 244 | splitRect(rc, m_arrayImageGrid[0].bottomRight(), arrayDest, 9); 245 | // 246 | for (int i = 0; i < 9; i++) { 247 | if (i == 4) 248 | continue; 249 | // 250 | const QRect& rcSrc = m_arrayImageGrid[i]; 251 | const QRect& rcDest = arrayDest[i]; 252 | // 253 | p->drawImage(rcDest, m_img, rcSrc); 254 | } 255 | } 256 | 257 | MuShadowWidget::MuShadowWidget(int shadowSize, bool canResize, QWidget *parent) 258 | : m_shadowSize(shadowSize) 259 | , QWidget(parent) 260 | , m_shadow(new MuSkin9GridImage()) 261 | { 262 | setAttribute(Qt::WA_TranslucentBackground); 263 | setWindowFlag(Qt::FramelessWindowHint); 264 | setMouseTracking(true); 265 | // 266 | QImage image = MuMakeShadowImage(shadowSize, false); 267 | m_shadow->setImage(image, QPoint(shadowSize + 1, shadowSize + 1)); 268 | } 269 | 270 | void MuShadowWidget::paintEvent(QPaintEvent *e) 271 | { 272 | Q_UNUSED(e) 273 | QPainter painter(this); 274 | m_shadow->drawBorder(&painter, rect()); 275 | } 276 | -------------------------------------------------------------------------------- /libFramelessWindow/MuShadowWidget.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuShadowWidget.h 5 | * 实现边框阴影 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef MUSHADOWWIDGET_H 14 | #define MUSHADOWWIDGET_H 15 | 16 | #include 17 | #include "FramelessWindow_Global.h" 18 | 19 | class MuSkin9GridImage 20 | { 21 | protected: 22 | QImage m_img; 23 | QRect m_arrayImageGrid[9]; 24 | // 25 | bool clear(); 26 | public: 27 | static bool splitRect(const QRect& rcSrc, QPoint ptTopLeft, QRect* parrayRect, int nArrayCount); 28 | bool setImage(const QImage& image, QPoint ptTopLeft); 29 | void drawBorder(QPainter* p, QRect rc) const; 30 | }; 31 | 32 | 33 | class FRAMELESSWINDOWSHARED_EXPORT MuShadowWidget : public QWidget 34 | { 35 | Q_OBJECT 36 | public: 37 | MuShadowWidget(int shadowSize, bool canResize, QWidget *parent = nullptr); 38 | 39 | virtual void paintEvent(QPaintEvent *e); 40 | 41 | private: 42 | MuSkin9GridImage* m_shadow; 43 | int m_shadowSize; 44 | }; 45 | 46 | #endif // MUSHADOWWIDGET_H 47 | -------------------------------------------------------------------------------- /libFramelessWindow/MuShadowWindow.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuShadowWindow.h 5 | * 所有自定义窗口的基类,定义窗口各个位置的布局 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef MUSHADOWWINDOW_H 14 | #define MUSHADOWWINDOW_H 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "MuShadowWidget.h" 24 | #include "FramelessWindow_Global.h" 25 | #include "MuTitleBar.h" 26 | #include "MuFramelessHelper.h" 27 | 28 | class QPainter; 29 | class QLineEdit; 30 | class QLabel; 31 | 32 | /************************************* 33 | * ---------------------------------- 34 | * |shadowWindow | 35 | * | ---------------------------- | 36 | * | |ShadowWidget | | 37 | * | | ---------------------- | | 38 | * | | |ShadowClientWidget | | | 39 | * | | | ------------------ | | | 40 | * | | | |TitleBar | | | | 41 | * | | | ------------------ | | | 42 | * | | | ------------------ | | | 43 | * | | | |ClientWidget | | | | 44 | * | | | | | | | | 45 | * | | | ------------------ | | | 46 | * | | ---------------------- | | 47 | * | | | | 48 | * | ---------------------------- | 49 | * | | 50 | * ---------------------------------- 51 | *************************************/ 52 | template 53 | class MuShadowWindow : public Base 54 | { 55 | public: 56 | explicit MuShadowWindow(bool canResize, int shadowSize, QWidget *parent = nullptr) 57 | : Base(parent) 58 | , m_shadowSize(shadowSize) 59 | , m_pShadowWidget(nullptr) 60 | , m_pClientWidget(nullptr) 61 | { 62 | Base *pT = this; 63 | pT->setAttribute(Qt::WA_TranslucentBackground, true); 64 | pT->setWindowFlags(Qt::FramelessWindowHint); 65 | pT->setContentsMargins(0, 0, 0, 0); 66 | 67 | QVBoxLayout *pWindowLayout = new QVBoxLayout(pT); 68 | pWindowLayout->setContentsMargins(0, 0, 0, 0); 69 | pWindowLayout->setSpacing(0); 70 | 71 | // 边框阴影widget 72 | m_pShadowWidget = new MuShadowWidget(m_shadowSize, canResize, this); 73 | m_pShadowWidget->setContentsMargins(m_shadowSize, m_shadowSize, m_shadowSize, m_shadowSize); 74 | m_pShadowWidget->setAutoFillBackground(true); 75 | pWindowLayout->addWidget(m_pShadowWidget); 76 | 77 | QVBoxLayout *pRootLayout = new QVBoxLayout(m_pShadowWidget); 78 | pRootLayout->setContentsMargins(0, 0, 0, 0); 79 | pRootLayout->setSpacing(0); 80 | 81 | // 窗口主要区域 82 | QWidget *pShadowClientWidget = new QWidget(m_pShadowWidget); 83 | pRootLayout->addWidget(pShadowClientWidget); 84 | pShadowClientWidget->setAutoFillBackground(true); 85 | m_pShadowClientLayout = new QVBoxLayout(pShadowClientWidget); 86 | m_pShadowClientLayout->setContentsMargins(0, 0, 0, 0); 87 | m_pShadowClientLayout->setSpacing(0); 88 | 89 | m_titleBar = new MuTitleBar(pShadowClientWidget, this, m_pShadowWidget, canResize); 90 | this->installEventFilter(m_titleBar); 91 | m_pShadowClientLayout->addWidget(m_titleBar); 92 | m_titleBar->setObjectName("titleBar1"); 93 | 94 | m_pClientWidget = new QWidget(pShadowClientWidget); 95 | m_pShadowClientLayout->addWidget(m_pClientWidget); 96 | 97 | m_pClientLayout = new QVBoxLayout; 98 | m_pClientWidget->setLayout(m_pClientLayout); 99 | 100 | m_pHelper = new MuFramelessHelper(this); 101 | m_pHelper->setShadowWidth(m_shadowSize); 102 | m_pHelper->activateOn(this, m_pShadowWidget); 103 | m_pHelper->setTitleHeight(m_titleBar->height()); 104 | m_pHelper->setWidgetResizable(true); 105 | m_pHelper->setWidgetMovable(true); 106 | m_pHelper->setRubberBandOnMove(false); 107 | m_pHelper->setRubberBandOnResize(false); 108 | 109 | QObject::connect(m_titleBar, &MuTitleBar::HeightChanged, [this](const int &height) { m_pHelper->setTitleHeight(height); }); 110 | } 111 | 112 | public: 113 | QWidget* rootWidget() const { return m_pShadowWidget; } 114 | QWidget *clientWidget() const { return m_pClientWidget; } 115 | QLayout* clientLayout() const { return m_pClientLayout; } 116 | MuTitleBar *titleBar() const { return m_titleBar; } 117 | QSize oldSize() const { return m_titleBar->oldSize(); } 118 | void setRubberBandOnMove(bool enable) { m_pHelper->setRubberBandOnMove(enable); } 119 | void setRubberBandOnResize(bool enable) { m_pHelper->setRubberBandOnResize(enable); } 120 | void setTitleBarHeight(int height) 121 | { 122 | if (height < 0) 123 | return; 124 | 125 | m_titleBar->setFixedHeight(height); 126 | m_pHelper->setTitleHeight(height); 127 | } 128 | 129 | 130 | /** 131 | * @brief setClientWidget 132 | * 设置client替换掉旧的m_pClientWidget 133 | * \warning 134 | * 如果调用了该函数就不能调用clientLayout()函数了,因为m_pClientLayout指针已被释放 135 | * @param client 136 | */ 137 | void setClientWidget(QWidget *client) { 138 | if (client == nullptr) 139 | return; 140 | 141 | m_pShadowClientLayout->removeWidget(m_pClientWidget); 142 | m_pClientWidget->deleteLater(); 143 | m_pClientLayout->deleteLater(); 144 | m_pClientLayout = nullptr; 145 | m_pClientWidget = client; 146 | m_pShadowClientLayout->addWidget(m_pClientWidget); 147 | } 148 | 149 | void setResizable(bool resizable) { m_pHelper->setWidgetResizable(resizable); } 150 | void setMovable(bool movable) {m_pHelper->setWidgetMovable(movable); } 151 | 152 | private: 153 | int m_shadowSize; 154 | MuShadowWidget *m_pShadowWidget; 155 | QWidget *m_pClientWidget; 156 | QVBoxLayout *m_pClientLayout; 157 | QVBoxLayout *m_pShadowClientLayout; 158 | MuFramelessHelper *m_pHelper; 159 | MuTitleBar *m_titleBar; 160 | }; 161 | 162 | typedef MuShadowWindow MuCustomWindowWidget; 163 | typedef MuShadowWindow MuCustomDialogWidget; 164 | typedef MuShadowWindow MuCustomMessageBoxWidget; 165 | 166 | #endif // MUSHADOWWINDOW_H 167 | -------------------------------------------------------------------------------- /libFramelessWindow/MuTitleBar.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuTitleBar.cpp 5 | * 自定义窗体的标题栏。 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #ifdef Q_OS_WIN32 20 | #include 21 | #endif 22 | #include 23 | #include 24 | #include 25 | #include "MuTitleBar.h" 26 | #include "MuShadowWindow.h" 27 | #include "MuCursorPosCalculator.h" 28 | 29 | MuTitleBar::MuTitleBar(QWidget *parent, QWidget *window, QWidget *shadowContainerWidget, bool canResize) 30 | : QWidget(parent) 31 | , m_window(window) 32 | , m_shadowContainerWidget(shadowContainerWidget) 33 | , m_oldContentsMargin(10, 10, 10, 10) 34 | , m_canResize(canResize) 35 | { 36 | setFixedHeight(MuCursorPosCalculator::m_nTitleHeight); 37 | 38 | m_pIconLabel = new QLabel(this); 39 | m_pTitleLabel = new QLabel(this); 40 | m_pMinimizeButton = new QPushButton(this); 41 | m_pMaximizeButton = new QPushButton(this); 42 | m_pCloseButton = new QPushButton(this); 43 | m_pCustomWidget = new QWidget(this); 44 | 45 | m_pIconLabel->setFixedSize(20, 20); 46 | m_pIconLabel->setScaledContents(true); 47 | 48 | // m_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); 49 | 50 | m_pMinimizeButton->setFixedSize(27, 22); 51 | m_pMaximizeButton->setFixedSize(27, 22); 52 | m_pCloseButton->setFixedSize(27, 22); 53 | 54 | m_pTitleLabel->setObjectName("titleLabel"); 55 | m_pMinimizeButton->setObjectName("minimizeButton"); 56 | m_pMaximizeButton->setObjectName("maximizeButton"); 57 | m_pCloseButton->setObjectName("closeButton"); 58 | 59 | m_pMinimizeButton->setCheckable(true); 60 | m_pMaximizeButton->setCheckable(true); 61 | m_pCloseButton->setCheckable(true); 62 | 63 | m_pMinimizeButton->setToolTip("Minimize"); 64 | m_pMaximizeButton->setToolTip("Maximize"); 65 | m_pCloseButton->setToolTip("Close"); 66 | 67 | m_pCustomWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 68 | 69 | QHBoxLayout *pLayout = new QHBoxLayout(this); 70 | pLayout->addWidget(m_pIconLabel); 71 | pLayout->addSpacing(5); 72 | pLayout->addWidget(m_pTitleLabel); 73 | pLayout->addWidget(m_pCustomWidget); 74 | pLayout->addWidget(m_pMinimizeButton); 75 | pLayout->addWidget(m_pMaximizeButton); 76 | pLayout->addWidget(m_pCloseButton); 77 | pLayout->setSpacing(0); 78 | pLayout->setContentsMargins(5, 0, 5, 0); 79 | 80 | setLayout(pLayout); 81 | 82 | connect(m_pMinimizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked())); 83 | connect(m_pMaximizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked())); 84 | connect(m_pCloseButton, SIGNAL(clicked(bool)), this, SLOT(onClicked())); 85 | } 86 | MuTitleBar::~MuTitleBar() 87 | { 88 | 89 | } 90 | 91 | void MuTitleBar::setMinimumVisible(bool minimum) 92 | { 93 | if (!minimum) 94 | m_pMinimizeButton->hide(); 95 | else 96 | m_pMaximizeButton->show(); 97 | } 98 | 99 | void MuTitleBar::setMaximumVisible(bool maximum) 100 | { 101 | if (!maximum) 102 | m_pMaximizeButton->hide(); 103 | else 104 | m_pMaximizeButton->show(); 105 | } 106 | 107 | void MuTitleBar::setTitleHeight(int height) 108 | { 109 | if (height < 0) 110 | height = 0; 111 | setFixedHeight(height); 112 | emit HeightChanged(height); 113 | } 114 | 115 | QWidget *MuTitleBar::customWidget() const 116 | { 117 | return m_pCustomWidget; 118 | } 119 | 120 | QPushButton *MuTitleBar::minimizeButton() const 121 | { 122 | return m_pMinimizeButton; 123 | } 124 | 125 | QPushButton *MuTitleBar::maximizeButton() const 126 | { 127 | return m_pMaximizeButton; 128 | } 129 | 130 | QPushButton *MuTitleBar::closeButton() const 131 | { 132 | return m_pCloseButton; 133 | } 134 | 135 | QLabel *MuTitleBar::titleLabel() const 136 | { 137 | return m_pTitleLabel; 138 | } 139 | 140 | QSize MuTitleBar::oldSize() const 141 | { 142 | return m_oldSize; 143 | } 144 | 145 | void MuTitleBar::paintEvent(QPaintEvent *e) 146 | { 147 | Q_UNUSED(e) 148 | 149 | QStyleOption opt; 150 | opt.init(this); 151 | QPainter p(this); 152 | style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); 153 | } 154 | 155 | void MuTitleBar::mouseDoubleClickEvent(QMouseEvent *event) 156 | { 157 | Q_UNUSED(event); 158 | 159 | emit m_pMaximizeButton->clicked(); 160 | } 161 | 162 | bool MuTitleBar::eventFilter(QObject *obj, QEvent *event) 163 | { 164 | switch (event->type()) { 165 | case QEvent::WindowTitleChange: { 166 | QWidget *pWidget = qobject_cast(obj); 167 | if (pWidget) { 168 | m_pTitleLabel->setText(pWidget->windowTitle()); 169 | return true; 170 | } 171 | } 172 | case QEvent::WindowIconChange: { 173 | QWidget *pWidget = qobject_cast(obj); 174 | if (pWidget) { 175 | QIcon icon = pWidget->windowIcon(); 176 | m_pIconLabel->setPixmap(icon.pixmap(m_pIconLabel->size())); 177 | return true; 178 | } 179 | } 180 | case QEvent::Move: 181 | case QEvent::WindowStateChange: 182 | updateMaximize(); 183 | return true; 184 | 185 | case QEvent::Resize: 186 | if (m_window->isMaximized()) { 187 | QResizeEvent *re = reinterpret_cast(event); 188 | if (re != nullptr) { 189 | m_oldSize = re->oldSize(); 190 | } 191 | } 192 | updateMaximize(); 193 | return true; 194 | default: 195 | return QWidget::eventFilter(obj, event); 196 | } 197 | } 198 | 199 | void MuTitleBar::onClicked() 200 | { 201 | QPushButton *pButton = qobject_cast(sender()); 202 | QWidget *pWindow = this->window(); 203 | if (pWindow->isTopLevel()) { 204 | if (pButton == m_pMinimizeButton) { 205 | pWindow->showMinimized(); 206 | } 207 | else if (pButton == m_pMaximizeButton) { 208 | if (!m_canResize) 209 | return; 210 | 211 | if (Qt::WindowMaximized == m_window->windowState()) { 212 | m_shadowContainerWidget->setContentsMargins(m_oldContentsMargin); 213 | m_window->showNormal(); 214 | } else { 215 | m_oldContentsMargin = m_shadowContainerWidget->contentsMargins(); 216 | m_shadowContainerWidget->setContentsMargins(0, 0, 0, 0); 217 | m_window->showMaximized(); 218 | } 219 | } 220 | else if (pButton == m_pCloseButton) { 221 | pWindow->close(); 222 | } 223 | } 224 | } 225 | 226 | void MuTitleBar::updateMaximize() 227 | { 228 | if (m_window != nullptr) { 229 | bool bMaximize = m_window->isMaximized(); 230 | if (bMaximize) { 231 | m_pMaximizeButton->setToolTip(tr("Restore")); 232 | m_pMaximizeButton->setProperty("maximizeProperty", "restore"); 233 | } else { 234 | m_pMaximizeButton->setProperty("maximizeProperty", "maximize"); 235 | m_pMaximizeButton->setToolTip(tr("Maximize")); 236 | } 237 | m_pMaximizeButton->setStyle(QApplication::style()); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /libFramelessWindow/MuTitleBar.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuTitleBar.h 5 | * 自定义窗体的标题栏。 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef MUTITLEBAR_H 14 | #define MUTITLEBAR_H 15 | 16 | #include 17 | #include "FramelessWindow_Global.h" 18 | 19 | class QLabel; 20 | class QPushButton; 21 | class FRAMELESSWINDOWSHARED_EXPORT MuTitleBar : public QWidget 22 | { 23 | Q_OBJECT 24 | public: 25 | explicit MuTitleBar(QWidget *parent, QWidget *window, QWidget *shadowContainerWidget, bool canResize); 26 | ~MuTitleBar(); 27 | 28 | /** 29 | * @brief setMinimumVisible 设置最小化按钮是否可见 30 | * @param minimum 31 | */ 32 | void setMinimumVisible(bool minimum); 33 | /** 34 | * @brief setMaximumVisible 设计最大化还原按钮是否可见 35 | * @param maximum 36 | */ 37 | void setMaximumVisible(bool maximum); 38 | 39 | /** 40 | * @brief setTitleHeight 41 | * 改变标题栏的高度 42 | * \warning 43 | * 如果通过其它函数改变标题栏高度,标题栏的某些区域可能不能拖动窗口 44 | * 或者标题栏以外的区域可能可以拖动窗口 45 | * @param height 46 | */ 47 | void setTitleHeight(int height); 48 | 49 | /** 50 | * @brief customWidget 51 | * 自定义添加内容。除按钮图标标题之外的widget 52 | * @return 53 | */ 54 | QWidget *customWidget() const; 55 | 56 | QPushButton *minimizeButton() const; 57 | QPushButton *maximizeButton() const; 58 | QPushButton *closeButton() const; 59 | QLabel *titleLabel() const; 60 | 61 | /** 62 | * @brief oldSize 63 | * @return 64 | */ 65 | QSize oldSize() const; 66 | 67 | protected: 68 | virtual void paintEvent(QPaintEvent *e); 69 | 70 | /** 71 | * @brief mouseDoubleClickEvent 双击标题栏进行界面的最大化/还原 72 | * @param event QMouseEvent * 73 | */ 74 | virtual void mouseDoubleClickEvent(QMouseEvent *event); 75 | 76 | /** 77 | * @brief eventFilter 设置界面标题与图标 78 | * @param obj 79 | * @param event 80 | * @return 81 | * bool 82 | */ 83 | virtual bool eventFilter(QObject *obj, QEvent *event); 84 | 85 | private slots: 86 | /** 87 | * @brief onClicked 进行最小化、最大化/还原、关闭操作 88 | */ 89 | void onClicked(); 90 | 91 | signals: 92 | void ShowMaximized(); 93 | void ShowNormal(); 94 | void HeightChanged(int height); 95 | 96 | private: 97 | /** 98 | * @brief updateMaximize update the button status 99 | */ 100 | void updateMaximize(); 101 | 102 | private: 103 | QLabel *m_pIconLabel; 104 | QLabel *m_pTitleLabel; 105 | QPushButton *m_pMinimizeButton; 106 | QPushButton *m_pMaximizeButton; 107 | QPushButton *m_pCloseButton; 108 | QWidget *m_pCustomWidget; // 图标,标题,最大最小关闭按钮之外,自定义添加的内容 109 | QWidget* m_window; 110 | QWidget* m_shadowContainerWidget; 111 | QMargins m_oldContentsMargin; 112 | bool m_canResize; 113 | QSize m_oldSize; // the size before Maximized 114 | }; 115 | 116 | #endif // MUTITLEBAR_H 117 | -------------------------------------------------------------------------------- /libFramelessWindow/MuWidgetData.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuWidgetData.cpp 5 | * 处理鼠标事件。 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "MuWidgetData.h" 20 | #include "MuFramelessHelperPrivate.h" 21 | #include "MuCursorPosCalculator.h" 22 | #include "MuShadowWindow.h" 23 | 24 | MuWidgetData::MuWidgetData(MuFramelessHelperPrivate *_d, QWidget *window, QWidget *shadowContainerWidget) 25 | : d(_d) 26 | , m_window(window) 27 | , m_oldShadowWidth(0) 28 | , m_shadowContainerWidget(shadowContainerWidget) 29 | { 30 | m_bLeftButtonPressed = false; 31 | m_bCursorShapeChanged = false; 32 | m_bLeftButtonTitlePressed = false; 33 | m_pRubberBand = NULL; 34 | 35 | m_windowFlags = m_window->windowFlags(); 36 | m_window->setMouseTracking(true); 37 | m_window->setAttribute(Qt::WA_Hover, true); 38 | 39 | if (shadowContainerWidget != nullptr) 40 | m_oldContentsMargin = shadowContainerWidget->contentsMargins(); 41 | 42 | updateRubberBandStatus(); 43 | } 44 | 45 | MuWidgetData::~MuWidgetData() 46 | { 47 | m_window->setMouseTracking(false); 48 | m_window->setWindowFlags(m_windowFlags); 49 | m_window->setAttribute(Qt::WA_Hover, false); 50 | 51 | delete m_pRubberBand; 52 | m_pRubberBand = NULL; 53 | } 54 | 55 | QWidget *MuWidgetData::widget() 56 | { 57 | return m_window; 58 | } 59 | 60 | void MuWidgetData::handleWidgetEvent(QEvent *event) 61 | { 62 | switch (event->type()) { 63 | case QEvent::MouseButtonPress: 64 | handleMousePressEvent(static_cast(event)); 65 | break; 66 | 67 | case QEvent::MouseButtonRelease: 68 | handleMouseReleaseEvent(static_cast(event)); 69 | break; 70 | 71 | case QEvent::MouseMove: 72 | handleMouseMoveEvent(static_cast(event)); 73 | break; 74 | 75 | case QEvent::Leave: 76 | handleLeaveEvent(static_cast(event)); 77 | break; 78 | 79 | case QEvent::HoverMove: 80 | handleHoverMoveEvent(static_cast(event)); 81 | break; 82 | 83 | default: 84 | break; 85 | } 86 | } 87 | 88 | void MuWidgetData::updateRubberBandStatus() 89 | { 90 | if (d->m_bRubberBandOnMove || d->m_bRubberBandOnResize) { 91 | if(nullptr == m_pRubberBand) 92 | m_pRubberBand = new QRubberBand(QRubberBand::Rectangle); 93 | } else { 94 | delete m_pRubberBand; 95 | m_pRubberBand = nullptr; 96 | } 97 | } 98 | 99 | void MuWidgetData::setShadowWidth(const int width) 100 | { 101 | if (width > 0) 102 | m_oldShadowWidth = width; 103 | m_nShadowWidth = width; 104 | } 105 | 106 | void MuWidgetData::handleMousePressEvent(QMouseEvent *event) 107 | { 108 | if (event->button() == Qt::LeftButton) { 109 | m_bLeftButtonPressed = true; 110 | m_bLeftButtonTitlePressed = event->pos().y() < m_moveMousePos.m_nTitleHeight + m_oldShadowWidth; 111 | 112 | QRect frameRect = m_window->frameGeometry(); 113 | frameRect.setX(frameRect.x() + m_nShadowWidth); 114 | frameRect.setY(frameRect.y() + m_nShadowWidth); 115 | frameRect.setWidth(frameRect.width() - m_nShadowWidth); 116 | frameRect.setHeight(frameRect.height() - m_nShadowWidth); 117 | if (Qt::WindowMaximized != m_window->windowState()) 118 | m_pressedMousePos.recalculate(event->globalPos(), frameRect); 119 | 120 | m_ptDragPos = event->globalPos() - frameRect.topLeft(); 121 | m_ptDragPos.setX(m_ptDragPos.x() + m_nShadowWidth); 122 | m_ptDragPos.setY(m_ptDragPos.y() + m_nShadowWidth); 123 | m_dLeftScale = double(m_ptDragPos.x()) / double(frameRect.width()); 124 | m_nRightLength = frameRect.width() - m_ptDragPos.x(); 125 | 126 | if (m_pressedMousePos.m_bOnEdges) { 127 | if (d->m_bRubberBandOnResize) { 128 | m_pRubberBand->setGeometry(frameRect); 129 | m_pRubberBand->show(); 130 | } 131 | } 132 | // 当全屏的时候先不显示橡皮筋,先还原大小,再显示橡皮筋 133 | else if (d->m_bRubberBandOnMove && Qt::WindowMaximized != m_window->windowState()) { 134 | m_pRubberBand->setGeometry(frameRect); 135 | m_pRubberBand->show(); 136 | } 137 | } 138 | } 139 | 140 | void MuWidgetData::handleMouseReleaseEvent(QMouseEvent *event) 141 | { 142 | if (event->button() == Qt::LeftButton) { 143 | m_bLeftButtonPressed = false; 144 | m_bLeftButtonTitlePressed = false; 145 | m_pressedMousePos.reset(); 146 | if (m_pRubberBand && m_pRubberBand->isVisible()) { 147 | m_pRubberBand->hide(); 148 | QRect rectTemp = m_pRubberBand->geometry(); 149 | QRect windowRect = QRect(rectTemp.x() - m_nShadowWidth, 150 | rectTemp.y() - m_nShadowWidth, 151 | rectTemp.width() + m_nShadowWidth * 2, 152 | rectTemp.height() + m_nShadowWidth * 2); 153 | m_window->setGeometry(windowRect); 154 | } 155 | } 156 | } 157 | 158 | void MuWidgetData::handleMouseMoveEvent(QMouseEvent *event) 159 | { 160 | if (m_bLeftButtonPressed) { 161 | if (d->m_bWidgetResizable && m_pressedMousePos.m_bOnEdges && !m_window->isMaximized()) { 162 | resizeWidget(event->globalPos()); 163 | } else if (d->m_bWidgetMovable && m_bLeftButtonTitlePressed) { 164 | moveWidget(event->globalPos()); 165 | } 166 | } else if (d->m_bWidgetResizable) { 167 | updateCursorShape(event->globalPos()); 168 | } 169 | } 170 | 171 | void MuWidgetData::handleLeaveEvent(QMouseEvent *event) 172 | { 173 | Q_UNUSED(event) 174 | if (!m_bLeftButtonPressed) { 175 | m_window->unsetCursor(); 176 | } 177 | } 178 | 179 | void MuWidgetData::handleHoverMoveEvent(QMouseEvent *event) 180 | { 181 | if (d->m_bWidgetResizable && !m_bLeftButtonPressed) { 182 | updateCursorShape(m_window->mapToGlobal(event->pos())); 183 | } 184 | } 185 | 186 | void MuWidgetData::updateCursorShape(const QPoint &gMousePos) 187 | { 188 | if (m_window->isFullScreen() || m_window->isMaximized()) { 189 | if(m_bCursorShapeChanged) { 190 | m_window->unsetCursor(); 191 | } 192 | return; 193 | } 194 | QRect rect = m_window->frameGeometry(); 195 | rect.setX(rect.x() + m_nShadowWidth); 196 | rect.setY(rect.y() + m_nShadowWidth); 197 | rect.setWidth(rect.width() - m_nShadowWidth); 198 | rect.setHeight(rect.height() - m_nShadowWidth); 199 | 200 | m_moveMousePos.recalculate(gMousePos, rect); 201 | 202 | if (m_moveMousePos.m_bOnTopLeftEdge || m_moveMousePos.m_bOnBottomRightEdge) { 203 | m_window->setCursor( Qt::SizeFDiagCursor ); 204 | m_bCursorShapeChanged = true; 205 | } else if(m_moveMousePos.m_bOnTopRightEdge || m_moveMousePos.m_bOnBottomLeftEdge) { 206 | m_window->setCursor( Qt::SizeBDiagCursor ); 207 | m_bCursorShapeChanged = true; 208 | } else if(m_moveMousePos.m_bOnLeftEdge || m_moveMousePos.m_bOnRightEdge) { 209 | m_window->setCursor( Qt::SizeHorCursor ); 210 | m_bCursorShapeChanged = true; 211 | } else if(m_moveMousePos.m_bOnTopEdge || m_moveMousePos.m_bOnBottomEdge) { 212 | m_window->setCursor( Qt::SizeVerCursor ); 213 | m_bCursorShapeChanged = true; 214 | } else { 215 | if (m_bCursorShapeChanged) { 216 | m_window->unsetCursor(); 217 | m_bCursorShapeChanged = false; 218 | } 219 | } 220 | } 221 | 222 | void MuWidgetData::resizeWidget(const QPoint &gMousePos) 223 | { 224 | QRect origRect; 225 | 226 | if (d->m_bRubberBandOnResize) 227 | origRect = m_pRubberBand->frameGeometry(); 228 | else 229 | origRect = m_window->frameGeometry(); 230 | 231 | int left = origRect.left(); 232 | int top = origRect.top(); 233 | int right = origRect.right(); 234 | int bottom = origRect.bottom(); 235 | origRect.getCoords(&left, &top, &right, &bottom); 236 | 237 | int minWidth = m_window->minimumWidth(); 238 | int minHeight = m_window->minimumHeight(); 239 | 240 | if (m_pressedMousePos.m_bOnTopLeftEdge) { 241 | left = gMousePos.x() - m_nShadowWidth; 242 | top = gMousePos.y() - m_nShadowWidth; 243 | } else if (m_pressedMousePos.m_bOnBottomLeftEdge) { 244 | left = gMousePos.x() - m_nShadowWidth; 245 | bottom = gMousePos.y() + m_nShadowWidth; 246 | } else if (m_pressedMousePos.m_bOnTopRightEdge) { 247 | right = gMousePos.x() + m_nShadowWidth; 248 | top = gMousePos.y() - m_nShadowWidth; 249 | } else if (m_pressedMousePos.m_bOnBottomRightEdge) { 250 | right = gMousePos.x() + m_nShadowWidth; 251 | bottom = gMousePos.y() + m_nShadowWidth; 252 | } else if (m_pressedMousePos.m_bOnLeftEdge) { 253 | left = gMousePos.x() - m_nShadowWidth; 254 | } else if (m_pressedMousePos.m_bOnRightEdge) { 255 | right = gMousePos.x() + m_nShadowWidth; 256 | } else if (m_pressedMousePos.m_bOnTopEdge) { 257 | top = gMousePos.y() - m_nShadowWidth; 258 | } else if (m_pressedMousePos.m_bOnBottomEdge) { 259 | bottom = gMousePos.y() + m_nShadowWidth; 260 | } 261 | 262 | QRect newRect(QPoint(left, top), QPoint(right, bottom)); 263 | 264 | if (newRect.isValid()) { 265 | if (minWidth > newRect.width()) { 266 | if (left != origRect.left()) 267 | newRect.setLeft(origRect.left()); 268 | else 269 | newRect.setRight(origRect.right()); 270 | } 271 | if (minHeight > newRect.height()) { 272 | if (top != origRect.top()) 273 | newRect.setTop(origRect.top()); 274 | else 275 | newRect.setBottom(origRect.bottom()); 276 | } 277 | 278 | if (d->m_bRubberBandOnResize) { 279 | m_pRubberBand->setGeometry(newRect); 280 | } else { 281 | m_window->setGeometry(newRect); 282 | } 283 | } 284 | } 285 | 286 | void MuWidgetData::moveWidget(const QPoint &gMousePos) 287 | { 288 | if (d->m_bRubberBandOnMove && Qt::WindowMaximized != m_window->windowState()) { 289 | m_pRubberBand->move(gMousePos - m_ptDragPos); 290 | } else { 291 | // 如果全屏时移动窗口,窗口按点击位置还原 292 | if (Qt::WindowMaximized == m_window->windowState()) { 293 | if (m_dLeftScale <= 0.3) { } 294 | else if (m_dLeftScale > 0.3 && m_dLeftScale < 0.7) { 295 | m_ptDragPos.setX(m_window->normalGeometry().width() * m_dLeftScale); 296 | } else if (m_dLeftScale >= 0.7) { 297 | m_ptDragPos.setX(m_window->normalGeometry().width() - m_nRightLength); 298 | } 299 | m_ptDragPos.setY(m_oldShadowWidth + m_ptDragPos.y()); 300 | m_shadowContainerWidget->setContentsMargins(m_oldContentsMargin); 301 | MuShadowWindow *pWindow = static_cast *>(m_window); 302 | 303 | if (typeid(m_window).name() == "MuWinAeroShadowWindow") { 304 | m_window->resize(m_window->normalGeometry().size()); 305 | } else { 306 | #ifdef Q_OS_LINUX 307 | m_window->setWindowState(Qt::WindowNoState); 308 | m_window->resize(pWindow->oldSize()); 309 | #endif 310 | // 先resize一下,不然Aero窗体会有明显的误差 311 | m_window->resize(pWindow->normalGeometry().size()); 312 | } 313 | m_window->showNormal(); 314 | 315 | 316 | // 当全屏的时候先不显示橡皮筋,先还原大小,再显示橡皮筋 317 | if (d->m_bRubberBandOnMove) { 318 | m_pRubberBand->setGeometry(m_window->geometry()); 319 | m_pRubberBand->move(gMousePos - m_ptDragPos); 320 | m_pRubberBand->show(); 321 | } 322 | } else { 323 | m_oldContentsMargin = m_shadowContainerWidget->contentsMargins(); 324 | } 325 | m_window->move(gMousePos - m_ptDragPos); 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /libFramelessWindow/MuWidgetData.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuWidgetData.h 5 | * 处理窗口的放大缩小移动等事件 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef MUWIDGETDATA_H 14 | #define MUWIDGETDATA_H 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "MuCursorPosCalculator.h" 20 | 21 | class MuFramelessHelperPrivate; 22 | class MuCursorPosCalculator; 23 | class QWidget; 24 | class QEvent; 25 | class QMouseEvent; 26 | class QRubberBand; 27 | class QPoint; 28 | 29 | class MuWidgetData 30 | { 31 | public: 32 | explicit MuWidgetData(MuFramelessHelperPrivate *_d, QWidget *window, QWidget *shadowContainerWidget = nullptr); 33 | ~MuWidgetData(); 34 | 35 | QWidget *widget(); 36 | // 处理鼠标事件-划过、按下、释放、移动 37 | void handleWidgetEvent(QEvent *event); 38 | // 更新橡皮筋状态 39 | void updateRubberBandStatus(); 40 | 41 | void setShadowWidth(const int width); 42 | 43 | private: 44 | // 处理鼠标按下 45 | void handleMousePressEvent(QMouseEvent *event); 46 | // 处理鼠标释放 47 | void handleMouseReleaseEvent(QMouseEvent *event); 48 | // 处理鼠标移动 49 | void handleMouseMoveEvent(QMouseEvent *event); 50 | // 处理鼠标离开 51 | void handleLeaveEvent(QMouseEvent *event); 52 | // 处理鼠标进入 53 | void handleHoverMoveEvent(QMouseEvent *event); 54 | 55 | // 更新鼠标样式 56 | void updateCursorShape(const QPoint &gMousePos); 57 | // 重置窗口大小 58 | void resizeWidget(const QPoint &gMousePos); 59 | // 移动窗体 60 | void moveWidget(const QPoint &gMousePos); 61 | 62 | private: 63 | MuFramelessHelperPrivate *d; 64 | QRubberBand *m_pRubberBand; 65 | QWidget *m_pWidget; 66 | QPoint m_ptDragPos; 67 | double m_dLeftScale; // 鼠标位置距离最窗口最左边的距离占整个宽度的比例 68 | int m_nRightLength; // 鼠标位置距离最窗口最右边的距离 69 | MuCursorPosCalculator m_pressedMousePos; 70 | MuCursorPosCalculator m_moveMousePos; 71 | bool m_bLeftButtonPressed; 72 | bool m_bLeftButtonTitlePressed; 73 | bool m_bCursorShapeChanged; 74 | Qt::WindowFlags m_windowFlags; 75 | int m_nShadowWidth; 76 | int m_oldShadowWidth; 77 | QMargins m_oldContentsMargin; 78 | QWidget *m_window; 79 | QWidget *m_shadowContainerWidget; 80 | QRect m_oldGeometry; 81 | }; 82 | 83 | #endif // MUWIDGETDATA_H 84 | -------------------------------------------------------------------------------- /libFramelessWindow/MuWinDWMAPI.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuWinDwmapi.cpp 5 | * 简单封装了Win平台下的DWM接口实现,后期可能弃用 6 | * 7 | * dnybz 8 | * GitHub: https://github.com/dnybz 9 | * 10 | * FlyWM_ 11 | * GitHub: https://github.com/FlyWM 12 | * CSDN: https://blog.csdn.net/a844651990 13 | * 14 | */ 15 | #include "MuWinDWMAPI.h" 16 | 17 | #ifdef Q_OS_WIN32 18 | 19 | MuWinDwmapi::MuWinDwmapi() 20 | { 21 | } 22 | 23 | MuWinDwmapi::~MuWinDwmapi() 24 | { 25 | } 26 | 27 | 28 | MuWinDwmapi *MuWinDwmapi::instance() 29 | { 30 | static MuWinDwmapi s_dwmapi; 31 | return &s_dwmapi; 32 | } 33 | 34 | HRESULT MuWinDwmapi::dwmExtendFrameIntoClientArea(HWND hWnd, const MARGINS *pMarInset) const 35 | { 36 | return DwmExtendFrameIntoClientArea(hWnd, pMarInset); 37 | } 38 | 39 | HRESULT MuWinDwmapi::enableBlurBehind(HWND hwnd) 40 | { 41 | HRESULT hr = S_OK; 42 | 43 | // Create and populate the blur-behind structure. 44 | DWM_BLURBEHIND bb = {0}; 45 | 46 | // Specify blur-behind and blur region. 47 | bb.dwFlags = DWM_BB_ENABLE; 48 | bb.fEnable = true; 49 | bb.hRgnBlur = NULL; 50 | 51 | // Enable blur-behind. 52 | hr = DwmEnableBlurBehindWindow(hwnd, &bb); 53 | 54 | return hr; 55 | } 56 | 57 | HRESULT MuWinDwmapi::dwmEnableTransition(HWND hWnd, bool enable) 58 | { 59 | HRESULT hr = S_OK; 60 | BOOL enabled; 61 | if (enable) { 62 | enabled = FALSE; 63 | hr = DwmSetWindowAttribute(hWnd, DWMWA_TRANSITIONS_FORCEDISABLED, &enabled, sizeof(enabled)); 64 | } else { 65 | enabled = TRUE; 66 | hr = DwmSetWindowAttribute(hWnd, DWMWA_TRANSITIONS_FORCEDISABLED, &enabled, sizeof(enabled)); 67 | } 68 | return hr; 69 | } 70 | 71 | int MuWinDwmapi::dwmIsCompositionEnabledsEnabled() const 72 | { 73 | HRESULT hr = S_OK; 74 | BOOL enabled; 75 | hr = DwmIsCompositionEnabled(&enabled); 76 | if (hr == S_OK) 77 | return enabled; 78 | else 79 | return -1; 80 | } 81 | 82 | HRESULT MuWinDwmapi::dwmEnableComposition(bool enable) 83 | { 84 | HRESULT hr = S_OK; 85 | if (enable) 86 | hr = DwmEnableComposition(DWM_EC_ENABLECOMPOSITION); 87 | else 88 | hr = DwmEnableComposition(DWM_EC_DISABLECOMPOSITION); 89 | 90 | return hr; 91 | } 92 | 93 | HRESULT MuWinDwmapi::dwmEnabledNoClientRender(HWND hWnd, bool enable) 94 | { 95 | HRESULT hr = S_OK; 96 | DWMNCRENDERINGPOLICY ncrp; 97 | if (enable) { 98 | ncrp = DWMNCRP_ENABLED; 99 | hr = DwmSetWindowAttribute(hWnd, DWMWA_NCRENDERING_POLICY, &ncrp, sizeof(ncrp)); 100 | } else { 101 | ncrp = DWMNCRP_DISABLED; 102 | hr = DwmSetWindowAttribute(hWnd, DWMWA_NCRENDERING_POLICY, &ncrp, sizeof(ncrp)); 103 | } 104 | return hr; 105 | } 106 | 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /libFramelessWindow/MuWinDWMAPI.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MuWinDwmapi.h 5 | * 简单封装了Win平台下的DWM接口,后期可能弃用 6 | * 7 | * dnybz 8 | * GitHub: https://github.com/dnybz 9 | * 10 | * FlyWM_ 11 | * GitHub: https://github.com/FlyWM 12 | * CSDN: https://blog.csdn.net/a844651990 13 | * 14 | */ 15 | 16 | #include 17 | 18 | #ifdef Q_OS_WIN32 19 | 20 | #ifndef MUWINDWMAPI_H 21 | #define MUWINDWMAPI_H 22 | 23 | #include 24 | #include 25 | #include "FramelessWindow_Global.h" 26 | 27 | class FRAMELESSWINDOWSHARED_EXPORT MuWinDwmapi 28 | { 29 | public: 30 | static MuWinDwmapi* instance(); 31 | 32 | /** 33 | * @brief DwnIsEnabled 判断系统Aero效果是否开启 34 | * @return -1,函数执行失败; 0,未开启;1,已开启; 35 | */ 36 | int dwmIsCompositionEnabledsEnabled() const; 37 | 38 | /** 39 | * @brief dwmEnableComposition 开启或关闭Aero Glass效果 40 | * @param enable 41 | * @return 42 | */ 43 | HRESULT dwmEnableComposition(bool enable); 44 | 45 | /** 46 | * @brief dwmEnabledNoClientRender 47 | * 开启或者关闭非客户区渲染 48 | * \warning 当系统的Aero Glass关闭时,设置无效。 49 | * @param hWnd 50 | * @param enable 51 | * @return 52 | */ 53 | HRESULT dwmEnabledNoClientRender(HWND hWnd, bool enable); 54 | 55 | /** 56 | * @brief dwmExtendFrameIntoClientArea 57 | * GLASS效果向客户区域扩展 58 | * \note 非客户区通常包括窗口标题栏和窗口边框。 59 | * 缺省状态下,非客户区会被渲染成毛玻璃效果,这也称为Compostion。 60 | * @param hWnd 窗口句柄 61 | * @param pMarInset 62 | * MARGINS指定了在上下左右4个方向上扩展的范围。如果4个值均为-1,则扩展到整个客户区。 63 | * @return 64 | */ 65 | HRESULT dwmExtendFrameIntoClientArea(HWND hWnd, const MARGINS *pMarInset) const; 66 | 67 | /** 68 | * @brief enableBlurBehind 在指定窗口上启用模糊效果。 69 | * @param hwnd 窗口句柄 70 | * @return 71 | */ 72 | HRESULT enableBlurBehind(HWND hwnd); 73 | 74 | /** 75 | * @brief dwmEnableTransition 76 | * Transition控制是否以动画方式显示窗口的最小化和还原。 77 | * 只对当前窗口有效 78 | * @param hWnd 79 | * @param enable 80 | * @return 81 | */ 82 | HRESULT dwmEnableTransition(HWND hWnd, bool enable); 83 | 84 | private: 85 | MuWinDwmapi(); 86 | MuWinDwmapi(const MuWinDwmapi &); 87 | MuWinDwmapi &operator = (const MuWinDwmapi &); 88 | ~MuWinDwmapi(); 89 | 90 | private: 91 | 92 | }; 93 | 94 | 95 | #endif // MUWINDWMAPI_H 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /libFramelessWindow/MuWinTitlebar.cpp: -------------------------------------------------------------------------------- 1 | #include "MuWinTitlebar.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "muwinwindow.h" 11 | 12 | MuWinTitlebar::MuWinTitlebar(QWidget *parent) 13 | : QWidget(parent), 14 | minButton_(new QPushButton()), 15 | maxRestoreButton_(new QPushButton(this)), 16 | closeButton_(new QPushButton(this)), 17 | mainLayout_(new QHBoxLayout(this)) 18 | { 19 | // setAttribute(Qt::WA_TransparentForMouseEvents); 20 | maxRestoreButton_->setCheckable(true); 21 | 22 | mainLayout_->addStretch(); 23 | mainLayout_->addWidget(minButton_); 24 | mainLayout_->addWidget(maxRestoreButton_); 25 | mainLayout_->addWidget(closeButton_); 26 | 27 | minButton_->setFixedSize(35, 35); 28 | maxRestoreButton_->setFixedSize(35, 35); 29 | closeButton_->setFixedSize(35, 35); 30 | 31 | minButton_->setObjectName("minButton"); 32 | minButton_->setStyleSheet("QPushButton { " 33 | " border: none;" 34 | " padding: 3px;" 35 | " image: url(:/images/winwindow/minimize.png);" 36 | "}" 37 | "QPushButton:hover { " 38 | " border: none;" 39 | " background-color: #4baeeb;" 40 | "}"); 41 | 42 | maxRestoreButton_->setStyleSheet("QPushButton { " 43 | " border: none;" 44 | " padding: 8px;" 45 | " image: url(:/images/winwindow/maximize.png);" 46 | "}" 47 | "QPushButton:hover { " 48 | " border: none;" 49 | " background-color: #4baeeb;" 50 | "}" 51 | "QPushButton::checked { " 52 | " border: none;" 53 | " padding: 8px;" 54 | " image: url(:/images/winwindow/restore.png);" 55 | "}" 56 | "QPushButton::checked:hover { " 57 | " border: none;" 58 | " background-color: #4baeeb;" 59 | "}" 60 | ); 61 | 62 | closeButton_->setStyleSheet("QPushButton { " 63 | " border: none;" 64 | " padding: 8px;" 65 | " image: url(:/images/winwindow/close.png);" 66 | "}" 67 | "QPushButton:hover { " 68 | " border: none;" 69 | " background-color: #4baeeb;" 70 | "}"); 71 | 72 | connect(minButton_, &QPushButton::clicked, this, &MuWinTitlebar::ShowMinimized); 73 | connect(closeButton_, &QPushButton::clicked, this, &MuWinTitlebar::Close); 74 | connect(maxRestoreButton_, &QPushButton::clicked, [this](bool checked) { 75 | if (checked) 76 | emit ShowMaximized(); 77 | else 78 | emit ShowRestoreSize(); 79 | }); 80 | } 81 | 82 | bool MuWinTitlebar::eventFilter(QObject *watched, QEvent *event) 83 | { 84 | MuWinWindow *window = qobject_cast(watched); 85 | if (window == nullptr) 86 | return false; 87 | 88 | switch (event->type()) { 89 | case QEvent::Resize: { 90 | if (window->isMaximized()) { 91 | maxRestoreButton_->setChecked(true); 92 | } else { 93 | maxRestoreButton_->setChecked(false); 94 | } 95 | return true; 96 | } 97 | 98 | default: 99 | break; 100 | } 101 | return QWidget::eventFilter(watched, event); 102 | } 103 | 104 | void MuWinTitlebar::resizeEvent(QResizeEvent *e) 105 | { 106 | QRegion reg(frameGeometry()); 107 | reg -= QRegion(geometry()); 108 | reg += childrenRegion(); 109 | setMask(reg); 110 | QWidget::resizeEvent(e); 111 | } 112 | 113 | 114 | -------------------------------------------------------------------------------- /libFramelessWindow/MuWinTitlebar.h: -------------------------------------------------------------------------------- 1 | #ifndef MUTITLEBAR_H 2 | #define MUTITLEBAR_H 3 | 4 | #include 5 | #include "FramelessWindow_Global.h" 6 | 7 | class QHBoxLayout; 8 | class QPushButton; 9 | class FRAMELESSWINDOWSHARED_EXPORT MuWinTitlebar : public QWidget 10 | { 11 | Q_OBJECT 12 | public: 13 | explicit MuWinTitlebar(QWidget *parent = nullptr); 14 | 15 | bool eventFilter(QObject *watched, QEvent *event); 16 | void resizeEvent(QResizeEvent *e); 17 | 18 | signals: 19 | void ShowMinimized(); 20 | void ShowMaximized(); 21 | void ShowRestoreSize(); 22 | void Close(); 23 | 24 | public slots: 25 | 26 | private: 27 | QPushButton *minButton_; 28 | QPushButton *maxRestoreButton_; 29 | QPushButton *closeButton_; 30 | 31 | QHBoxLayout *mainLayout_; 32 | }; 33 | 34 | #endif // MUTITLEBAR_H 35 | -------------------------------------------------------------------------------- /libFramelessWindow/MuWinWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "MuWinWindow.h" 2 | 3 | #ifdef Q_OS_WIN32 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "MuWinTitlebar.h" 14 | 15 | #pragma comment (lib, "user32.lib") 16 | 17 | #ifndef GET_X_LPARAM 18 | #define GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam)) 19 | #endif 20 | #ifndef GET_Y_LPARAM 21 | #define GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam)) 22 | #endif 23 | 24 | MuWinWindow::MuWinWindow(QWidget *parent) : 25 | QWidget(parent), 26 | clientWidget_(new QWidget(this)) 27 | { 28 | setWindowFlags(Qt::FramelessWindowHint); 29 | setMinimumSize(800, 600); 30 | 31 | HWND hwnd = reinterpret_cast(this->winId()); 32 | DWORD style = GetWindowLong(hwnd, GWL_STYLE); 33 | SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION); 34 | 35 | bool enabled = QtWin::isCompositionEnabled(); 36 | if (enabled) { 37 | HWND hwnd = (HWND)this->winId(); 38 | DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); 39 | ::SetWindowLong(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION | WS_BORDER); 40 | QtWin::extendFrameIntoClientArea(this, 1, 1, 1, 1); 41 | } 42 | 43 | // 其实是设置的标题栏的颜色 44 | setStyleSheet("background-color: #52baff"); 45 | clientWidget_->setStyleSheet("background-color: #FFFFFF"); 46 | 47 | MuWinTitlebar *titleBar = new MuWinTitlebar(this); 48 | titleBar->setFixedHeight(50); 49 | 50 | mainLayout_ = new QVBoxLayout(this); 51 | mainLayout_->addWidget(titleBar); 52 | mainLayout_->addWidget(clientWidget_); 53 | mainLayout_->setContentsMargins(0, 0, 0, 0); 54 | 55 | installEventFilter(titleBar); 56 | 57 | setWindowIcon(":/images/winwindow/1.jpg"); 58 | setWindowTitle("WinWindow"); 59 | 60 | connect(titleBar, &MuWinTitlebar::ShowMinimized, this, &MuWinWindow::showMinimized); 61 | connect(titleBar, &MuWinTitlebar::ShowMaximized, this, &MuWinWindow::showMaximized); 62 | connect(titleBar, &MuWinTitlebar::ShowRestoreSize, this, &MuWinWindow::showNormal); 63 | connect(titleBar, &MuWinTitlebar::Close, this, &MuWinWindow::close); 64 | } 65 | 66 | MuWinWindow::~MuWinWindow() 67 | { 68 | } 69 | 70 | /// 71 | /// \brief MuWinWindow::paintEvent 通过paintEvent绘制图标和标题,如果用MuTitleBar来显示的图标和标题的话, 72 | /// 当鼠标点击图标和标题时无法移动窗体 73 | /// \param e 74 | /// 75 | void MuWinWindow::paintEvent(QPaintEvent *e) 76 | { 77 | QPainter p(this); 78 | 79 | // 绘制窗口图标 80 | QRect imgTarget(10, 10, 30, 30); 81 | QImage img(iconFileName_); 82 | p.drawImage(imgTarget, img.scaled(30, 30, Qt::KeepAspectRatio, Qt::SmoothTransformation)); 83 | 84 | // 绘制标题 85 | QFont font; 86 | font.setPixelSize(14); 87 | QFontMetrics fm(font); 88 | QRect titleTarget(45, 10, fm.width(title_), 30); 89 | 90 | p.setFont(font); 91 | p.setPen(Qt::white); 92 | p.drawText(titleTarget, title_, QTextOption(Qt::AlignCenter)); 93 | 94 | QWidget::paintEvent(e); 95 | } 96 | 97 | QString MuWinWindow::iconFileName() const 98 | { 99 | return iconFileName_; 100 | } 101 | 102 | void MuWinWindow::setWindowIcon(const QString &fileName) 103 | { 104 | iconFileName_ = fileName; 105 | this->QWidget::setWindowIcon(QIcon(fileName)); 106 | } 107 | 108 | void MuWinWindow::setWindowTitle(const QString &title) 109 | { 110 | title_ = title; 111 | this->QWidget::setWindowTitle(title); 112 | } 113 | 114 | bool MuWinWindow::nativeEvent(const QByteArray &eventType, 115 | void *message, 116 | long *result) 117 | { 118 | 119 | #ifdef Q_OS_WIN 120 | if (eventType != "windows_generic_MSG") 121 | return false; 122 | 123 | MSG* msg = static_cast(message); 124 | 125 | QWidget* widget = QWidget::find(reinterpret_cast(msg->hwnd)); 126 | if (!widget) 127 | return false; 128 | 129 | switch (msg->message) { 130 | case WM_NCCALCSIZE: { 131 | *result = 0; 132 | return true; 133 | } 134 | 135 | case WM_NCHITTEST: { 136 | int x = GET_X_LPARAM(msg->lParam); 137 | int y = GET_Y_LPARAM(msg->lParam); 138 | 139 | QPoint pt = mapFromGlobal(QPoint(x, y)); 140 | *result = calculateBorder(pt); 141 | if (*result == HTCLIENT) { 142 | QWidget* tempWidget = this->childAt(pt.x(), pt.y()); 143 | if (tempWidget == NULL) { 144 | *result = HTCAPTION; 145 | } 146 | } 147 | return true; 148 | } 149 | 150 | case WM_GETMINMAXINFO: { 151 | if (::IsZoomed(msg->hwnd)) { 152 | isMaximized_ = true; 153 | RECT frame = { 0, 0, 0, 0 }; 154 | AdjustWindowRectEx(&frame, WS_OVERLAPPEDWINDOW, FALSE, 0); 155 | frame.left = abs(frame.left); 156 | frame.top = abs(frame.bottom); 157 | widget->setContentsMargins(frame.left, frame.top, frame.right, frame.bottom); 158 | } 159 | else { 160 | widget->setContentsMargins(0, 0, 0, 0); 161 | isMaximized_ = false; 162 | } 163 | 164 | *result = ::DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam); 165 | return true; 166 | } 167 | break; 168 | 169 | default: 170 | break; 171 | } 172 | 173 | #endif 174 | 175 | return QWidget::nativeEvent(eventType, message, result); 176 | } 177 | 178 | LRESULT MuWinWindow::calculateBorder(const QPoint &pt) 179 | { 180 | if (::IsZoomed((HWND)this->winId())) { 181 | return HTCLIENT; 182 | } 183 | int borderSize = 4; 184 | int cx = this->size().width(); 185 | int cy = this->size().height(); 186 | 187 | QRect rectTopLeft(0, 0, borderSize, borderSize); 188 | if (rectTopLeft.contains(pt)) { 189 | return HTTOPLEFT; 190 | } 191 | 192 | QRect rectLeft(0, borderSize, borderSize, cy - borderSize * 2); 193 | if (rectLeft.contains(pt)) { 194 | return HTLEFT; 195 | } 196 | 197 | QRect rectTopRight(cx - borderSize, 0, borderSize, borderSize); 198 | if (rectTopRight.contains(pt)) { 199 | return HTTOPRIGHT; 200 | } 201 | 202 | QRect rectRight(cx - borderSize, borderSize, borderSize, cy - borderSize * 2); 203 | if (rectRight.contains(pt)) { 204 | return HTRIGHT; 205 | } 206 | 207 | QRect rectTop(borderSize, 0, cx - borderSize * 2, borderSize); 208 | if (rectTop.contains(pt)) { 209 | return HTTOP; 210 | } 211 | 212 | QRect rectBottomLeft(0, cy - borderSize, borderSize, borderSize); 213 | if (rectBottomLeft.contains(pt)) { 214 | return HTBOTTOMLEFT; 215 | } 216 | 217 | QRect rectBottomRight(cx - borderSize, cy - borderSize, borderSize, borderSize); 218 | if (rectBottomRight.contains(pt)) { 219 | return HTBOTTOMRIGHT; 220 | } 221 | 222 | QRect rectBottom(borderSize, cy - borderSize, cx - borderSize * 2, borderSize); 223 | if (rectBottom.contains(pt)) { 224 | return HTBOTTOM; 225 | } 226 | 227 | return HTCLIENT; 228 | } 229 | 230 | #endif 231 | -------------------------------------------------------------------------------- /libFramelessWindow/MuWinWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MUWINWINDOW_H 2 | #define MUWINWINDOW_H 3 | 4 | #include 5 | 6 | #ifdef Q_OS_WIN32 7 | 8 | #include 9 | #include "FramelessWindow_Global.h" 10 | 11 | namespace Ui { 12 | class MuWinWindow; 13 | } 14 | 15 | class QHBoxLayout; 16 | class QVBoxLayout; 17 | class FRAMELESSWINDOWSHARED_EXPORT MuWinWindow : public QWidget 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit MuWinWindow(QWidget *parent = 0); 23 | ~MuWinWindow(); 24 | 25 | QString iconFileName() const; 26 | void setWindowIcon(const QString &fileName); 27 | void setWindowTitle(const QString &title); 28 | 29 | bool isMaximized() const 30 | { return isMaximized_; } 31 | 32 | 33 | protected: 34 | virtual bool nativeEvent(const QByteArray &eventType, 35 | void *message, 36 | long *result); 37 | 38 | void paintEvent(QPaintEvent *e); 39 | 40 | private: 41 | LRESULT calculateBorder(const QPoint &pt); 42 | 43 | private: 44 | Ui::MuWinWindow *ui; 45 | 46 | QString iconFileName_; 47 | QString title_; 48 | 49 | QVBoxLayout *mainLayout_; 50 | QWidget *clientWidget_; 51 | 52 | bool isMaximized_; 53 | }; 54 | 55 | #endif 56 | 57 | #endif // MUWINWINDOW_H 58 | -------------------------------------------------------------------------------- /libFramelessWindow/images.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/closeBtnBlack_16.png 4 | images/closeBtnWhite_16.png 5 | images/minimizeBtnBlack_16.png 6 | images/minimizeBtnWhite_16.png 7 | images/restoreBlack_16.png 8 | images/restoreWhite_16.png 9 | images/maximizeBtnBlack_16.png 10 | images/maximizeBtnWhite_16.png 11 | images/errorRed_48.png 12 | images/questionBlue_48.png 13 | images/successGreen_48.png 14 | images/warningYellow_48.png 15 | images/logo.jpg 16 | images/informationBlue_48.png 17 | images/winwindow/1.jpg 18 | images/winwindow/close.png 19 | images/winwindow/maximize.png 20 | images/winwindow/minimize.png 21 | images/winwindow/restore.png 22 | 23 | 24 | -------------------------------------------------------------------------------- /libFramelessWindow/images/closeBtnBlack_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/closeBtnBlack_16.png -------------------------------------------------------------------------------- /libFramelessWindow/images/closeBtnWhite_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/closeBtnWhite_16.png -------------------------------------------------------------------------------- /libFramelessWindow/images/errorRed_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/errorRed_48.png -------------------------------------------------------------------------------- /libFramelessWindow/images/informationBlue_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/informationBlue_48.png -------------------------------------------------------------------------------- /libFramelessWindow/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/logo.jpg -------------------------------------------------------------------------------- /libFramelessWindow/images/maximizeBtnBlack_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/maximizeBtnBlack_16.png -------------------------------------------------------------------------------- /libFramelessWindow/images/maximizeBtnWhite_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/maximizeBtnWhite_16.png -------------------------------------------------------------------------------- /libFramelessWindow/images/minimizeBtnBlack_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/minimizeBtnBlack_16.png -------------------------------------------------------------------------------- /libFramelessWindow/images/minimizeBtnWhite_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/minimizeBtnWhite_16.png -------------------------------------------------------------------------------- /libFramelessWindow/images/questionBlue_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/questionBlue_48.png -------------------------------------------------------------------------------- /libFramelessWindow/images/restoreBlack_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/restoreBlack_16.png -------------------------------------------------------------------------------- /libFramelessWindow/images/restoreWhite_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/restoreWhite_16.png -------------------------------------------------------------------------------- /libFramelessWindow/images/successGreen_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/successGreen_48.png -------------------------------------------------------------------------------- /libFramelessWindow/images/warningYellow_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/warningYellow_48.png -------------------------------------------------------------------------------- /libFramelessWindow/images/winwindow/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/winwindow/1.jpg -------------------------------------------------------------------------------- /libFramelessWindow/images/winwindow/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/winwindow/close.png -------------------------------------------------------------------------------- /libFramelessWindow/images/winwindow/maximize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/winwindow/maximize.png -------------------------------------------------------------------------------- /libFramelessWindow/images/winwindow/minimize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/winwindow/minimize.png -------------------------------------------------------------------------------- /libFramelessWindow/images/winwindow/restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libFramelessWindow/images/winwindow/restore.png -------------------------------------------------------------------------------- /libFramelessWindow/libFramelessWindow.pri: -------------------------------------------------------------------------------- 1 | #--------------------------------------------- 2 | # 自定义无边框窗体、对话框和提示框 3 | # 4 | # libFramelessWindow.pri 5 | # 工程文件 6 | # 7 | # FlyWM_ 8 | # GitHub: https://github.com/FlyWM 9 | # CSDN: https://blog.csdn.net/a844651990 10 | # 11 | #--------------------------------------------- 12 | 13 | INCLUDEPATH += $$PWD 14 | 15 | DEPENDPATH += $$PWD 16 | 17 | TEMPLATE += fakelib 18 | 19 | # qtLibraryTarget确保windows下debug模式生成的动态库可以自动加个d 20 | # 用来区分 release 和 debug 模式下的库, 这里知识为了设置LIBFRAMELESSWINDOW_NAME的值, 21 | # 所以 TEMPLATE -= fakelib,不然 qtLibraryTarget 获取不到值 22 | LIBFRAMELESSWINDOW_NAME = $$qtLibraryTarget(FramelessWindow) 23 | 24 | TEMPLATE -= fakelib 25 | 26 | include(../common.pri) 27 | 28 | # FramelessWindow-buildlib 标志用来区分是 libFramelessWindow调用 29 | # 还是 libTest调用, 所以需要在 libFramelessWindow.pro中 30 | # 设置 CONFIG += FramelessWindow-buidlib 31 | FramelessWindow-buildlib{ 32 | # 不要加$$PWD 33 | HEADERS += \ 34 | MuFramelessHelper.h \ 35 | MuFramelessHelperPrivate.h \ 36 | MuCursorPosCalculator.h \ 37 | MuTitleBar.h \ 38 | MuWidgetData.h \ 39 | MuWinDWMAPI.h \ 40 | MuShadowWidget.h \ 41 | MuShadowWindow.h \ 42 | MuCustomWindow.h \ 43 | MuWinTitlebar.h \ 44 | MuWinWindow.h \ 45 | FramelessWindow_Global.h 46 | 47 | SOURCES += \ 48 | MuFramelessHelper.cpp \ 49 | MuWidgetData.cpp\ 50 | MuCursorPosCalculator.cpp \ 51 | MuTitleBar.cpp \ 52 | MuWinDWMAPI.cpp \ 53 | MuShadowWidget.cpp \ 54 | MuCustomWindow.cpp \ 55 | MuWinTitlebar.cpp \ 56 | MuWinWindow.cpp 57 | 58 | RESOURCES += \ 59 | images.qrc 60 | 61 | QT += widgets 62 | 63 | win32: { 64 | QT += winextras 65 | LIBS += -lDwmapi 66 | } 67 | }else{ 68 | LIBS += -L$$PROJECT_LIBDIR -l$$LIBFRAMELESSWINDOW_NAME 69 | } 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /libFramelessWindow/libFramelessWindow.pro: -------------------------------------------------------------------------------- 1 | #--------------------------------------------- 2 | # 自定义无边框窗体、对话框和提示框 3 | # 4 | # libFramelessWindow.pro 5 | # 工程文件 6 | # 7 | # FlyWM_ 8 | # GitHub: https://github.com/FlyWM 9 | # CSDN: https://blog.csdn.net/a844651990 10 | # 11 | #--------------------------------------------- 12 | 13 | TEMPLATE = lib 14 | 15 | CONFIG += FramelessWindow-buildlib 16 | 17 | include(libFramelessWindow.pri) 18 | 19 | TARGET = $$LIBFRAMELESSWINDOW_NAME 20 | 21 | DESTDIR = $$PROJECT_LIBDIR 22 | 23 | win32{ 24 | DLLDESTDIR = $$PROJECT_BINDIR 25 | QMAKE_DISTCLEAN += $$PROJECT_BINDIR/$${LIBFRAMELESSWINDOW_NAME}.dll 26 | } 27 | 28 | CONFIG += debug_and_release build_all 29 | 30 | # 宏定义 31 | DEFINES += FRAMELESSWINDOW_LIBRARY HAVE_WINDOW_AERO 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /libTest/AeroClientWidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AeroCLientWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | This is a WinAeroWindow! 21 | 22 | 23 | Qt::AlignCenter 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /libTest/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MainWindow.h 5 | * 测试用例主要窗口 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include "MainWindow.h" 16 | #include "ui_MainWindow.h" 17 | #include "ui_AeroClientWidget.h" 18 | #include "MuWinWindow.h" 19 | 20 | MainWindow::MainWindow(QWidget *parent) 21 | : MuCustomWindow(parent) 22 | , ui(new Ui::MainWindow) 23 | , aeroUI(new Ui::AeroCLientWidget) 24 | { 25 | setWindowTitle("Test Custom Window"); 26 | resize(800, 600); 27 | 28 | QWidget *pClientWidget = new QWidget(this); 29 | ui->setupUi(pClientWidget); 30 | 31 | this->titleBar()->setTitleHeight(50); 32 | this->titleBar()->setObjectName("titleBar"); 33 | this->titleBar()->titleLabel()->setObjectName("titleLabel"); 34 | this->titleBar()->minimizeButton()->setObjectName("minimizeButton"); 35 | this->titleBar()->maximizeButton()->setObjectName("maximizeButton"); 36 | this->titleBar()->closeButton()->setObjectName("closeButton"); 37 | 38 | // 设置中心客户区域 39 | setClientWidget(pClientWidget); 40 | 41 | // 设置messagebox的按钮样式表和标题样式表 42 | const QString buttonStyle = "QPushButton { \ 43 | border: none; \ 44 | background-color: #52baff; \ 45 | width: 80px; \ 46 | height: 30px; \ 47 | } \ 48 | QPushButton::pressed { \ 49 | background-color: gray; \ 50 | }"; 51 | MuCustomMessageBox::setTitleStyleSheet(QStringLiteral("QLabel { color: black }")); 52 | MuCustomMessageBox::setButtonStyleSheet(QDialogButtonBox::Ok, buttonStyle); 53 | connect(ui->dialogBtn, &QPushButton::clicked, this, &MainWindow::onDialogBtnClicked); 54 | connect(ui->informationBtn, &QPushButton::clicked, this, &MainWindow::onInformationBtnClicked); 55 | connect(ui->errorBtn, &QPushButton::clicked, this, &MainWindow::onErrorBtnClicked); 56 | connect(ui->successBtn, &QPushButton::clicked, this, &MainWindow::onSuccessBtnClicked); 57 | connect(ui->warningBtn, &QPushButton::clicked, this, &MainWindow::onWarningBtnClicked); 58 | #ifdef Q_OS_WIN32 59 | initAreoWindow(); 60 | connect(ui->aeroBtn, &QPushButton::clicked, m_AeroWindow, &MuWinAeroShadowWindow::show); 61 | connect(ui->winWindowBtn, &QPushButton::clicked, this, &MainWindow::onWinWindow); 62 | #else 63 | ui->aeroBtn->hide(); 64 | #endif 65 | } 66 | 67 | MainWindow::~MainWindow() 68 | { 69 | delete ui; 70 | #ifdef Q_OS_WIN32 71 | delete m_AeroWindow; 72 | #endif 73 | } 74 | 75 | void MainWindow::onDialogBtnClicked() 76 | { 77 | MuCustomDialog dialog; 78 | QLabel label("This is a Custom Dialog!"); 79 | label.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); 80 | dialog.titleBar()->titleLabel()->setObjectName("dialogTitleLabel"); 81 | dialog.setModal(true); 82 | dialog.setWindowTitle("dialog"); 83 | dialog.setClientWidget(&label); 84 | dialog.exec(); 85 | } 86 | 87 | void MainWindow::onInformationBtnClicked() 88 | { 89 | MuCustomMessageBox::showInformation(nullptr, 90 | QStringLiteral("Information!"), 91 | QStringLiteral("This is a Information MessageBox!")); 92 | } 93 | 94 | void MainWindow::onErrorBtnClicked() 95 | { 96 | MuCustomMessageBox::showError(nullptr, 97 | QStringLiteral("Error!"), 98 | QStringLiteral("This is a Error MessageBox!")); 99 | } 100 | 101 | void MainWindow::onSuccessBtnClicked() 102 | { 103 | MuCustomMessageBox::showSuccess(nullptr, 104 | QStringLiteral("Success!"), 105 | QStringLiteral("This is a Success MessageBox!")); 106 | } 107 | 108 | void MainWindow::onWarningBtnClicked() 109 | { 110 | MuCustomMessageBox::showWarning(nullptr, 111 | QStringLiteral("Warning!"), 112 | QStringLiteral("This is a Warning MessageBox!")); 113 | } 114 | 115 | #ifdef Q_OS_WIN32 116 | void MainWindow::initAreoWindow() 117 | { 118 | m_AeroWindow = new MuWinAeroShadowWindow; 119 | m_AeroWindow->setRubberBandOnMove(true); 120 | m_AeroWindow->setRubberBandOnResize(true); 121 | m_AeroWindow->setWindowTitle(QStringLiteral("Test Aero Window")); 122 | m_AeroWindow->titleBar()->setObjectName("aeroTitleBar"); 123 | QWidget *pClientWidget = new QWidget(m_AeroWindow); 124 | aeroUI->setupUi(pClientWidget); 125 | m_AeroWindow->setClientWidget(pClientWidget); 126 | } 127 | #endif 128 | 129 | void MainWindow::onWinWindow() 130 | { 131 | MuWinWindow *window = new MuWinWindow; 132 | window->resize(800, 600); 133 | window->show(); 134 | } 135 | -------------------------------------------------------------------------------- /libTest/MainWindow.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * MainWindow.h 5 | * 测试用例主要窗口 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef MAINWINDOW_H 14 | #define MAINWINDOW_H 15 | 16 | #include 17 | #include "MuCustomWindow.h" 18 | 19 | namespace Ui { 20 | class MainWindow; 21 | class AeroCLientWidget; 22 | } 23 | 24 | class MainWindow : public MuCustomWindow 25 | { 26 | Q_OBJECT 27 | 28 | public: 29 | explicit MainWindow(QWidget *parent = 0); 30 | ~MainWindow(); 31 | 32 | private slots: 33 | void onDialogBtnClicked(); 34 | void onInformationBtnClicked(); 35 | void onErrorBtnClicked(); 36 | void onSuccessBtnClicked(); 37 | void onWarningBtnClicked(); 38 | void onWinWindow(); 39 | 40 | private: 41 | #ifdef Q_OS_WIN32 42 | void initAreoWindow(); 43 | #endif 44 | 45 | private: 46 | Ui::MainWindow *ui; 47 | Ui::AeroCLientWidget *aeroUI; 48 | MuCustomDialog *dialog; 49 | #ifdef Q_OS_WIN32 50 | MuWinAeroShadowWindow *m_AeroWindow; 51 | #endif 52 | }; 53 | 54 | #endif // MAINWINDOW_H 55 | -------------------------------------------------------------------------------- /libTest/MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 90 20 | 80 21 | 75 22 | 23 23 | 24 | 25 | 26 | Dialog 27 | 28 | 29 | 30 | 31 | 32 | 90 33 | 190 34 | 75 35 | 23 36 | 37 | 38 | 39 | success 40 | 41 | 42 | 43 | 44 | 45 | 90 46 | 140 47 | 101 48 | 23 49 | 50 | 51 | 52 | information 53 | 54 | 55 | 56 | 57 | 58 | 210 59 | 140 60 | 75 61 | 23 62 | 63 | 64 | 65 | error 66 | 67 | 68 | 69 | 70 | 71 | 210 72 | 190 73 | 75 74 | 23 75 | 76 | 77 | 78 | warning 79 | 80 | 81 | 82 | 83 | 84 | 90 85 | 240 86 | 121 87 | 23 88 | 89 | 90 | 91 | AeroWindow 92 | 93 | 94 | 95 | 96 | 97 | 230 98 | 240 99 | 75 100 | 23 101 | 102 | 103 | 104 | WinWindow 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /libTest/StyleSheetHelper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * StyleSheetHelper.h 5 | * 加载qss文件。 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #ifndef LSSTYLESHEETHELPER_H 14 | #define LSSTYLESHEETHELPER_H 15 | 16 | #include 17 | #include 18 | 19 | class StyleSheetHelper 20 | { 21 | public: 22 | static void setStyle(const QString &qssFile) { 23 | QFile qss(qssFile); 24 | qss.open(QFile::ReadOnly); 25 | qApp->setStyleSheet(qss.readAll()); 26 | qss.close(); 27 | } 28 | }; 29 | 30 | #endif // LSSTYLESHEETHELPER_H 31 | -------------------------------------------------------------------------------- /libTest/images.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/minBtn32_Gray.png 4 | images/minBtn32_White.png 5 | images/maxBtn32_Gray.png 6 | images/maxBtn32_White.png 7 | images/restoreBtn32_Gray.png 8 | images/restoreBtn32_White.png 9 | images/closeBtn32_Gray.png 10 | images/closeBtn32_White.png 11 | images/logo.jpg 12 | images/closeBtnBlack_16.png 13 | images/closeBtnWhite_16.png 14 | images/errorRed_48.png 15 | images/informationBlue_48.png 16 | images/maximizeBtnBlack_16.png 17 | images/maximizeBtnWhite_16.png 18 | images/minimizeBtnBlack_16.png 19 | images/minimizeBtnWhite_16.png 20 | images/questionBlue_48.png 21 | images/restoreBlack_16.png 22 | images/restoreWhite_16.png 23 | images/successGreen_48.png 24 | images/warningYellow_48.png 25 | 26 | 27 | -------------------------------------------------------------------------------- /libTest/images/closeBtn32_Gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/closeBtn32_Gray.png -------------------------------------------------------------------------------- /libTest/images/closeBtn32_White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/closeBtn32_White.png -------------------------------------------------------------------------------- /libTest/images/closeBtnBlack_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/closeBtnBlack_16.png -------------------------------------------------------------------------------- /libTest/images/closeBtnWhite_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/closeBtnWhite_16.png -------------------------------------------------------------------------------- /libTest/images/errorRed_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/errorRed_48.png -------------------------------------------------------------------------------- /libTest/images/informationBlue_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/informationBlue_48.png -------------------------------------------------------------------------------- /libTest/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/logo.jpg -------------------------------------------------------------------------------- /libTest/images/maxBtn32_Gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/maxBtn32_Gray.png -------------------------------------------------------------------------------- /libTest/images/maxBtn32_White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/maxBtn32_White.png -------------------------------------------------------------------------------- /libTest/images/maximizeBtnBlack_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/maximizeBtnBlack_16.png -------------------------------------------------------------------------------- /libTest/images/maximizeBtnWhite_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/maximizeBtnWhite_16.png -------------------------------------------------------------------------------- /libTest/images/minBtn32_Gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/minBtn32_Gray.png -------------------------------------------------------------------------------- /libTest/images/minBtn32_White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/minBtn32_White.png -------------------------------------------------------------------------------- /libTest/images/minimizeBtnBlack_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/minimizeBtnBlack_16.png -------------------------------------------------------------------------------- /libTest/images/minimizeBtnWhite_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/minimizeBtnWhite_16.png -------------------------------------------------------------------------------- /libTest/images/questionBlue_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/questionBlue_48.png -------------------------------------------------------------------------------- /libTest/images/restoreBlack_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/restoreBlack_16.png -------------------------------------------------------------------------------- /libTest/images/restoreBtn32_Gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/restoreBtn32_Gray.png -------------------------------------------------------------------------------- /libTest/images/restoreBtn32_White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/restoreBtn32_White.png -------------------------------------------------------------------------------- /libTest/images/restoreWhite_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/restoreWhite_16.png -------------------------------------------------------------------------------- /libTest/images/successGreen_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/successGreen_48.png -------------------------------------------------------------------------------- /libTest/images/warningYellow_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/libTest/images/warningYellow_48.png -------------------------------------------------------------------------------- /libTest/libTest.pro: -------------------------------------------------------------------------------- 1 | #--------------------------------------------- 2 | # 自定义无边框窗体、对话框和提示框 3 | # 4 | # libTest.pri 5 | # 工程文件 测试程序 6 | # 7 | # FlyWM_ 8 | # GitHub: https://github.com/FlyWM 9 | # CSDN: https://blog.csdn.net/a844651990 10 | # 11 | #--------------------------------------------- 12 | 13 | TEMPLATE = app 14 | 15 | TARGET = libTest 16 | 17 | include(../libFramelessWindow/libFramelessWindow.pri) 18 | 19 | DESTDIR = $$PROJECT_BINDIR 20 | 21 | unix:QMAKE_RPATHDIR += $$PROJECT_LIBDIR 22 | 23 | QT += widgets 24 | 25 | SOURCES += \ 26 | main.cpp \ 27 | MainWindow.cpp 28 | 29 | HEADERS += \ 30 | MainWindow.h \ 31 | MainWindow.h \ 32 | StyleSheetHelper.h 33 | 34 | FORMS += \ 35 | MainWindow.ui \ 36 | AeroClientWidget.ui 37 | 38 | RESOURCES += \ 39 | qss.qrc \ 40 | images.qrc 41 | 42 | -------------------------------------------------------------------------------- /libTest/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定义无边框窗体、对话框和提示框 3 | * 4 | * main.cpp 5 | * 测试入口函数。 6 | * 7 | * FlyWM_ 8 | * GitHub: https://github.com/FlyWM 9 | * CSDN: https://blog.csdn.net/a844651990 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include "MainWindow.h" 16 | #include "StyleSheetHelper.h" 17 | #include "MuCustomWindow.h" 18 | #include "MuShadowWindow.h" 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | QApplication a(argc, argv); 23 | 24 | StyleSheetHelper::setStyle(":/style.qss"); 25 | 26 | MainWindow w; 27 | w.show(); 28 | 29 | return a.exec(); 30 | } 31 | -------------------------------------------------------------------------------- /libTest/qss.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | style.qss 4 | 5 | 6 | -------------------------------------------------------------------------------- /libTest/style.qss: -------------------------------------------------------------------------------- 1 | /* 2 | * titleBar 3 | */ 4 | MuTitleBar#titleBar { 5 | background-color: #c62f2f; 6 | } 7 | MuTitleBar#aeroTitleBar { 8 | background-color: #4696ff; 9 | } 10 | QLabel#titleLabel { 11 | color: white; 12 | font-family: 'Microsoft Yahei'; 13 | } 14 | QPushButton#minimizeButton, #maximizeButton, #closeButton { 15 | border: none; 16 | } 17 | QPushButton#minimizeButton { 18 | image: url(:/images/minBtn32_Gray.png); 19 | } 20 | QPushButton#minimizeButton:hover { 21 | image: url(:/images/minBtn32_White.png); 22 | } 23 | 24 | QPushButton#maximizeButton { 25 | border: none; 26 | image: url(:/images/maxBtn32_Gray.png); 27 | } 28 | QPushButton#maximizeButton:hover { 29 | image: url(:/images/maxBtn32_White.png); 30 | } 31 | QPushButton#maximizeButton[maximizeProperty=restore] { 32 | image: url(:/images/restoreBtn32_Gray.png); 33 | padding-top: 2px; 34 | padding-bottom: 2px; 35 | } 36 | QPushButton#maximizeButton[maximizeProperty=restore]:hover { 37 | image: url(:/images/restoreBtn32_White.png); 38 | } 39 | QPushButton#maximizeButton[maximizeProperty=maximize]:hover { 40 | image: url(:/images/maxBtn32_White.png); 41 | } 42 | 43 | QPushButton#closeButton { 44 | border: none; 45 | image: url(:/images/closeBtn32_Gray.png); 46 | } 47 | QPushButton#closeButton:hover { 48 | image: url(:/images/closeBtn32_White.png); 49 | } 50 | /*************************************************/ 51 | 52 | QLabel#dialogTitleLabel { 53 | color: black; 54 | font-family: 'Microsoft Yahei'; 55 | } 56 | -------------------------------------------------------------------------------- /projectFramelessWindow.pro: -------------------------------------------------------------------------------- 1 | #--------------------------------------------- 2 | # 自定义无边框窗体、对话框和提示框 3 | # 4 | # projectFramelessWindow.pro 5 | # 工程文件 6 | # 7 | # FlyWM_ 8 | # GitHub: https://github.com/FlyWM 9 | # CSDN: https://blog.csdn.net/a844651990 10 | # 11 | #--------------------------------------------- 12 | 13 | TEMPLATE = subdirs 14 | 15 | # 当使用subdirs模板时,此选项指定应按给出目录的顺序处理列出的目录 16 | CONFIG += ordered 17 | 18 | SUBDIRS += libFramelessWindow \ 19 | libTest 20 | 21 | -------------------------------------------------------------------------------- /samples/AeroWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/samples/AeroWindow.png -------------------------------------------------------------------------------- /samples/CustomDialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/samples/CustomDialog.png -------------------------------------------------------------------------------- /samples/CustomInformationMessagBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/samples/CustomInformationMessagBox.png -------------------------------------------------------------------------------- /samples/CustomSuccessMessageBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/samples/CustomSuccessMessageBox.png -------------------------------------------------------------------------------- /samples/CustomWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/samples/CustomWindow.png -------------------------------------------------------------------------------- /samples/scaleAndMove_noRubber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/samples/scaleAndMove_noRubber.gif -------------------------------------------------------------------------------- /samples/scaleAndMove_withRubber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlyWM/FramelessWindow-Qt/9a73ef584c98988bb45334d773abff74bf2f4281/samples/scaleAndMove_withRubber.gif --------------------------------------------------------------------------------