├── preview_1.png
├── libtest
├── style.qss
├── style.qrc
├── libTest.pro
├── mainwindow.h
├── main.cpp
├── stylesheethelper.h
└── mainwindow.cpp
├── QtFramelessWindow.pro
├── libframelesswindow
├── images
│ ├── titlebar
│ │ ├── close.png
│ │ ├── max.png
│ │ ├── menu.png
│ │ ├── min.png
│ │ └── restore.png
│ ├── msgbox
│ │ ├── msg-info-48x48.png
│ │ ├── msg-error-48x48.png
│ │ ├── msg-success-48x48.png
│ │ ├── msg-warning-48x48.png
│ │ └── msg-question-48x48.png
│ └── background
│ │ ├── client-shadow.png
│ │ └── client-shadow.psd
├── style.qrc
├── framelesswindow_global.h
├── images.qrc
├── framelesshelperprivate.h
├── libframelesswindow.pri
├── cursorposcalculator.h
├── borderimage.h
├── borderimage.cpp
├── titlebar.h
├── widgetdata.h
├── statebutton.h
├── cursorposcalculator.cpp
├── style
│ ├── style_black.qss
│ └── style_white.qss
├── framelesshelper.h
├── framelesshelper.cpp
├── statebutton.cpp
├── framelesswindow.h
├── titlebar.cpp
├── widgetdata.cpp
├── framelesswindow.cpp
└── widgetshadow.h
├── .gitignore
└── README.md
/preview_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/preview_1.png
--------------------------------------------------------------------------------
/libtest/style.qss:
--------------------------------------------------------------------------------
1 | QPushButton#openDlgBtn {
2 | background: lightgreen;
3 | border: none;
4 | }
5 |
--------------------------------------------------------------------------------
/libtest/style.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | style.qss
4 |
5 |
6 |
--------------------------------------------------------------------------------
/QtFramelessWindow.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = subdirs
2 |
3 | # 当使用subdirs模板时,此选项指定应按给出目录的顺序处理列出的目录
4 | CONFIG += ordered
5 |
6 | SUBDIRS += libtest
7 |
8 |
--------------------------------------------------------------------------------
/libframelesswindow/images/titlebar/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/titlebar/close.png
--------------------------------------------------------------------------------
/libframelesswindow/images/titlebar/max.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/titlebar/max.png
--------------------------------------------------------------------------------
/libframelesswindow/images/titlebar/menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/titlebar/menu.png
--------------------------------------------------------------------------------
/libframelesswindow/images/titlebar/min.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/titlebar/min.png
--------------------------------------------------------------------------------
/libframelesswindow/images/titlebar/restore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/titlebar/restore.png
--------------------------------------------------------------------------------
/libframelesswindow/images/msgbox/msg-info-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/msgbox/msg-info-48x48.png
--------------------------------------------------------------------------------
/libframelesswindow/images/background/client-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/background/client-shadow.png
--------------------------------------------------------------------------------
/libframelesswindow/images/background/client-shadow.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/background/client-shadow.psd
--------------------------------------------------------------------------------
/libframelesswindow/images/msgbox/msg-error-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/msgbox/msg-error-48x48.png
--------------------------------------------------------------------------------
/libframelesswindow/images/msgbox/msg-success-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/msgbox/msg-success-48x48.png
--------------------------------------------------------------------------------
/libframelesswindow/images/msgbox/msg-warning-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/msgbox/msg-warning-48x48.png
--------------------------------------------------------------------------------
/libframelesswindow/images/msgbox/msg-question-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangqiangcc/QtFramelessWindow/HEAD/libframelesswindow/images/msgbox/msg-question-48x48.png
--------------------------------------------------------------------------------
/libframelesswindow/style.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | style/style_black.qss
4 | style/style_white.qss
5 |
6 |
7 |
--------------------------------------------------------------------------------
/libtest/libTest.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = app
2 |
3 | TARGET = libTest
4 |
5 | #DEFINES += HAVE_WINDOW_AERO
6 |
7 | include(../libFramelessWindow/libFramelessWindow.pri)
8 |
9 | DESTDIR = $$PROJECT_BINDIR
10 |
11 | unix:QMAKE_RPATHDIR += $$PROJECT_LIBDIR
12 |
13 | QT += widgets
14 |
15 | SOURCES += \
16 | main.cpp \
17 | mainwindow.cpp \
18 |
19 | HEADERS += \
20 | mainwindow.h \
21 | stylesheethelper.h \
22 |
23 | RESOURCES += \
24 | style.qrc
25 |
26 |
--------------------------------------------------------------------------------
/libframelesswindow/framelesswindow_global.h:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * framelesswindow_global.h
5 | *
6 | */
7 |
8 | #ifndef FRAMELESSWINDOW_GLOBAL_H
9 | #define FRAMELESSWINDOW_GLOBAL_H
10 |
11 | #include
12 |
13 | #if defined(FRAMELESSWINDOW_LIBRARY)
14 | # define FRAMELESSWINDOWSHARED_EXPORT Q_DECL_EXPORT
15 | #else
16 | # define FRAMELESSWINDOWSHARED_EXPORT Q_DECL_IMPORT
17 | #endif
18 |
19 | #endif // FRAMELESSWINDOW_GLOBAL_H
20 |
--------------------------------------------------------------------------------
/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 |
14 | #ifndef MAINWINDOW_H
15 | #define MAINWINDOW_H
16 |
17 | #include
18 | #include
19 |
20 | class MainWindow : public FramelessWindow
21 | {
22 | public:
23 | MainWindow(QWidget *parent = nullptr);
24 |
25 |
26 |
27 | };
28 |
29 | #endif // MAINWINDOW_H
30 |
--------------------------------------------------------------------------------
/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 "mainwindow.h"
15 | #include "stylesheethelper.h"
16 |
17 | int main(int argc, char *argv[])
18 | {
19 | QApplication a(argc, argv);
20 |
21 | StyleSheetHelper::setStyle(":/style.qss");
22 |
23 | MainWindow w;
24 | w.show();
25 |
26 | return a.exec();
27 | }
28 |
--------------------------------------------------------------------------------
/.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 |
18 | /.qmake.cache
19 | /.qmake.stash
20 | *.pro.user
21 | *.pro.user.*
22 | *.qbs.user
23 | *.qbs.user.*
24 | *.moc
25 | moc_*.cpp
26 | moc_*.h
27 | qrc_*.cpp
28 | ui_*.h
29 | Makefile*
30 | *build-*
31 |
32 | # QtCreator
33 |
34 | *.autosave
35 |
36 | # QtCtreator Qml
37 | *.qmlproject.user
38 | *.qmlproject.user.*
39 |
40 | # QtCtreator CMake
41 | CMakeLists.txt.user*
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/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 | {
24 | QFile qss(qssFile);
25 | qss.open(QFile::ReadOnly);
26 | qApp->setStyleSheet(qss.readAll());
27 | qss.close();
28 | }
29 | };
30 |
31 | #endif // LSSTYLESHEETHELPER_H
32 |
--------------------------------------------------------------------------------
/libframelesswindow/images.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | images/titlebar/close.png
4 | images/titlebar/max.png
5 | images/titlebar/menu.png
6 | images/titlebar/min.png
7 | images/titlebar/restore.png
8 | images/background/client-shadow.png
9 | images/msgbox/msg-error-48x48.png
10 | images/msgbox/msg-info-48x48.png
11 | images/msgbox/msg-question-48x48.png
12 | images/msgbox/msg-success-48x48.png
13 | images/msgbox/msg-warning-48x48.png
14 |
15 |
16 |
--------------------------------------------------------------------------------
/libframelesswindow/framelesshelperprivate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * framelesshelperprivate.h
5 | * 存储界面对应的数据集合,以及是否可移动、可缩放属性。
6 | *
7 | */
8 |
9 | #ifndef FRAMELESSHELPERPRIVATE_H
10 | #define FRAMELESSHELPERPRIVATE_H
11 |
12 | #include "widgetdata.h"
13 | #include
14 | #include
15 | /**
16 | * @brief The FramelessHelperPrivate class
17 | * 存储界面对应的数据集合,以及是否可移动、可缩放属性
18 | */
19 | class FramelessHelperPrivate
20 | {
21 | public:
22 | QHash m_widgetDataHash;
23 | bool m_bWidgetMovable : true;
24 | bool m_bWidgetResizable : true;
25 | bool m_bRubberBandOnResize : true;
26 | bool m_bRubberBandOnMove : true;
27 | };
28 |
29 | #endif // FRAMELESSHELPERPRIVATE_H
30 |
--------------------------------------------------------------------------------
/libframelesswindow/libframelesswindow.pri:
--------------------------------------------------------------------------------
1 | INCLUDEPATH += $$PWD
2 | DEPENDPATH += $$PWD
3 |
4 | DEFINES += FRAMELESSWINDOW_LIBRARY
5 |
6 | HEADERS += \
7 | $$PWD/cursorposcalculator.h \
8 | $$PWD/framelesshelper.h \
9 | $$PWD/framelesshelperprivate.h \
10 | $$PWD/framelesswindow.h \
11 | $$PWD/framelesswindow_global.h \
12 | $$PWD/widgetdata.h \
13 | $$PWD/titlebar.h \
14 | $$PWD/borderimage.h \
15 | $$PWD/statebutton.h \
16 | $$PWD/widgetshadow.h
17 |
18 | SOURCES += \
19 | $$PWD/cursorposcalculator.cpp \
20 | $$PWD/framelesshelper.cpp \
21 | $$PWD/framelesswindow.cpp \
22 | $$PWD/widgetdata.cpp \
23 | $$PWD/titlebar.cpp \
24 | $$PWD/borderimage.cpp \
25 | $$PWD/statebutton.cpp
26 |
27 | RESOURCES += \
28 | $$PWD/images.qrc \
29 | $$PWD/style.qrc
30 |
--------------------------------------------------------------------------------
/libframelesswindow/cursorposcalculator.h:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * cursorposcalculator.h
5 | * 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角
6 | */
7 |
8 | #ifndef CURSORPOSCALCULATOR_H
9 | #define CURSORPOSCALCULATOR_H
10 |
11 | /**
12 | * @brief The CursorPosCalculator class
13 | * 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角
14 | */
15 | class QPoint;
16 | class QRect;
17 | class CursorPosCalculator
18 | {
19 | public:
20 | explicit CursorPosCalculator();
21 |
22 | void reset();
23 | void recalculate(const QPoint &gMousePos, const QRect &frameRect);
24 |
25 | public:
26 | bool m_bOnEdges : true;
27 | bool m_bOnLeftEdge : true;
28 | bool m_bOnRightEdge : true;
29 | bool m_bOnTopEdge : true;
30 | bool m_bOnBottomEdge : true;
31 | bool m_bOnTopLeftEdge : true;
32 | bool m_bOnBottomLeftEdge : true;
33 | bool m_bOnTopRightEdge : true;
34 | bool m_bOnBottomRightEdge : true;
35 |
36 | static int m_nBorderWidth;
37 | static int m_nTitleHeight;
38 | };
39 |
40 | #endif // CURSORPOSCALCULATOR_H
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # QtFramelessWindow
2 | Custom frameless window,dialog,messagebox Library / 自定义无边框窗体,对话框和提示框,并封装成库
3 |
4 | 
5 |
6 | 使用方法:
7 |
8 | ```c++
9 | #include "framelesswindow.h"
10 | #include
11 | #include
12 |
13 | int main(int argc, char *argv[])
14 | {
15 | QApplication a(argc, argv);
16 |
17 | // FramelessWindow
18 | FramelessWindow *pWindow = new FramelessWindow();
19 | QWidget *pCentralWidget = new QWidget(pWindow);
20 | pWindow->setCentralWidget(pCentralWidget);
21 | pWindow->show();
22 |
23 | // FramelessDialog
24 | FramelessDialog *pDialog = new FramelessDialog(pWindow);
25 | QWidget *pDlgCentralWidget = new QWidget(pDialog);
26 | QPushButton *pButton = new QPushButton(pDlgCentralWidget);
27 | pDialog->setCentralWidget(pDlgCentralWidget);
28 | pDialog->setModal(true);
29 | pDialog->show();
30 |
31 | // FramelessMessageBox
32 | FramelessMessageBox::showInformation(pWindow, QObject::tr("提示!"), QObject::tr("自定义提示框!"));
33 | return a.exec();
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/libframelesswindow/borderimage.h:
--------------------------------------------------------------------------------
1 | #ifndef BORDERIMAGE_H
2 | #define BORDERIMAGE_H
3 |
4 | #include
5 | #include
6 |
7 | class BorderImage
8 | {
9 | public:
10 | const QMargins& margin() const { return m_margin; }
11 | const QMargins& border() const { return m_border; }
12 | const QPixmap& pixmap() const { return m_pixmap; }
13 | const QString& pixmap_url() const { return m_pixmapUrl; }
14 |
15 | public:
16 | void setPixmap(const QString& url);
17 | void setPixmap(const QPixmap& pixmap);
18 |
19 | //order: left top right bottom
20 | void setBorder(const QString& border);
21 | void setBorder(const QMargins& border);
22 | void setBorder(int left, int top, int right, int bottom);
23 |
24 | void setMargin(const QString& border);
25 | void setMargin(const QMargins& border);
26 | void setMargin(int left, int top, int right, int bottom);
27 |
28 | void load(const QString& pixmap_url, const QString& border, const QString& margin);
29 |
30 | private:
31 | QMargins m_margin;
32 | QMargins m_border;
33 | QPixmap m_pixmap;
34 | QString m_pixmapUrl;
35 | };
36 |
37 | #endif // BORDERIMAGE_H
38 |
--------------------------------------------------------------------------------
/libframelesswindow/borderimage.cpp:
--------------------------------------------------------------------------------
1 | #include "borderimage.h"
2 | #include
3 |
4 | void BorderImage::setPixmap(const QString& url)
5 | {
6 | m_pixmapUrl = url;
7 | m_pixmap.load(url);
8 | }
9 |
10 | void BorderImage::setPixmap(const QPixmap& pixmap)
11 | {
12 | m_pixmap = pixmap;
13 | }
14 |
15 | void BorderImage::setBorder(const QString& border)
16 | {
17 | QTextStream qs((QString*)&border);
18 | int left, top, right, bottom;
19 | qs >> left >> top >> right >> bottom;
20 | setBorder(left, top, right, bottom);
21 | }
22 |
23 | void BorderImage::setBorder(const QMargins& border)
24 | {
25 | m_border = border;
26 | }
27 |
28 | void BorderImage::setBorder(int left, int top, int right, int bottom)
29 | {
30 | QMargins m(left, top, right, bottom);
31 | m_border = m;
32 | }
33 |
34 | void BorderImage::setMargin(const QString& border)
35 | {
36 | QTextStream qs((QString*)&border);
37 | int left, top, right, bottom;
38 | qs >> left >> top >> right >> bottom;
39 | setMargin(left, top, right, bottom);
40 | }
41 |
42 | void BorderImage::setMargin(const QMargins& border)
43 | {
44 | m_margin = border;
45 | }
46 |
47 | void BorderImage::setMargin(int left, int top, int right, int bottom)
48 | {
49 | QMargins m(left, top, right, bottom);
50 | m_margin = m;
51 | }
52 |
53 | void BorderImage::load(const QString& pixmap_url, const QString& border, const QString& margin)
54 | {
55 | setPixmap(pixmap_url);
56 | setBorder(border);
57 | setMargin(margin);
58 | }
59 |
--------------------------------------------------------------------------------
/libtest/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库/测试程序
3 | *
4 | * mainwindow.cpp
5 | * 测试窗体。
6 | *
7 | */
8 |
9 | #include "mainwindow.h"
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | MainWindow::MainWindow(QWidget *parent)
16 | : FramelessWindow(parent)
17 | {
18 | setWindowTitle(tr("Custom Frameless Window"));
19 | setRubberBandOnMove(false);
20 | hideTitleBar();
21 |
22 | setStyleSheetFile(":/style/style_white.qss");
23 |
24 | QWidget *pMainWidget = new QWidget(this);
25 |
26 | QWidget *leftWidget = new QWidget(this);
27 | leftWidget->setFixedWidth(64);
28 | leftWidget->setStyleSheet("background-color:#03A9F4;");
29 |
30 | QWidget *rightWidget = new QWidget(this);
31 | rightWidget->setStyleSheet("background-color:#EEEEEE;");
32 |
33 | TitleBar *titleBar = new TitleBar(this);
34 |
35 | QWidget *rigthContext = new QWidget(this);
36 | rigthContext->setStyleSheet("background-color:#FFFFFF;");
37 |
38 | QVBoxLayout *rightLayout = new QVBoxLayout(rightWidget);
39 | rightLayout->setMargin(0);
40 | rightLayout->setSpacing(0);
41 | rightLayout->addWidget(titleBar);
42 | rightLayout->addWidget(rigthContext);
43 | rightLayout->addStretch();
44 |
45 |
46 | QHBoxLayout *pLayout = new QHBoxLayout(pMainWidget);
47 | pLayout->addWidget(leftWidget);
48 | pLayout->addWidget(rightWidget);
49 | pLayout->setMargin(0);
50 | pLayout->setSpacing(0);
51 |
52 | setCentralWidget(pMainWidget);
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/libframelesswindow/titlebar.h:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * titlebar.h
5 | * 自定义窗体的标题栏。
6 | *
7 | */
8 |
9 | #ifndef TITLEBAR_H
10 | #define TITLEBAR_H
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | class QLabel;
17 | class QPushButton;
18 | class TitleBar : public QWidget
19 | {
20 | Q_OBJECT
21 | public:
22 | explicit TitleBar(QWidget *parent = nullptr);
23 | ~TitleBar();
24 |
25 | void setMinimumVisible(bool minimum);
26 | void setMaximumVisible(bool maximum);
27 | void setMaximizeDisabled();
28 | void hideTitleIcon();
29 |
30 | protected:
31 | /**
32 | * @brief mouseDoubleClickEvent
33 | * 双击标题栏进行界面的最大化/还原
34 | * @param event
35 | * QMouseEvent *
36 | */
37 | virtual void mouseDoubleClickEvent(QMouseEvent *event);
38 |
39 | // 进行鼠界面的拖动
40 | // virtual void mousePressEvent(QMouseEvent *event);
41 |
42 | /**
43 | * @brief eventFilter
44 | * @note 设置界面标题与图标
45 | * @param obj
46 | * @param event
47 | * @return
48 | * bool
49 | */
50 | virtual bool eventFilter(QObject *obj, QEvent *event);
51 |
52 |
53 | private slots:
54 | /**
55 | * @brief onClicked
56 | * @note 进行最小化、最大化/还原、关闭操作
57 | */
58 | void onClicked();
59 |
60 | private:
61 | /**
62 | * @brief updateMaximize
63 | * @note 最大化/还原
64 | */
65 | void updateMaximize();
66 |
67 | private:
68 | QHBoxLayout *m_pMainLayout;
69 | QLabel *m_pIconLabel;
70 | QLabel *m_pTitleLabel;
71 | StateButton *m_pMinimizeButton;
72 | StateButton *m_pMaximizeButton;
73 | StateButton *m_pCloseButton;
74 | bool m_bMaximizeDisabled;
75 | };
76 |
77 | #endif // TITLEBAR_H
78 |
--------------------------------------------------------------------------------
/libframelesswindow/widgetdata.h:
--------------------------------------------------------------------------------
1 | #ifndef WIDGETDATA_H
2 | #define WIDGETDATA_H
3 | #include
4 | #include
5 | #include "cursorposcalculator.h"
6 |
7 | class FramelessHelperPrivate;
8 | class CursorPosCalculator;
9 | class QWidget;
10 | class QEvent;
11 | class QMouseEvent;
12 | class QRubberBand;
13 | class QPoint;
14 |
15 | class WidgetData
16 | {
17 | public:
18 | explicit WidgetData(FramelessHelperPrivate *_d, QWidget *pTopLevelWidget);
19 | ~WidgetData();
20 |
21 | QWidget *widget();
22 | // 处理鼠标事件-划过、按下、释放、移动
23 | void handleWidgetEvent(QEvent *event);
24 | // 更新橡皮筋状态
25 | void updateRubberBandStatus();
26 |
27 | private:
28 | // 处理鼠标按下
29 | void handleMousePressEvent(QMouseEvent *event);
30 | // 处理鼠标释放
31 | void handleMouseReleaseEvent(QMouseEvent *event);
32 | // 处理鼠标移动
33 | void handleMouseMoveEvent(QMouseEvent *event);
34 | // 处理鼠标离开
35 | void handleLeaveEvent(QMouseEvent *event);
36 | // 处理鼠标进入
37 | void handleHoverMoveEvent(QMouseEvent *event);
38 |
39 | // 更新鼠标样式
40 | void updateCursorShape(const QPoint &gMousePos);
41 | // 重置窗口大小
42 | void resizeWidget(const QPoint &gMousePos);
43 | // 移动窗体
44 | void moveWidget(const QPoint &gMousePos);
45 |
46 | private:
47 | FramelessHelperPrivate *d;
48 | QRubberBand *m_pRubberBand;
49 | QWidget *m_pWidget;
50 | QPoint m_ptDragPos;
51 | double m_dLeftScale; // 鼠标位置距离最窗口最左边的距离占整个宽度的比例
52 | int m_nRightLength; // 鼠标位置距离最窗口最右边的距离
53 | CursorPosCalculator m_pressedMousePos;
54 | CursorPosCalculator m_moveMousePos;
55 | bool m_bLeftButtonPressed;
56 | bool m_bLeftButtonTitlePressed;
57 | bool m_bCursorShapeChanged;
58 | Qt::WindowFlags m_windowFlags;
59 | };
60 |
61 | #endif // WIDGETDATA_H
62 |
--------------------------------------------------------------------------------
/libframelesswindow/statebutton.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef _STATE_BUTTON_H_
3 | #define _STATE_BUTTON_H_
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | //a pixmap have 5 picture which state is normal\hover\pressed\disabled\checked
10 | //this button does not draw focus rect
11 | class StateButton : public QPushButton
12 | {
13 | Q_OBJECT
14 | public:
15 | explicit StateButton(QWidget *parent = 0);
16 | ~StateButton();
17 |
18 | public:
19 | void loadPixmap(const QString& pic_name, int state_count=4);
20 | void setPixmap(const QPixmap& pixmap, int state_count=4);
21 |
22 | void loadBackground(const QString& pic_name, int state_count=4);
23 | void setBackground(const QPixmap& pixmap, int state_count=4);
24 |
25 | protected:
26 | void enterEvent(QEvent *);
27 | void leaveEvent(QEvent *);
28 | void mousePressEvent(QMouseEvent *event);
29 | void mouseReleaseEvent(QMouseEvent *event);
30 | void paintEvent(QPaintEvent *);
31 |
32 | private:
33 | void paint_pixmap();
34 |
35 | private:
36 | //枚举按钮的几种状态
37 | enum ButtonStatus {NORMAL, HOVER, PRESSED, DISABLED, CHECKED};
38 | //pximap_位图类型, 仅能选择其一. 如果两者都需要,请选择BACKGROUND + QPushButton::setIcon
39 | enum PixmapType {NONE, FOREGROUND, BACKGROUND};
40 |
41 | QPixmap m_pixmap; //图片
42 | PixmapType m_pixmapType;
43 | int m_stateCount; //图片有几种状态(几张子图)
44 | ButtonStatus m_status; //当前状态
45 | int m_width; //按钮宽度
46 | int m_height; //按钮高度
47 | bool m_mousePressed; //鼠标左键是否按下
48 | };
49 |
50 | //按钮的图标在上面,文字在下面
51 | class IconTextButton: public QPushButton
52 | {
53 | public:
54 | IconTextButton(QWidget *parent);
55 | ~IconTextButton();
56 |
57 | protected:
58 | void paintEvent(QPaintEvent *e);
59 | };
60 |
61 | class TextButton: public QPushButton
62 | {
63 | Q_OBJECT
64 | public:
65 | TextButton(QWidget *parent = 0);
66 | ~TextButton();
67 | };
68 |
69 | #endif //
70 |
--------------------------------------------------------------------------------
/libframelesswindow/cursorposcalculator.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * cursorposcalculator.cpp
5 | * 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角
6 | *
7 | */
8 |
9 | #include "cursorposcalculator.h"
10 | #include
11 | #include
12 |
13 | int CursorPosCalculator::m_nBorderWidth = 5;
14 | int CursorPosCalculator::m_nTitleHeight = 30;
15 |
16 | CursorPosCalculator::CursorPosCalculator()
17 | {
18 | reset();
19 | }
20 |
21 | void CursorPosCalculator::reset()
22 | {
23 | m_bOnEdges = false;
24 | m_bOnLeftEdge = false;
25 | m_bOnRightEdge = false;
26 | m_bOnTopEdge = false;
27 | m_bOnBottomEdge = false;
28 | m_bOnTopLeftEdge = false;
29 | m_bOnBottomLeftEdge = false;
30 | m_bOnTopRightEdge = false;
31 | m_bOnBottomRightEdge = false;
32 | }
33 |
34 | void CursorPosCalculator::recalculate(const QPoint &gMousePos, const QRect &frameRect)
35 | {
36 | int globalMouseX = gMousePos.x();
37 | int globalMouseY = gMousePos.y();
38 |
39 | int frameX = frameRect.x();
40 | int frameY = frameRect.y();
41 |
42 | int frameWidth = frameRect.width();
43 | int frameHeight = frameRect.height();
44 |
45 | m_bOnLeftEdge = (globalMouseX >= frameX &&
46 | globalMouseX <= frameX + m_nBorderWidth);
47 | m_bOnRightEdge = (globalMouseX >= frameX + frameWidth - m_nBorderWidth &&
48 | globalMouseX <= frameX + frameWidth);
49 | m_bOnTopEdge = (globalMouseY >= frameY &&
50 | globalMouseY <= frameY + m_nBorderWidth);
51 |
52 | m_bOnBottomEdge = (globalMouseY >= frameY + frameHeight - m_nBorderWidth &&
53 | globalMouseY <= frameY + frameHeight);
54 |
55 | m_bOnTopLeftEdge = m_bOnTopEdge && m_bOnLeftEdge;
56 | m_bOnBottomLeftEdge = m_bOnBottomEdge && m_bOnLeftEdge;
57 | m_bOnTopRightEdge = m_bOnTopEdge && m_bOnRightEdge;
58 | m_bOnBottomRightEdge = m_bOnBottomEdge && m_bOnRightEdge;
59 |
60 | m_bOnEdges = m_bOnLeftEdge || m_bOnRightEdge || m_bOnTopEdge || m_bOnBottomEdge;
61 | }
62 |
--------------------------------------------------------------------------------
/libframelesswindow/style/style_black.qss:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库/测试程序
3 | *
4 | * style.qss
5 | * qss全局文件,设置界面的配色主题等。
6 | *
7 | */
8 |
9 |
10 | /********** 无边框主窗体 **********/
11 | FramelessWindow#framelessWindow {
12 | background-color: #323232;
13 | }
14 | /********************************/
15 |
16 |
17 | /*********** 标题栏 **************/
18 | QPushButton#minimizeButton {
19 | border: none;
20 | image: url(:/images/minimizeBtnWhite_16.png);
21 | }
22 | QPushButton#minimizeButton:hover {
23 | background: #505050;
24 | }
25 |
26 | QPushButton#maximizeButton {
27 | border: none;
28 | image: url(:/images/restoreWhite_16.png);
29 | }
30 | QPushButton#maximizeButton:hover {
31 | background: #505050;
32 | }
33 | QPushButton#maximizeButton[maximizeProperty=restore] {
34 | image: url(:/images/restoreWhite_16.png);
35 | }
36 | QPushButton#maximizeButton[maximizeProperty=maximize] {
37 | image: url(:/images/maximizeBtnWhite_16.png);
38 | }
39 |
40 | QPushButton#closeButton {
41 | border: none;
42 | image: url(:/images/closeBtnWhite_16.png);
43 | }
44 | QPushButton#closeButton:hover {
45 | background: #505050;
46 | }
47 |
48 | QPushButton#minimizeButton:pressed {
49 | background: #C8C8C8;
50 | image: url(:/images/minimizeBtnBlack_16.png);
51 | }
52 | QPushButton#maximizeButton:pressed {
53 | background: #C8C8C8;
54 | image: url(:/images/restoreBlack_16.png);
55 | }
56 | QPushButton#closeButton:pressed {
57 | background: #C8C8C8;
58 | image: url(:/images/closeBtnBlack_16.png);
59 | }
60 | QLabel#titleLabel {
61 | color: white;
62 | }
63 | /********************************/
64 |
65 | /******* 自定义无边框提示框 *******/
66 | FramelessMessageBox#framelessMessagBox {
67 | background-color: #404040;
68 | }
69 | QLabel#messageTextLabel {
70 | color: white;
71 | font-family: "Microsoft Yahei";
72 | font-size: 14pt;
73 | }
74 | QPushButton#yesButton {
75 | background-color: red;
76 | }
77 | /********************************/
78 |
79 | /******* 自定义无边框对话框 *******/
80 | FramelessDialog#framelessDialog {
81 | background-color: #2E2E2E;
82 | }
83 | /********************************/
84 |
85 |
--------------------------------------------------------------------------------
/libframelesswindow/style/style_white.qss:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库/测试程序
3 | *
4 | * style.qss
5 | * qss全局文件,设置界面的配色主题等。
6 | *
7 | */
8 |
9 |
10 | /********** 无边框主窗体 **********/
11 | QWidget#framelessWindow {
12 | background-color: white;
13 | border-style: solid;
14 | border-width: 1px;
15 | border-color: green;
16 | }
17 | /********************************/
18 |
19 |
20 | /*********** 标题栏 **************/
21 | QPushButton#minimizeButton {
22 | border: none;
23 | image: url(:/images/minimizeBtnWhite_16.png);
24 | }
25 | QPushButton#minimizeButton:hover {
26 | background: #505050;
27 | }
28 |
29 | QPushButton#maximizeButton {
30 | border: none;
31 | image: url(:/images/restoreWhite_16.png);
32 | }
33 | QPushButton#maximizeButton:hover {
34 | background: #505050;
35 | }
36 | QPushButton#maximizeButton[maximizeProperty=restore] {
37 | image: url(:/images/restoreWhite_16.png);
38 | }
39 | QPushButton#maximizeButton[maximizeProperty=maximize] {
40 | image: url(:/images/maximizeBtnWhite_16.png);
41 | }
42 |
43 | QPushButton#closeButton {
44 | border: none;
45 | image: url(:/images/closeBtnWhite_16.png);
46 | }
47 | QPushButton#closeButton:hover {
48 | background: #505050;
49 | }
50 |
51 | QPushButton#minimizeButton:pressed {
52 | background: #C8C8C8;
53 | image: url(:/images/minimizeBtnBlack_16.png);
54 | }
55 | QPushButton#maximizeButton:pressed {
56 | background: #C8C8C8;
57 | image: url(:/images/restoreBlack_16.png);
58 | }
59 | QPushButton#closeButton:pressed {
60 | background: #C8C8C8;
61 | image: url(:/images/closeBtnBlack_16.png);
62 | }
63 | QLabel#titleLabel {
64 | color: white;
65 | }
66 | /********************************/
67 |
68 | /******* 自定义无边框提示框 *******/
69 | FramelessMessageBox#framelessMessagBox {
70 | background-color: white;
71 | border-style: solid;
72 | border-width: 1px;
73 | border-color: green;
74 | }
75 | QLabel#messageTextLabel {
76 | color: white;
77 | font-family: "Microsoft Yahei";
78 | font-size: 14pt;
79 | }
80 | QPushButton#yesButton {
81 | background-color: red;
82 | }
83 | /********************************/
84 |
85 | /******* 自定义无边框对话框 *******/
86 | FramelessDialog#framelessDialog {
87 | background-color: white;
88 | border-style: solid;
89 | border-width: 1px;
90 | border-color: green;
91 | }
92 | /********************************/
93 |
94 |
--------------------------------------------------------------------------------
/libframelesswindow/framelesshelper.h:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * framelesshelper.h
5 | * FramelessHelper类。设置窗体是否可移动、缩放、橡皮筋等属性。
6 | *
7 | */
8 |
9 | #ifndef FRAMELESSHELPER_H
10 | #define FRAMELESSHELPER_H
11 |
12 | #include
13 | #include
14 | #include "widgetdata.h"
15 |
16 |
17 | class QWdiget;
18 | class FramelessHelperPrivate;
19 | class FramelessHelper : public QObject
20 | {
21 | Q_OBJECT
22 | public:
23 | explicit FramelessHelper(QObject *parent = nullptr);
24 | ~FramelessHelper();
25 |
26 | /**
27 | * @brief activateOn
28 | * 激活窗体
29 | * @param topLevelWidget
30 | * QWidget *
31 | */
32 | void activateOn(QWidget *topLevelWidget);
33 |
34 | /**
35 | * @brief removeFrom
36 | * 移除窗体
37 | * @param topLevelWidget
38 | * QWidget *
39 | */
40 | void removeFrom(QWidget *topLevelWidget);
41 |
42 | /**
43 | * @brief setWidgetMovable
44 | * 设置窗体移动
45 | * @param movable
46 | * bool
47 | */
48 | void setWidgetMovable(bool movable);
49 |
50 | /**
51 | * @brief setWidgetResizable
52 | * 设置窗体缩放
53 | * @param resizable
54 | * bool
55 | */
56 |
57 | void setWidgetResizable(bool resizable);
58 | /**
59 | * @brief setRubberBandOnMove
60 | * 设置橡皮筋移动
61 | * @param movable
62 | * bool
63 | */
64 | void setRubberBandOnMove(bool movable);
65 | /**
66 | * @brief setRubberBandOnResize
67 | * 设置橡皮筋缩放
68 | * @param resizable
69 | * bool
70 | */
71 | void setRubberBandOnResize(bool resizable);
72 |
73 | /**
74 | * @brief setBorderWidth
75 | * 设置边框的宽度
76 | * @param width
77 | * unsigned int
78 | */
79 | void setBorderWidth(uint width);
80 |
81 | /**
82 | * @brief setTitleHeight
83 | * 设置标题栏高度
84 | * @param height
85 | * unsigned int
86 | */
87 | void setTitleHeight(uint height);
88 |
89 | bool widgetResizable() const;
90 | bool widgetMoable() const;
91 | bool rubberBandOnMove() const;
92 | bool rubberBandOnResize() const;
93 | uint borderWidth() const;
94 | uint titleHeight() const;
95 |
96 | protected:
97 | virtual bool eventFilter(QObject *watched, QEvent *event);
98 |
99 | private:
100 | FramelessHelperPrivate *d;
101 | };
102 |
103 | #endif // FRAMELESSHELPER_H
104 |
--------------------------------------------------------------------------------
/libframelesswindow/framelesshelper.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * framelesshelper.cpp
5 | * 实现了FramelessHelper类。设置窗体是否可移动、缩放、橡皮筋等属性。
6 | *
7 | */
8 |
9 | #include "framelesshelper.h"
10 | #include "framelesshelperprivate.h"
11 | #include "cursorposcalculator.h"
12 | #include
13 | #include
14 |
15 | FramelessHelper::FramelessHelper(QObject *parent)
16 | : QObject(parent)
17 | , d(new FramelessHelperPrivate())
18 | {
19 | d->m_bWidgetMovable = true;
20 | d->m_bWidgetResizable = true;
21 | d->m_bRubberBandOnMove = false;
22 | d->m_bRubberBandOnResize = false;
23 | }
24 |
25 | FramelessHelper::~FramelessHelper()
26 | {
27 | QList keys = d->m_widgetDataHash.keys();
28 | int size = keys.size();
29 | for(int i = 0; i < size; ++i) {
30 | delete d->m_widgetDataHash.take(keys[i]);
31 | }
32 |
33 | delete d;
34 | }
35 |
36 | void FramelessHelper::activateOn(QWidget *topLevelWidget)
37 | {
38 | if(!d->m_widgetDataHash.contains(topLevelWidget)) {
39 | WidgetData *data = new WidgetData(d, topLevelWidget);
40 | d->m_widgetDataHash.insert(topLevelWidget, data);
41 |
42 | topLevelWidget->installEventFilter(this);
43 | }
44 | }
45 |
46 | void FramelessHelper::removeFrom(QWidget *topLevelWidget)
47 | {
48 | WidgetData *data = d->m_widgetDataHash.take(topLevelWidget);
49 | if(data) {
50 | topLevelWidget->removeEventFilter(this);
51 | delete data;
52 | }
53 | }
54 |
55 | void FramelessHelper::setWidgetMovable(bool movable)
56 | {
57 | d->m_bWidgetMovable = movable;
58 | }
59 |
60 | void FramelessHelper::setWidgetResizable(bool resizable)
61 | {
62 | d->m_bWidgetResizable = resizable;
63 | }
64 |
65 | void FramelessHelper::setRubberBandOnMove(bool movable)
66 | {
67 | d->m_bRubberBandOnMove = movable;
68 | QList list = d->m_widgetDataHash.values();
69 | foreach(WidgetData *data, list) {
70 | data->updateRubberBandStatus();
71 | }
72 | }
73 |
74 | void FramelessHelper::setRubberBandOnResize(bool resizable)
75 | {
76 | d->m_bRubberBandOnResize = resizable;
77 | QList list = d->m_widgetDataHash.values();
78 | foreach(WidgetData *data, list) {
79 | data->updateRubberBandStatus();
80 | }
81 | }
82 |
83 | void FramelessHelper::setBorderWidth(uint width)
84 | {
85 | if(width > 0) {
86 | CursorPosCalculator::m_nBorderWidth = width;
87 | }
88 | }
89 |
90 | void FramelessHelper::setTitleHeight(uint height)
91 | {
92 | if(height > 0) {
93 | CursorPosCalculator::m_nTitleHeight = height;
94 | }
95 | }
96 |
97 | bool FramelessHelper::widgetResizable() const
98 | {
99 | return d->m_bWidgetResizable;
100 | }
101 |
102 | bool FramelessHelper::widgetMoable() const
103 | {
104 | return d->m_bWidgetMovable;
105 | }
106 |
107 | bool FramelessHelper::rubberBandOnMove() const
108 | {
109 | return d->m_bRubberBandOnMove;
110 | }
111 |
112 | bool FramelessHelper::rubberBandOnResize() const
113 | {
114 | return d->m_bRubberBandOnResize;
115 | }
116 |
117 | uint FramelessHelper::borderWidth() const
118 | {
119 | return CursorPosCalculator::m_nBorderWidth;
120 | }
121 |
122 | uint FramelessHelper::titleHeight() const
123 | {
124 | return CursorPosCalculator::m_nTitleHeight;
125 | }
126 |
127 | bool FramelessHelper::eventFilter(QObject *watched, QEvent *event)
128 | {
129 | switch(event->type()) {
130 | case QEvent::MouseMove:
131 | case QEvent::HoverMove:
132 | case QEvent::MouseButtonPress:
133 | case QEvent::MouseButtonRelease:
134 | case QEvent::Leave:
135 | {
136 | WidgetData *data = d->m_widgetDataHash.value(static_cast(watched));
137 | if(data) {
138 | data->handleWidgetEvent(event);
139 | return true;
140 | }
141 | }
142 | default:
143 | return QObject::eventFilter(watched, event);
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/libframelesswindow/statebutton.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "statebutton.h"
3 | #include
4 | #include
5 | #include
6 |
7 | StateButton::StateButton(QWidget *parent)
8 | :QPushButton(parent)
9 | ,m_status(NORMAL)
10 | ,m_mousePressed(false)
11 | ,m_pixmapType(NONE)
12 | {
13 | setStyleSheet("QPushButton{background:transparent;border:none;}");
14 | }
15 |
16 | StateButton::~StateButton()
17 | {
18 | }
19 |
20 | void StateButton::loadPixmap(const QString& pic_name, int state_count)
21 | {
22 | m_pixmapType = FOREGROUND;
23 | m_pixmap.load(pic_name);
24 | m_stateCount = state_count;
25 | m_width = m_pixmap.width()/state_count;
26 | m_height = m_pixmap.height();
27 | setFixedSize(m_width, m_height);
28 | }
29 |
30 | void StateButton::setPixmap(const QPixmap& pixmap, int state_count)
31 | {
32 | m_pixmapType = FOREGROUND;
33 | m_pixmap = pixmap;
34 | m_stateCount = state_count;
35 | m_width = m_pixmap.width()/state_count;
36 | m_height = m_pixmap.height();
37 | setFixedSize(m_width, m_height);
38 | }
39 |
40 | void StateButton::loadBackground(const QString& pic_name, int state_count/*=4*/)
41 | {
42 | loadPixmap(pic_name, state_count);
43 | m_pixmapType = BACKGROUND;
44 | }
45 |
46 | void StateButton::setBackground(const QPixmap& pixmap, int state_count/*=4*/)
47 | {
48 | setPixmap(pixmap, state_count);
49 | m_pixmapType = BACKGROUND;
50 | }
51 |
52 | void StateButton::enterEvent(QEvent *e)
53 | {
54 | m_status = HOVER;
55 | update();
56 | }
57 |
58 | void StateButton::mousePressEvent(QMouseEvent *event)
59 | {
60 | if(event->button() == Qt::LeftButton) {
61 | m_mousePressed = true;
62 | m_status = PRESSED;
63 | update();
64 | }
65 |
66 | QPushButton::mousePressEvent(event);
67 | }
68 |
69 | void StateButton::mouseReleaseEvent(QMouseEvent *event)
70 | {
71 | if(m_mousePressed) {
72 | m_mousePressed = false;
73 |
74 | if(this->rect().contains(event->pos())) {
75 | //if (isCheckable())
76 | //{
77 | // setChecked(!isChecked());
78 | //}
79 | //emit clicked();
80 |
81 | m_status = HOVER;
82 | } else {
83 | m_status = NORMAL;
84 | }
85 |
86 | update();
87 | }
88 |
89 | QPushButton::mouseReleaseEvent(event);
90 | }
91 |
92 | void StateButton::leaveEvent(QEvent *e)
93 | {
94 | m_status = NORMAL;
95 | update();
96 | QPushButton::leaveEvent(e);
97 | }
98 |
99 | void StateButton::paintEvent(QPaintEvent *e)
100 | {
101 | if(m_pixmapType == BACKGROUND) {
102 | paint_pixmap();
103 | }
104 |
105 | // QPushButton::paintEvent(e);
106 | QStylePainter p(this);
107 | QStyleOptionButton option;
108 | initStyleOption(&option);
109 | if(option.state & QStyle::State_HasFocus) {
110 | option.state ^= QStyle::State_HasFocus; //去除焦点框
111 | option.state |= QStyle::State_MouseOver;
112 | }
113 | p.drawControl(QStyle::CE_PushButton, option);
114 |
115 | if(m_pixmapType == FOREGROUND) {
116 | paint_pixmap();
117 | }
118 | }
119 |
120 | void StateButton::paint_pixmap()
121 | {
122 | QPainter painter(this);
123 |
124 | //根据状态显示图片
125 | ButtonStatus status = m_status;
126 | if(!isEnabled()) {
127 | status = DISABLED;
128 | } else if(isChecked()) {
129 | status = CHECKED;
130 | //没有checked图片,用hover代替
131 | if(status >= m_stateCount) {
132 | status = HOVER;
133 | }
134 | }
135 |
136 | if(status >= m_stateCount) {
137 | status = NORMAL;
138 | }
139 |
140 | painter.drawPixmap(rect(), m_pixmap.copy(m_width * status, 0, m_width, m_height));
141 | }
142 | //////////////////////////////////////////////////////////////////////////
143 |
144 |
145 | IconTextButton::IconTextButton(QWidget *parent)
146 | :QPushButton(parent)
147 | {
148 | }
149 |
150 | IconTextButton::~IconTextButton()
151 | {
152 | }
153 |
154 | void IconTextButton::paintEvent(QPaintEvent *e)
155 | {
156 | QStyleOptionButton opt;
157 | initStyleOption(&opt);
158 | //opt.text = "";
159 | //opt.icon = QIcon();
160 | //opt.state &= ~QStyle::State_HasFocus; //去除焦点框
161 |
162 | QStylePainter p(this);
163 | //绘制QSS描述的如border-image等
164 | p.drawControl(QStyle::CE_PushButtonBevel, opt);
165 |
166 | QRect r = rect(); //style()->subElementRect ( QStyle::SE_PushButtonContents, &opt, this);
167 |
168 | int v_space = 2;
169 | int x = r.left() + (r.width() - opt.iconSize.width()) / 2;
170 | int h = opt.iconSize.height() + v_space + opt.fontMetrics.height();
171 | int y = r.top() + (r.height() - h) / 2;
172 |
173 | //y -= 2;
174 |
175 | p.drawPixmap(x, y, opt.icon.pixmap(opt.iconSize));
176 |
177 | y += opt.iconSize.height() + v_space;
178 | y += opt.fontMetrics.ascent(); //加这个值的原因:The y-position is used as the baseline of the font.
179 | x = r.left() + (r.width() - opt.fontMetrics.width(opt.text)) / 2;
180 | p.drawText(x, y, opt.text);
181 | }
182 |
183 | TextButton::TextButton(QWidget *parent)
184 | :QPushButton(parent)
185 | {
186 | this->setFlat(true);
187 | this->setStyleSheet("QPushButton{background: transparent;}");
188 | }
189 |
190 | TextButton::~TextButton()
191 | {
192 |
193 | }
194 |
--------------------------------------------------------------------------------
/libframelesswindow/framelesswindow.h:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * framelesswindow.h
5 | * 定义了FramelessWindow、FramlessDialog、FramelessMessageBox
6 | *
7 | */
8 |
9 | #ifndef FRAMELESSWINDOW_H
10 | #define FRAMELESSWINDOW_H
11 |
12 | #include "framelesswindow_global.h"
13 | #include "borderimage.h"
14 | #include "widgetshadow.h"
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | typedef WidgetShadow FramelessWindow;
25 |
26 | /**
27 | * @brief The FramelessDialog class
28 | * 无边框自定义对话框
29 | */
30 | class FRAMELESSWINDOWSHARED_EXPORT FramelessDialog : public WidgetShadow
31 | {
32 | Q_OBJECT
33 |
34 | public:
35 | FramelessDialog(QWidget *parent = nullptr);
36 |
37 | };
38 |
39 |
40 | class QLabel;
41 | class QGridLayout;
42 | class QDialogButtonBox;
43 | class QHBoxLayout;
44 | class QAbstractButton;
45 | /**
46 | * @brief The FramelessMessageBox class
47 | * 无边框自定义提示框
48 | */
49 | class FRAMELESSWINDOWSHARED_EXPORT FramelessMessageBox : public FramelessDialog
50 | {
51 | Q_OBJECT
52 |
53 | public:
54 | FramelessMessageBox(QWidget *parent = nullptr, const QString &title = tr("Tip"), const QString &text = "",
55 | QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = QMessageBox::Ok);
56 |
57 | ~FramelessMessageBox();
58 |
59 | enum IconType {
60 | MSG_NOICON = 0, // 无图标
61 | MSG_INFORMATION, // 提示信息
62 | MSG_WARNNING, // 提示警告
63 | MSG_QUESTION, // 提示询问
64 | MSG_ERROR, // 提示错误
65 | MSG_SUCCESS, // 提示成功
66 | };
67 |
68 | QAbstractButton *clickedButton() const;
69 | QMessageBox::StandardButton standardButton(QAbstractButton *button) const;
70 | /**
71 | * @brief setDefaultButton
72 | * 设置默认按钮
73 | * @param button
74 | */
75 | void setDefaultButton(QPushButton *button);
76 | void setDefaultButton(QMessageBox::StandardButton button);
77 | /**
78 | * @brief setTitle
79 | * 设置窗体标题
80 | * @param title
81 | */
82 | void setTitle(const QString &title);
83 | /**
84 | * @brief setText
85 | * @note 设置提示信息
86 | * @param text
87 | */
88 | void setText(const QString &text);
89 | /**
90 | * @brief setIcon
91 | * @note 设置窗体图标
92 | * @param icon
93 | */
94 | void setIcon(const QString &icon);
95 |
96 | /**
97 | * @brief hideInfoIcon
98 | * @note 隐藏icon
99 | */
100 | void hideInfoIcon();
101 |
102 | /**
103 | * @brief addWidget
104 | * 添加控件-替换提示信息所在的QLabel
105 | * @param pWidget
106 | */
107 | void addWidget(QWidget *pWidget);
108 |
109 | static QMessageBox::StandardButton showMessageBox(QWidget *parent, const QString &title,
110 | const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
111 | IconType messageType = MSG_NOICON,
112 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
113 |
114 | static QMessageBox::StandardButton showInformation(QWidget *parent, const QString &title,
115 | const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
116 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
117 | static QMessageBox::StandardButton showError(QWidget *parent, const QString &title,
118 | const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
119 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
120 | static QMessageBox::StandardButton showSuccess(QWidget *parent, const QString &title,
121 | const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
122 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
123 | static QMessageBox::StandardButton showQuestion(QWidget *parent, const QString &title,
124 | const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No,
125 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
126 | static QMessageBox::StandardButton showWarning(QWidget *parent, const QString &title,
127 | const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
128 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
129 | static QMessageBox::StandardButton showCritical(QWidget *parent, const QString &title,
130 | const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok,
131 | QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
132 | static QMessageBox::StandardButton showCheckBoxQuestion(QWidget *parent, const QString &title,
133 | const QString &text, QMessageBox::StandardButtons buttons,
134 | QMessageBox::StandardButton defaultButton);
135 |
136 |
137 | protected:
138 | /**
139 | * @brief changeEvent
140 | * 多语言翻译
141 | * @param event
142 | */
143 | void changeEvent(QEvent *event);
144 |
145 | private slots:
146 | void onButtonClicked(QAbstractButton *button);
147 |
148 | private:
149 | void translateUI();
150 | int execReturnCode(QAbstractButton *button);
151 |
152 | private:
153 | QLabel *m_pIconLabel;
154 | QLabel *m_pLabel;
155 | QGridLayout *m_pGridLayout;
156 | QDialogButtonBox *m_pButtonBox;
157 | QAbstractButton *m_pClickedButton;
158 | QAbstractButton *m_pDefaultButton;
159 | QHBoxLayout *m_pLayout;
160 | };
161 |
162 | #endif // FRAMELESSWINDOW_H
163 |
--------------------------------------------------------------------------------
/libframelesswindow/titlebar.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * titlebar.cpp
5 | * 自定义窗体的标题栏。
6 | *
7 | */
8 |
9 | #include "titlebar.h"
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | TitleBar::TitleBar(QWidget *parent)
20 | : QWidget(parent)
21 | , m_bMaximizeDisabled(false)
22 | {
23 | setFixedHeight(30);
24 |
25 | m_pIconLabel = new QLabel(this);
26 | m_pTitleLabel = new QLabel(this);
27 | m_pMinimizeButton = new StateButton(this);
28 | m_pMinimizeButton->setPixmap(QPixmap(":/images/titlebar/min.png"));
29 | m_pMaximizeButton = new StateButton(this);
30 | m_pMaximizeButton->setPixmap(QPixmap(":/images/titlebar/max.png"));
31 | m_pCloseButton = new StateButton(this);
32 | m_pCloseButton->setPixmap(QPixmap(":/images/titlebar/close.png"));
33 |
34 | m_pIconLabel->setFixedSize(20, 20);
35 | m_pIconLabel->setScaledContents(true);
36 |
37 | m_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
38 |
39 | m_pTitleLabel->setObjectName("titleLabel");
40 | m_pMinimizeButton->setObjectName("minimizeButton");
41 | m_pMaximizeButton->setObjectName("maximizeButton");
42 | m_pCloseButton->setObjectName("closeButton");
43 |
44 | m_pMinimizeButton->setToolTip("Minimize");
45 | m_pMaximizeButton->setToolTip("Maximize");
46 | m_pCloseButton->setToolTip("Close");
47 |
48 | m_pMainLayout = new QHBoxLayout(this);
49 | m_pMainLayout->addSpacing(5);
50 | m_pMainLayout->addWidget(m_pIconLabel);
51 | m_pMainLayout->addSpacing(5);
52 | m_pMainLayout->addWidget(m_pTitleLabel);
53 | m_pMainLayout->addStretch();
54 | m_pMainLayout->addWidget(m_pMinimizeButton);
55 | m_pMainLayout->addWidget(m_pMaximizeButton);
56 | m_pMainLayout->addWidget(m_pCloseButton);
57 | m_pMainLayout->setSpacing(0);
58 | m_pMainLayout->setMargin(0);
59 |
60 | setLayout(m_pMainLayout);
61 |
62 | connect(m_pMinimizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
63 | connect(m_pMaximizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
64 | connect(m_pCloseButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
65 | }
66 | TitleBar::~TitleBar()
67 | {
68 |
69 | }
70 |
71 | void TitleBar::setMinimumVisible(bool minimum)
72 | {
73 | if(!minimum) m_pMinimizeButton->hide();
74 | }
75 |
76 | void TitleBar::setMaximumVisible(bool maximum)
77 | {
78 | if(!maximum) m_pMaximizeButton->hide();
79 | }
80 |
81 | void TitleBar::setMaximizeDisabled()
82 | {
83 | m_bMaximizeDisabled = true;
84 | }
85 |
86 | void TitleBar::hideTitleIcon()
87 | {
88 | m_pIconLabel->setVisible(false);
89 | }
90 |
91 | void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
92 | {
93 | Q_UNUSED(event);
94 | if(m_bMaximizeDisabled) {
95 | return;
96 | }
97 |
98 | emit m_pMaximizeButton->clicked();
99 | }
100 |
101 | //void TitleBar::mousePressEvent(QMouseEvent *event)
102 | //{
103 | // if (ReleaseCapture())
104 | // {
105 | // QWidget *pWindow = this->window();
106 | // if (pWindow->isTopLevel())
107 | // {
108 | // SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
109 | // }
110 | // }
111 | // event->ignore();
112 | //}
113 |
114 | bool TitleBar::eventFilter(QObject *obj, QEvent *event)
115 | {
116 | switch(event->type()) {
117 | case QEvent::WindowTitleChange:
118 | {
119 | QWidget *pWidget = qobject_cast(obj);
120 | if(pWidget) {
121 | m_pTitleLabel->setText(pWidget->windowTitle());
122 | return true;
123 | }
124 | }
125 | case QEvent::WindowIconChange:
126 | {
127 | QWidget *pWidget = qobject_cast(obj);
128 | if(pWidget) {
129 | QIcon icon = pWidget->windowIcon();
130 | m_pIconLabel->setPixmap(icon.pixmap(m_pIconLabel->size()));
131 | return true;
132 | }
133 | }
134 | case QEvent::Move:
135 | case QEvent::WindowStateChange:
136 | case QEvent::Resize:
137 | updateMaximize();
138 | return true;
139 | default:
140 | return QWidget::eventFilter(obj, event);
141 | }
142 | }
143 |
144 | void TitleBar::onClicked()
145 | {
146 | QPushButton *pButton = qobject_cast(sender());
147 | QWidget *pWindow = this->window();
148 | if(pWindow->isTopLevel()) {
149 | if(pButton == m_pMinimizeButton) {
150 | pWindow->showMinimized();
151 | } else if(pButton == m_pMaximizeButton) {
152 | if(pWindow->isMaximized()) {
153 | pWindow->showNormal();
154 | m_pMaximizeButton->setPixmap(QPixmap(":/images/titlebar/max.png"));
155 | } else {
156 | pWindow->showMaximized();
157 | window()->setGeometry(QApplication::desktop()->availableGeometry());
158 | m_pMaximizeButton->setPixmap(QPixmap(":/images/titlebar/restore.png"));
159 | }
160 | } else if(pButton == m_pCloseButton) {
161 | pWindow->close();
162 | }
163 | }
164 | }
165 |
166 | void TitleBar::updateMaximize()
167 | {
168 | QWidget *pWindow = this->window();
169 | if(pWindow->isTopLevel()) {
170 | bool bMaximize = pWindow->isMaximized();
171 | if(bMaximize) {
172 | m_pMaximizeButton->setToolTip(tr("Restore"));
173 | m_pMaximizeButton->setProperty("maximizeProperty", "restore");
174 | } else {
175 | m_pMaximizeButton->setProperty("maximizeProperty", "maximize");
176 | m_pMaximizeButton->setToolTip(tr("Maximize"));
177 | }
178 |
179 | m_pMaximizeButton->setStyle(QApplication::style());
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/libframelesswindow/widgetdata.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * widgetdata.cpp
5 | * 处理鼠标事件。
6 | *
7 | */
8 |
9 | #include "widgetdata.h"
10 | #include "framelesshelperprivate.h"
11 | #include "cursorposcalculator.h"
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | WidgetData::WidgetData(FramelessHelperPrivate *_d, QWidget *pTopLevelWidget)
20 | {
21 | d = _d;
22 | m_pWidget = pTopLevelWidget;
23 | m_bLeftButtonPressed = false;
24 | m_bCursorShapeChanged = false;
25 | m_bLeftButtonTitlePressed = false;
26 | m_pRubberBand = NULL;
27 |
28 | m_windowFlags = m_pWidget->windowFlags();
29 | m_pWidget->setMouseTracking(true);
30 | m_pWidget->setAttribute(Qt::WA_Hover, true);
31 |
32 | updateRubberBandStatus();
33 | }
34 |
35 | WidgetData::~WidgetData()
36 | {
37 | m_pWidget->setMouseTracking(false);
38 | m_pWidget->setWindowFlags(m_windowFlags);
39 | m_pWidget->setAttribute(Qt::WA_Hover, false);
40 |
41 | delete m_pRubberBand;
42 | m_pRubberBand = NULL;
43 | }
44 |
45 | QWidget *WidgetData::widget()
46 | {
47 | return m_pWidget;
48 | }
49 |
50 | void WidgetData::handleWidgetEvent(QEvent *event)
51 | {
52 | switch(event->type()) {
53 | case QEvent::MouseButtonPress:
54 | handleMousePressEvent(static_cast(event));
55 | break;
56 |
57 | case QEvent::MouseButtonRelease:
58 | handleMouseReleaseEvent(static_cast(event));
59 | break;
60 |
61 | case QEvent::MouseMove:
62 | handleMouseMoveEvent(static_cast(event));
63 | break;
64 |
65 | case QEvent::Leave:
66 | handleLeaveEvent(static_cast(event));
67 | break;
68 |
69 | case QEvent::HoverMove:
70 | handleHoverMoveEvent(static_cast(event));
71 | break;
72 |
73 | default:
74 | break;
75 | }
76 | }
77 |
78 | void WidgetData::updateRubberBandStatus()
79 | {
80 | if(d->m_bRubberBandOnMove || d->m_bRubberBandOnResize) {
81 | if(NULL == m_pRubberBand)
82 | m_pRubberBand = new QRubberBand(QRubberBand::Rectangle);
83 | } else {
84 | delete m_pRubberBand;
85 | m_pRubberBand = NULL;
86 | }
87 | }
88 |
89 | void WidgetData::handleMousePressEvent(QMouseEvent *event)
90 | {
91 | if(event->button() == Qt::LeftButton) {
92 | m_bLeftButtonPressed = true;
93 | m_bLeftButtonTitlePressed = event->pos().y() < m_moveMousePos.m_nTitleHeight;
94 |
95 | QRect frameRect = m_pWidget->frameGeometry();
96 | m_pressedMousePos.recalculate(event->globalPos(), frameRect);
97 |
98 | m_ptDragPos = event->globalPos() - frameRect.topLeft();
99 | m_dLeftScale = double(m_ptDragPos.x()) / double(frameRect.width());
100 | m_nRightLength = frameRect.width() - m_ptDragPos.x();
101 |
102 | if(m_pressedMousePos.m_bOnEdges) {
103 | if(d->m_bRubberBandOnResize) {
104 | m_pRubberBand->setGeometry(frameRect);
105 | m_pRubberBand->show();
106 | }
107 | } else if(d->m_bRubberBandOnMove) {
108 | m_pRubberBand->setGeometry(frameRect);
109 | m_pRubberBand->show();
110 | }
111 | }
112 | }
113 |
114 | void WidgetData::handleMouseReleaseEvent(QMouseEvent *event)
115 | {
116 | if(event->button() == Qt::LeftButton) {
117 | m_bLeftButtonPressed = false;
118 | m_bLeftButtonTitlePressed = false;
119 | m_pressedMousePos.reset();
120 | if(m_pRubberBand && m_pRubberBand->isVisible()) {
121 | m_pRubberBand->hide();
122 | m_pWidget->setGeometry(m_pRubberBand->geometry());
123 | }
124 | }
125 | }
126 |
127 | void WidgetData::handleMouseMoveEvent(QMouseEvent *event)
128 | {
129 | if(m_bLeftButtonPressed) {
130 | if(d->m_bWidgetResizable && m_pressedMousePos.m_bOnEdges) {
131 | resizeWidget(event->globalPos());
132 | } else if(d->m_bWidgetMovable && m_bLeftButtonTitlePressed) {
133 | moveWidget(event->globalPos());
134 | }
135 | } else if(d->m_bWidgetResizable) {
136 | updateCursorShape(event->globalPos());
137 | }
138 | }
139 |
140 | void WidgetData::handleLeaveEvent(QMouseEvent *event)
141 | {
142 | Q_UNUSED(event)
143 | if(!m_bLeftButtonPressed) {
144 | m_pWidget->unsetCursor();
145 | }
146 | }
147 |
148 | void WidgetData::handleHoverMoveEvent(QMouseEvent *event)
149 | {
150 | if(d->m_bWidgetResizable) {
151 | updateCursorShape(m_pWidget->mapToGlobal(event->pos()));
152 | }
153 | }
154 |
155 | void WidgetData::updateCursorShape(const QPoint &gMousePos)
156 | {
157 | if(m_pWidget->isFullScreen() || m_pWidget->isMaximized()) {
158 | if(m_bCursorShapeChanged) {
159 | m_pWidget->unsetCursor();
160 | }
161 | return;
162 | }
163 |
164 | m_moveMousePos.recalculate(gMousePos, m_pWidget->frameGeometry());
165 |
166 | if(m_moveMousePos.m_bOnTopLeftEdge || m_moveMousePos.m_bOnBottomRightEdge) {
167 | m_pWidget->setCursor(Qt::SizeFDiagCursor);
168 | m_bCursorShapeChanged = true;
169 | } else if(m_moveMousePos.m_bOnTopRightEdge || m_moveMousePos.m_bOnBottomLeftEdge) {
170 | m_pWidget->setCursor(Qt::SizeBDiagCursor);
171 | m_bCursorShapeChanged = true;
172 | } else if(m_moveMousePos.m_bOnLeftEdge || m_moveMousePos.m_bOnRightEdge) {
173 | m_pWidget->setCursor(Qt::SizeHorCursor);
174 | m_bCursorShapeChanged = true;
175 | } else if(m_moveMousePos.m_bOnTopEdge || m_moveMousePos.m_bOnBottomEdge) {
176 | m_pWidget->setCursor(Qt::SizeVerCursor);
177 | m_bCursorShapeChanged = true;
178 | } else {
179 | if(m_bCursorShapeChanged) {
180 | m_pWidget->unsetCursor();
181 | m_bCursorShapeChanged = false;
182 | }
183 | }
184 | }
185 |
186 | void WidgetData::resizeWidget(const QPoint &gMousePos)
187 | {
188 | QRect origRect;
189 |
190 | if(d->m_bRubberBandOnResize)
191 | origRect = m_pRubberBand->frameGeometry();
192 | else
193 | origRect = m_pWidget->frameGeometry();
194 |
195 | int left = origRect.left();
196 | int top = origRect.top();
197 | int right = origRect.right();
198 | int bottom = origRect.bottom();
199 | origRect.getCoords(&left, &top, &right, &bottom);
200 |
201 | int minWidth = m_pWidget->minimumWidth();
202 | int minHeight = m_pWidget->minimumHeight();
203 |
204 | if(m_pressedMousePos.m_bOnTopLeftEdge) {
205 | left = gMousePos.x();
206 | top = gMousePos.y();
207 | } else if(m_pressedMousePos.m_bOnBottomLeftEdge) {
208 | left = gMousePos.x();
209 | bottom = gMousePos.y();
210 | } else if(m_pressedMousePos.m_bOnTopRightEdge) {
211 | right = gMousePos.x();
212 | top = gMousePos.y();
213 | } else if(m_pressedMousePos.m_bOnBottomRightEdge) {
214 | right = gMousePos.x();
215 | bottom = gMousePos.y();
216 | } else if(m_pressedMousePos.m_bOnLeftEdge) {
217 | left = gMousePos.x();
218 | } else if(m_pressedMousePos.m_bOnRightEdge) {
219 | right = gMousePos.x();
220 | } else if(m_pressedMousePos.m_bOnTopEdge) {
221 | top = gMousePos.y();
222 | } else if(m_pressedMousePos.m_bOnBottomEdge) {
223 | bottom = gMousePos.y();
224 | }
225 |
226 | QRect newRect(QPoint(left, top), QPoint(right, bottom));
227 |
228 | if(newRect.isValid()) {
229 | if(minWidth > newRect.width()) {
230 | if(left != origRect.left())
231 | newRect.setLeft(origRect.left());
232 | else
233 | newRect.setRight(origRect.right());
234 | }
235 | if(minHeight > newRect.height()) {
236 | if(top != origRect.top())
237 | newRect.setTop(origRect.top());
238 | else
239 | newRect.setBottom(origRect.bottom());
240 | }
241 |
242 | if(d->m_bRubberBandOnResize) {
243 | m_pRubberBand->setGeometry(newRect);
244 | } else {
245 | m_pWidget->setGeometry(newRect);
246 | }
247 | }
248 | }
249 |
250 | void WidgetData::moveWidget(const QPoint &gMousePos)
251 | {
252 | if(d->m_bRubberBandOnMove) {
253 | m_pRubberBand->move(gMousePos - m_ptDragPos);
254 | } else {
255 | // 如果全屏时移动窗口,窗口按点击位置还原
256 | if(m_pWidget->isMaximized() || m_pWidget->isFullScreen()) {
257 | if(m_dLeftScale <= 0.3) { }
258 | else if(m_dLeftScale > 0.3 && m_dLeftScale < 0.7) {
259 | m_ptDragPos.setX(m_pWidget->normalGeometry().width() * m_dLeftScale);
260 | } else if(m_dLeftScale >= 0.7) {
261 | m_ptDragPos.setX(m_pWidget->normalGeometry().width() - m_nRightLength);
262 | }
263 |
264 | m_pWidget->setGeometry(0, 0, m_pWidget->normalGeometry().width(), m_pWidget->normalGeometry().height());
265 | }
266 | m_pWidget->move(gMousePos - m_ptDragPos);
267 | }
268 | }
269 |
--------------------------------------------------------------------------------
/libframelesswindow/framelesswindow.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义无边框窗体、对话框和提示框并封装成库
3 | *
4 | * framelesswindow.cpp
5 | * 实现了FramelessWindow、FramlessDialog、FramelessMessageBox
6 | *
7 | */
8 |
9 | #include "framelesswindow.h"
10 | #include "framelesshelper.h"
11 | #include "titlebar.h"
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | FramelessDialog::FramelessDialog(QWidget *parent)
30 | : WidgetShadow(parent)
31 | {
32 |
33 | resize(400, 300);
34 | setObjectName("framelessDialog");
35 | setWindowTitle("FramelessDialog");
36 | // 设置最大和还原按钮不可见
37 | setMinimumVisible(false);
38 | setMaximumVisible(false);
39 | }
40 |
41 | FramelessMessageBox::FramelessMessageBox(QWidget *parent, const QString &title, const QString &text,
42 | QMessageBox::StandardButtons buttons,
43 | QMessageBox::StandardButton defaultButton)
44 | : FramelessDialog(parent)
45 | {
46 | setObjectName("framelessMessagBox");
47 | setMinimumVisible(false);
48 | setMaximumVisible(false);
49 | setWidgetResizable(false);
50 | setWindowTitle(title);
51 | setMinimumSize(300, 150);
52 |
53 | m_pButtonBox = new QDialogButtonBox(this);
54 | m_pButtonBox->setStandardButtons(QDialogButtonBox::StandardButtons(int(buttons)));
55 | setDefaultButton(defaultButton);
56 |
57 | QPushButton *pOkButton = m_pButtonBox->button(QDialogButtonBox::Ok);
58 | if(pOkButton != Q_NULLPTR) {
59 | pOkButton->setObjectName("pOkButton");
60 | }
61 |
62 | QPushButton *pYesButton = m_pButtonBox->button(QDialogButtonBox::Yes);
63 | if(pYesButton != Q_NULLPTR) {
64 | pYesButton->setObjectName("pYesButton");
65 | }
66 |
67 | QPushButton *pNoButton = m_pButtonBox->button(QDialogButtonBox::No);
68 | if(pNoButton != Q_NULLPTR) {
69 | pNoButton->setObjectName("pNoButton");
70 | }
71 |
72 | QPushButton *pCloseButton = m_pButtonBox->button(QDialogButtonBox::Close);
73 | if(pCloseButton != Q_NULLPTR) {
74 | pCloseButton->setObjectName("pCloseButton");
75 | }
76 |
77 | QPushButton *pCancelButton = m_pButtonBox->button(QDialogButtonBox::Cancel);
78 | if(pCancelButton != Q_NULLPTR) {
79 | pCancelButton->setObjectName("pCancelButton");
80 | }
81 |
82 | m_pIconLabel = new QLabel(this);
83 | m_pLabel = new QLabel(this);
84 |
85 | QPixmap pixmap(":/images/msgbox/msg-info-48x48.png");
86 | m_pIconLabel->setPixmap(pixmap);
87 | m_pIconLabel->setFixedSize(35, 35);
88 | m_pIconLabel->setScaledContents(true);
89 | m_pIconLabel->setObjectName("m_pIconLabel");
90 |
91 | m_pLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
92 | m_pLabel->setObjectName("messageTextLabel");
93 | m_pLabel->setOpenExternalLinks(true);
94 | m_pLabel->setText(text);
95 |
96 | m_pGridLayout = new QGridLayout();
97 | m_pGridLayout->addWidget(m_pIconLabel, 0, 0, 2, 1, Qt::AlignTop);
98 | m_pGridLayout->addWidget(m_pLabel, 0, 1, 2, 1);
99 | m_pGridLayout->addWidget(m_pButtonBox, m_pGridLayout->rowCount(), 0, 1, m_pGridLayout->columnCount());
100 | m_pGridLayout->setSizeConstraint(QLayout::SetNoConstraint);
101 | m_pGridLayout->setHorizontalSpacing(10);
102 | m_pGridLayout->setVerticalSpacing(10);
103 | m_pGridLayout->setContentsMargins(10, 10, 10, 10);
104 | m_pFrameLessWindowLayout->addLayout(m_pGridLayout);
105 |
106 | translateUI();
107 |
108 | connect(m_pButtonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(onButtonClicked(QAbstractButton*)));
109 |
110 | // 计算文字宽度
111 | QFont wordfont;
112 | wordfont.setFamily(this->font().defaultFamily());
113 | wordfont.setPointSize(this->font().pointSize());
114 | QFontMetrics fm(wordfont);
115 | QRect rect = fm.boundingRect(text);
116 |
117 | resize(rect.width() + 60, 130);
118 | }
119 |
120 | FramelessMessageBox::~FramelessMessageBox()
121 | {
122 |
123 | }
124 |
125 | QAbstractButton *FramelessMessageBox::clickedButton() const
126 | {
127 | return m_pClickedButton;
128 | }
129 |
130 | QMessageBox::StandardButton FramelessMessageBox::standardButton(QAbstractButton *button) const
131 | {
132 | return (QMessageBox::StandardButton)m_pButtonBox->standardButton(button);
133 | }
134 |
135 | void FramelessMessageBox::setDefaultButton(QPushButton *button)
136 | {
137 | if(!m_pButtonBox->buttons().contains(button))
138 | return;
139 |
140 | m_pDefaultButton = button;
141 | button->setDefault(true);
142 | button->setFocus();
143 | }
144 |
145 | void FramelessMessageBox::setDefaultButton(QMessageBox::StandardButton button)
146 | {
147 | setDefaultButton(m_pButtonBox->button(QDialogButtonBox::StandardButton(button)));
148 | }
149 |
150 | void FramelessMessageBox::setTitle(const QString &title)
151 | {
152 | setWindowTitle(title);
153 | }
154 |
155 | void FramelessMessageBox::setText(const QString &text)
156 | {
157 | m_pLabel->setText(text);
158 | }
159 |
160 | void FramelessMessageBox::setIcon(const QString &icon)
161 | {
162 | m_pIconLabel->setPixmap(QPixmap(icon));
163 | }
164 |
165 | void FramelessMessageBox::hideInfoIcon()
166 | {
167 | //隐藏Icon
168 | m_pIconLabel->setVisible(false);
169 | //重新设置文字位置
170 | m_pGridLayout->addWidget(m_pLabel, 0, 0, 2, 1, Qt::AlignTop);
171 | }
172 |
173 | void FramelessMessageBox::addWidget(QWidget *pWidget)
174 | {
175 | m_pLabel->hide();
176 | m_pGridLayout->addWidget(pWidget, 0, 1, 2, 1);
177 | }
178 |
179 | QMessageBox::StandardButton FramelessMessageBox::showMessageBox(QWidget *parent,
180 | const QString &title,
181 | const QString &text,
182 | QMessageBox::StandardButtons buttons,
183 | IconType messageType,
184 | QMessageBox::StandardButton defaultButton)
185 | {
186 | FramelessMessageBox msgBox(parent, title, text, buttons, defaultButton);
187 | msgBox.hideTitleBarIcon();
188 |
189 | switch(messageType) {
190 | case MSG_NOICON:
191 | msgBox.hideInfoIcon();
192 | break;
193 | case MSG_INFORMATION:
194 | msgBox.setIcon(":/images/msgbox/msg-info-48x48.png");
195 | break;
196 | case MSG_WARNNING:
197 | msgBox.setIcon(":/images/msgbox/msg-warning-48x48.png");
198 | break;
199 | case MSG_QUESTION:
200 | msgBox.setIcon(":/images/msgbox/msg-question-48x48.png");
201 | break;
202 | case MSG_ERROR:
203 | msgBox.setIcon(":/images/msgbox/msg-error-48x48.png");
204 | break;
205 | case MSG_SUCCESS:
206 | msgBox.setIcon(":/images/msgbox/msg-success-48x48.png");
207 | break;
208 | default:
209 | break;
210 | }
211 |
212 | if(msgBox.exec() == -1)
213 | return QMessageBox::Cancel;
214 | return msgBox.standardButton(msgBox.clickedButton());
215 | }
216 |
217 | QMessageBox::StandardButton FramelessMessageBox::showInformation(QWidget *parent,
218 | const QString &title,
219 | const QString &text,
220 | QMessageBox::StandardButtons buttons,
221 | QMessageBox::StandardButton defaultButton)
222 | {
223 | FramelessMessageBox msgBox(parent, title, text, buttons, defaultButton);
224 | msgBox.setIcon(":/images/msgbox/msg-info-48x48.png");
225 | if(msgBox.exec() == -1)
226 | return QMessageBox::Cancel;
227 | return msgBox.standardButton(msgBox.clickedButton());
228 | }
229 |
230 | QMessageBox::StandardButton FramelessMessageBox::showError(QWidget *parent,
231 | const QString &title,
232 | const QString &text,
233 | QMessageBox::StandardButtons buttons,
234 | QMessageBox::StandardButton defaultButton)
235 | {
236 | FramelessMessageBox msgBox(parent, title, text, buttons, defaultButton);
237 | msgBox.setIcon(":/images/msgbox/msg-error-48x48.png");
238 | if(msgBox.exec() == -1)
239 | return QMessageBox::Cancel;
240 | return msgBox.standardButton(msgBox.clickedButton());
241 | }
242 |
243 | QMessageBox::StandardButton FramelessMessageBox::showSuccess(QWidget *parent,
244 | const QString &title,
245 | const QString &text,
246 | QMessageBox::StandardButtons buttons,
247 | QMessageBox::StandardButton defaultButton)
248 | {
249 | FramelessMessageBox msgBox(parent, title, text, buttons, defaultButton);
250 | msgBox.setIcon(":/images/msgbox/msg-success-48x48.png");
251 | if(msgBox.exec() == -1)
252 | return QMessageBox::Cancel;
253 | return msgBox.standardButton(msgBox.clickedButton());
254 | }
255 |
256 | QMessageBox::StandardButton FramelessMessageBox::showQuestion(QWidget *parent,
257 | const QString &title,
258 | const QString &text,
259 | QMessageBox::StandardButtons buttons,
260 | QMessageBox::StandardButton defaultButton)
261 | {
262 | FramelessMessageBox msgBox(parent, title, text, buttons, defaultButton);
263 | msgBox.setIcon(":/images/msgbox/msg-question-48x48.png");
264 | if(msgBox.exec() == -1)
265 | return QMessageBox::Cancel;
266 | return msgBox.standardButton(msgBox.clickedButton());
267 | }
268 |
269 | QMessageBox::StandardButton FramelessMessageBox::showWarning(QWidget *parent,
270 | const QString &title,
271 | const QString &text,
272 | QMessageBox::StandardButtons buttons,
273 | QMessageBox::StandardButton defaultButton)
274 | {
275 | FramelessMessageBox msgBox(parent, title, text, buttons, defaultButton);
276 | msgBox.setIcon(":/images/msgbox/msg-warning-48x48.png");
277 | if(msgBox.exec() == -1)
278 | return QMessageBox::Cancel;
279 | return msgBox.standardButton(msgBox.clickedButton());
280 | }
281 |
282 | QMessageBox::StandardButton FramelessMessageBox::showCritical(QWidget *parent,
283 | const QString &title,
284 | const QString &text,
285 | QMessageBox::StandardButtons buttons,
286 | QMessageBox::StandardButton defaultButton)
287 | {
288 | FramelessMessageBox msgBox(parent, title, text, buttons, defaultButton);
289 | msgBox.setIcon(":/images/msgbox/msg-warning-48x48.png");
290 | if(msgBox.exec() == -1)
291 | return QMessageBox::Cancel;
292 | return msgBox.standardButton(msgBox.clickedButton());
293 | }
294 |
295 | QMessageBox::StandardButton FramelessMessageBox::showCheckBoxQuestion(QWidget *parent,
296 | const QString &title,
297 | const QString &text,
298 | QMessageBox::StandardButtons buttons,
299 | QMessageBox::StandardButton defaultButton)
300 | {
301 | FramelessMessageBox msgBox(parent, title, text, buttons, defaultButton);
302 | msgBox.setIcon(":/images/msgbox/msg-question-48x48.png");
303 |
304 | QCheckBox *pCheckBox = new QCheckBox(&msgBox);
305 | pCheckBox->setText(text);
306 | msgBox.addWidget(pCheckBox);
307 | if(msgBox.exec() == -1)
308 | return QMessageBox::Cancel;
309 |
310 | QMessageBox::StandardButton standardButton = msgBox.standardButton(msgBox.clickedButton());
311 | if(standardButton == QMessageBox::Yes) {
312 | return pCheckBox->isChecked() ? QMessageBox::Yes : QMessageBox::No;
313 | }
314 | return QMessageBox::Cancel;
315 | }
316 |
317 | void FramelessMessageBox::changeEvent(QEvent *event)
318 | {
319 | switch(event->type()) {
320 | case QEvent::LanguageChange:
321 | translateUI();
322 | break;
323 |
324 | default:
325 | FramelessDialog::changeEvent(event);
326 | }
327 | }
328 |
329 | void FramelessMessageBox::onButtonClicked(QAbstractButton *button)
330 | {
331 | m_pClickedButton = button;
332 | done(execReturnCode(button));
333 | }
334 |
335 | void FramelessMessageBox::translateUI()
336 | {
337 | QPushButton *pYesButton = m_pButtonBox->button(QDialogButtonBox::Yes);
338 | if(pYesButton != NULL)
339 | pYesButton->setText(tr("Yes"));
340 |
341 | QPushButton *pNoButton = m_pButtonBox->button(QDialogButtonBox::No);
342 | if(pNoButton != NULL)
343 | pNoButton->setText(tr("No"));
344 |
345 | QPushButton *pOkButton = m_pButtonBox->button(QDialogButtonBox::Ok);
346 | if(pOkButton != NULL)
347 | pOkButton->setText(tr("Ok"));
348 |
349 | QPushButton *pCancelButton = m_pButtonBox->button(QDialogButtonBox::Cancel);
350 | if(pCancelButton != NULL)
351 | pCancelButton->setText(tr("Cancel"));
352 | }
353 |
354 | int FramelessMessageBox::execReturnCode(QAbstractButton *button)
355 | {
356 | int nResult = m_pButtonBox->standardButton(button);
357 | return nResult;
358 | }
359 |
--------------------------------------------------------------------------------
/libframelesswindow/widgetshadow.h:
--------------------------------------------------------------------------------
1 | /**
2 | * 自定义窗口阴影
3 | *
4 | * widgetshadow.h
5 | *
6 | */
7 |
8 | #ifndef WIDGETSHADOW_H
9 | #define WIDGETSHADOW_H
10 |
11 | #include "framelesswindow_global.h"
12 | #include "borderimage.h"
13 | #include "framelesshelper.h"
14 | #include "titlebar.h"
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 |
25 | template
26 | class WidgetShadow : public T
27 | {
28 | public:
29 | typedef typename WidgetShadow BaseClass;
30 |
31 | WidgetShadow(QWidget *parent = nullptr)
32 | :T(parent)
33 | , m_pHelper(Q_NULLPTR)
34 | , m_pTitleBar(Q_NULLPTR)
35 | , m_pMainWindow(Q_NULLPTR)
36 | , m_pMainLayout(Q_NULLPTR)
37 | , m_pFrameLessWindowLayout(Q_NULLPTR)
38 | , m_pCentralWdiget(new QWidget(this))
39 | , m_clientDrawType(kTopLeftToBottomRight)
40 | , m_redrawPixmap(true)
41 | , m_drawedPixmap(Q_NULLPTR)
42 | {
43 |
44 | resize(800, 600);
45 | setWindowTitle("FramelessWindow");
46 |
47 | //设置默认背景色为白色
48 | setClientColor(QColor(255, 255, 255));
49 | //设置默认阴影边框
50 | m_borderImage.load(":/images/background/client-shadow.png", "8 8 8 8", "8 8 8 8");
51 |
52 | m_pMainWindow = new QWidget(this);
53 | m_pMainWindow->setObjectName("framelessWindow");
54 | m_pMainLayout = new QVBoxLayout(this);
55 | m_pMainLayout->addWidget(m_pMainWindow);
56 | m_pMainLayout->setContentsMargins(m_borderImage.margin());
57 |
58 | setWindowFlags(Qt::FramelessWindowHint | windowFlags());
59 | setAttribute(Qt::WA_TranslucentBackground);
60 |
61 | m_pTitleBar = new TitleBar(this);
62 | installEventFilter(m_pTitleBar);//标题栏不注册事件,注册本窗口把事件转发到标题栏
63 | setTitleHeight(m_pTitleBar->height());
64 |
65 | m_pFrameLessWindowLayout = new QVBoxLayout(m_pMainWindow);
66 | m_pFrameLessWindowLayout->addWidget(m_pTitleBar);
67 | m_pFrameLessWindowLayout->addWidget(m_pCentralWdiget, 1);
68 | m_pFrameLessWindowLayout->setSpacing(0);
69 | m_pFrameLessWindowLayout->setContentsMargins(0, 0, 0, 0);
70 |
71 | m_pHelper = new FramelessHelper(this);
72 | m_pHelper->activateOn(this); //激活当前窗体
73 |
74 | //设置边框宽度
75 | m_pHelper->setBorderWidth((m_borderImage.margin().top()+m_borderImage.margin().left()+m_borderImage.margin().right()+m_borderImage.margin().bottom())/4);
76 |
77 | setWidgetMovalbe();
78 | setWidgetResizable();
79 | setRubberBandOnMove(false);
80 | setRubberBandOnResize(false);
81 | }
82 |
83 | ~WidgetShadow()
84 | {
85 | qDeleteAll(m_alphaCache);
86 | m_alphaCache.clear();
87 |
88 | if(m_drawedPixmap) {
89 | delete m_drawedPixmap;
90 | m_drawedPixmap = NULL;
91 | }
92 | }
93 |
94 | enum ClientDrawType {
95 | kTopLeftToBottomRight = 1, //左下到右下
96 | kTopRightToBottomLeft //右上到左下
97 | };
98 |
99 | /**
100 | * @brief setStyleSheetFile
101 | * @note 设置QSS样式文件
102 | * @param file
103 | */
104 | void setStyleSheetFile(const QString &file)
105 | {
106 | QFile qss(file);
107 | qss.open(QFile::ReadOnly);
108 | this->setStyleSheet(qss.readAll());
109 | qss.close();
110 | }
111 |
112 | /**
113 | * @brief setTitleHeight
114 | * @note 设置标题栏高度,如果设置了窗口可移动,拖动标题栏可以移动窗体
115 | * @param h
116 | * @note 标题栏的高度,默认是25
117 | */
118 | void setTitleHeight(int h = 25)
119 | {
120 | m_pHelper->setTitleHeight(h);
121 | }
122 |
123 | /**
124 | * @brief setWidgetMovalbe
125 | * @note 设置窗口是否可移动,默认可移动
126 | * @param movable
127 | */
128 | void setWidgetMovalbe(bool movable = true)
129 | {
130 | m_pHelper->setWidgetMovable(movable);
131 | }
132 |
133 | /**
134 | * @brief setWidgetResizable
135 | * @note 设置窗口是否可缩放,默认是可以进行缩放
136 | * @param resizable
137 | */
138 | void setWidgetResizable(bool resizable = true)
139 | {
140 | m_pHelper->setWidgetResizable(resizable);
141 | }
142 |
143 | /**
144 | * @brief setMinimumVisible
145 | * @note 设置窗口标题栏最小化按钮是否可见
146 | * @param vislble
147 | */
148 | void setMinimumVisible(bool vislble = true)
149 | {
150 | m_pTitleBar->setMinimumVisible(vislble);
151 | }
152 |
153 | /**
154 | * @brief setMaximumVisible
155 | * @note 设置窗口标题栏最大化或还原按钮是否可见
156 | * @param visible
157 | */
158 | void setMaximumVisible(bool visible = true)
159 | {
160 | m_pTitleBar->setMaximumVisible(visible);
161 | }
162 |
163 | /**
164 | * @brief setRubberBandOnMove
165 | * @note 设置窗口缩放时橡皮筋是否可移动,默认是可移动
166 | * @param rubber
167 | */
168 | void setRubberBandOnMove(bool move = true)
169 | {
170 | m_pHelper->setRubberBandOnMove(move);
171 | }
172 |
173 | /**
174 | * @brief setRubberBandOnResize
175 | * @note 设置窗口缩放时橡皮筋是否可缩放,默认可缩放
176 | * @param resize
177 | */
178 | void setRubberBandOnResize(bool resize = true)
179 | {
180 | m_pHelper->setRubberBandOnResize(resize);
181 | }
182 |
183 | /**
184 | * @brief setCentralWidget
185 | * @note 设置中心界面
186 | * @param w
187 | * QWidget *
188 | */
189 | void setCentralWidget(QWidget *w)
190 | {
191 | m_pCentralWdiget->deleteLater();
192 | m_pCentralWdiget = w;
193 | m_pFrameLessWindowLayout->addWidget(w, 1);
194 | }
195 |
196 |
197 | /**
198 | * @brief setBorderImage
199 | * @param image
200 | * @note 设置边框图片或阴影
201 | */
202 | void setBorderImage(const QString &image, const QMargins& border = {8,8,8,8}, const QMargins& margin = {6,6,6,6})
203 | {
204 | m_borderImage.setPixmap(image);
205 | m_borderImage.setBorder(border);
206 | m_borderImage.setMargin(margin);
207 | update();
208 | }
209 |
210 | /**
211 | * @brief setClientImage
212 | * @param file
213 | * @note 设置窗口背景片
214 | */
215 | void setClientImage(const QString &image)
216 | {
217 | m_clientPixmap.load(image);
218 | update();
219 | }
220 |
221 | /**
222 | * @brief setClientColor
223 | * @param color
224 | * @note 设置背景颜色
225 | */
226 | void setClientColor(const QColor &color)
227 | {
228 | //画一个1*1大小的纯色图片
229 | QPixmap pixmap(1,1); //作为绘图设备
230 | QPainter painter(&pixmap); //创建一直画笔
231 | painter.fillRect(0,0,1,1, color);
232 | m_clientPixmap = pixmap;
233 |
234 | update();
235 | }
236 |
237 | /**
238 | * @brief clientDrawType
239 | * @note 客户区背景绘制方式
240 | * @return
241 | */
242 | inline ClientDrawType clientDrawType() const
243 | {
244 | return m_clientDrawType;
245 | }
246 | void setClientDrawType(ClientDrawType type)
247 | {
248 | m_clientDrawType = type;
249 | }
250 |
251 | /**
252 | * @brief hideTitleBar
253 | * @note 不显示标题栏
254 | */
255 | void hideTitleBar()
256 | {
257 | m_pFrameLessWindowLayout->removeWidget(m_pTitleBar);
258 | m_pTitleBar->deleteLater();
259 | m_pTitleBar = Q_NULLPTR;
260 | }
261 |
262 | /**
263 | * @brief hideTitleBarIcon
264 | * @note 隐藏标题栏icon
265 | */
266 | void hideTitleBarIcon()
267 | {
268 | m_pTitleBar->hideTitleIcon();
269 | }
270 |
271 | /**
272 | * @brief 除去边框后的客户区rect
273 | * @return
274 | */
275 | QRect clientRect() const
276 | {
277 | QRect clientRect(rect());
278 | if(!isMaximized()) {
279 | const QMargins& m = m_borderImage.margin();
280 | clientRect.adjust(m.left(), m.top(), -m.right(), -m.bottom());
281 | }
282 |
283 | return clientRect;
284 | }
285 |
286 | /**
287 | * @brief 画背景图, 左上角画原始图,右下角拉伸
288 | * @param painter
289 | * @param rect
290 | * @param img
291 | */
292 | void drawTopLeft(QPainter *painter, const QRect& rect, const QPixmap& pixmap)
293 | {
294 | //图片比要画的区域大,剪辑
295 | int width = qMin(pixmap.width(), rect.width());
296 | int height = qMin(pixmap.height(), rect.height());
297 |
298 | painter->drawPixmap(rect.left(), rect.top(), pixmap, 0, 0, width, height);
299 |
300 | //图片宽度比要画的区域小,拉伸宽度
301 | if(width < rect.width()) {
302 | QRect dst(rect.left() + width, rect.top(), rect.width() - width, height/*r.height()*/);
303 | QRect src(width - 1, 0, 1, height);
304 | painter->drawPixmap(dst, pixmap, src);
305 | }
306 |
307 | //图片高度比要画的区域小,拉伸高度
308 | if(height < rect.height()) {
309 | QRect dst(rect.left(), rect.top() + height, width/*r.width()*/, rect.height() - height);
310 | QRect src(0, height - 1, width, 1);
311 | painter->drawPixmap(dst, pixmap, src);
312 | }
313 |
314 | //图片高度、宽度都比要画的区域小,拉伸最右下角
315 | if(width < rect.width() && height < rect.height()) {
316 | QRect dst(rect.left() + width, rect.top() + height, rect.width() - width, rect.height() - height);
317 | QRect src(width - 1, height - 1, 1, 1); //用最后一个点拉伸
318 | painter->drawPixmap(dst, pixmap, src);
319 | }
320 | }
321 |
322 | /**
323 | * @brief 画背景图, 右上角画原始图,左下角拉伸
324 | * @param painter
325 | * @param rect
326 | * @param img
327 | */
328 | void drawTopRight(QPainter *painter, const QRect& rect, const QPixmap& pixmap)
329 | {
330 | int width = qMin(pixmap.width(), rect.width());
331 | int height = qMin(rect.height(), pixmap.height());
332 |
333 | //左上, 图的左边往左拉伸
334 | if(rect.width() > pixmap.width()) {
335 | QRect src(0, 0, 1, height);
336 |
337 | QRect dst(rect.left(), rect.top(), rect.width() - pixmap.width(), height);
338 | painter->drawPixmap(dst, pixmap, src);
339 | }
340 |
341 | //右上()
342 | {
343 | QRect src(pixmap.width() - width, 0, width, height);
344 | QRect dst(rect.left() + rect.width() - width, rect.top(), width, height);
345 | painter->drawPixmap(dst, pixmap, src);
346 | }
347 |
348 | //左下(拉伸)
349 | if(rect.width() > pixmap.width() && rect.height() > pixmap.height()) {
350 | QRect src(0, height - 1, 1, 1);
351 | QRect dst(0, height, rect.width() - pixmap.width(), rect.height() - pixmap.height());
352 | painter->drawPixmap(dst, pixmap, src);
353 | }
354 |
355 | //右下(拉伸), 图的下边往下拉伸
356 | if(rect.height() > pixmap.height()) {
357 | QRect src(pixmap.width() - width, height - 1, width, 1);
358 | QRect dst(rect.left() + rect.width() - width, height, width, rect.height() - pixmap.height());
359 | painter->drawPixmap(dst, pixmap, src);
360 | }
361 | }
362 |
363 | protected:
364 | virtual void resizeEvent(QResizeEvent *event)
365 | {
366 | if(event->size() == event->oldSize()) {
367 | return;
368 | }
369 |
370 | m_redrawPixmap = true;
371 |
372 | //判断是否最大化
373 | //这里没有使用 isMaximized因为有时候不准确
374 | if(QApplication::desktop()->availableGeometry().width() == geometry().width() && \
375 | QApplication::desktop()->availableGeometry().height() == geometry().height()) {
376 | //无圆角,并禁止改变窗口大小
377 | this->clearMask();
378 | //最大化后,无边框无边距
379 | m_pMainLayout->setContentsMargins(0, 0, 0, 0);
380 | return;
381 |
382 | } else {
383 | //恢复窗口的边框边距
384 | if(m_pMainLayout->contentsMargins().isNull()) {
385 | m_pMainLayout->setContentsMargins(m_borderImage.margin());
386 | }
387 | }
388 |
389 | #if 1
390 | //圆角窗口
391 | QBitmap pixmap(event->size()); //生成一张位图
392 | QPainter painter(&pixmap); //QPainter用于在位图上绘画
393 | // 圆角平滑
394 | painter.setRenderHints(QPainter::Antialiasing, true);
395 |
396 | //填充位图矩形框(用白色填充)
397 | QRect r = this->rect();
398 | painter.fillRect(r, Qt::color0);
399 | painter.setBrush(Qt::color1);
400 | //在位图上画圆角矩形(用黑色填充)
401 | painter.drawRoundedRect(r, 0, 0);
402 | painter.end();
403 |
404 | //使用setmask过滤即可
405 | setMask(pixmap);
406 | #endif
407 | }
408 |
409 | virtual void paintEvent(QPaintEvent *event)
410 | {
411 | if(m_redrawPixmap || !m_drawedPixmap) {
412 | m_redrawPixmap = false;
413 | qDeleteAll(m_alphaCache);
414 | m_alphaCache.clear();
415 |
416 | QRect rect = this->rect();
417 |
418 | delete m_drawedPixmap; //it's safe to delete null
419 | m_drawedPixmap = new QPixmap(rect.width(), rect.height());
420 | m_drawedPixmap->fill(Qt::transparent);//Qt::black
421 |
422 | QPainter painter(m_drawedPixmap);
423 | painter.setRenderHint(QPainter::Antialiasing, true);
424 |
425 | //边框背景图
426 | const QMargins &m = m_borderImage.border();
427 | if(isMaximized()) { //最大化后,无边框
428 | //考虑只有一个borderimage作为背景的情况,这种情况最大化后就需要用borderimage去掉边框后作为背景图
429 | //把rect放大正好使边框看不见.
430 | rect.adjust(-m.left(), -m.top(), m.right(), m.bottom());
431 | }
432 | qDrawBorderPixmap(&painter, rect, m, m_borderImage.pixmap());
433 |
434 | //客户区图
435 | const QPixmap& bmp = m_clientPixmap;
436 | if(!bmp.isNull()) {
437 |
438 | rect = clientRect();
439 |
440 | QPixmap pixmap(rect.size());
441 | {
442 | QPainter p(&pixmap);
443 | //1-从左上固定,右下拉伸;2-右上固定,左下拉伸
444 | switch(clientDrawType()) {
445 | case kTopLeftToBottomRight:
446 | drawTopLeft(&p, pixmap.rect(), bmp);
447 | break;
448 | case kTopRightToBottomLeft:
449 | drawTopRight(&p, pixmap.rect(), bmp);
450 | break;
451 | default:
452 | p.drawPixmap(pixmap.rect(), bmp);
453 | break;
454 | }
455 | }
456 |
457 | painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);//CompositionMode_DestinationAtop,CompositionMode_SoftLight,CompositionMode_Multiply
458 | painter.drawPixmap(rect.left(), rect.top(), pixmap);
459 | }
460 | }
461 |
462 | QPainter painter(this);
463 | painter.drawPixmap(0, 0, *m_drawedPixmap);
464 | }
465 |
466 | protected:
467 | FramelessHelper *m_pHelper;
468 | TitleBar *m_pTitleBar;
469 | QWidget *m_pMainWindow;
470 | QVBoxLayout *m_pMainLayout;
471 | QVBoxLayout *m_pFrameLessWindowLayout;
472 | QWidget *m_pCentralWdiget;
473 | bool m_redrawPixmap; //是否需要重新创建客户区图像
474 | QPixmap *m_drawedPixmap; //画好的背景图像
475 | QHash m_alphaCache; //保存子控件alpha透明后的背景图
476 | QPixmap m_clientPixmap; //背景图片
477 | ClientDrawType m_clientDrawType; //背景图片绘制方式
478 | BorderImage m_borderImage; //阴影边框
479 | };
480 |
481 | #endif // WIDGETSHADOW_H
482 |
--------------------------------------------------------------------------------