├── .gitignore ├── Example ├── Image │ ├── max_gray.png │ ├── min_gray.png │ ├── set_gray.png │ ├── up_blue.png │ ├── up_white.png │ ├── check_blue.png │ ├── check_green.png │ ├── check_white.png │ ├── close_gray.png │ ├── close_red.png │ ├── down_blue.png │ ├── down_orange.png │ ├── down_white.png │ ├── left_blue.png │ ├── left_orange.png │ ├── left_white.png │ ├── max_orange.png │ ├── min_orange.png │ ├── normal_gray.png │ ├── right_blue.png │ ├── right_white.png │ ├── set_orange.png │ ├── up_orange.png │ ├── upmax_blue.png │ ├── upmax_white.png │ ├── check_orange.png │ ├── checked_blue.png │ ├── checked_green.png │ ├── checked_white.png │ ├── downmax_blue.png │ ├── downmax_white.png │ ├── leftmax_blue.png │ ├── leftmax_green.png │ ├── leftmax_white.png │ ├── leftmin_blue.png │ ├── leftmin_green.png │ ├── leftmin_white.png │ ├── normal_orange.png │ ├── right_orange.png │ ├── rightmax_blue.png │ ├── rightmin_blue.png │ ├── upmax_orange.png │ ├── checked_orange.png │ ├── downmax_orange.png │ ├── leftmax_orange.png │ ├── leftmin_orange.png │ ├── rightmax_green.png │ ├── rightmax_orange.png │ ├── rightmax_white.png │ ├── rightmin_green.png │ ├── rightmin_orange.png │ └── rightmin_white.png ├── MainWindow.cpp ├── MainWindow.h ├── PopupDemo.h ├── ToolTipDemo.h ├── main.cpp ├── example.pro ├── PopupDemo.cpp ├── img.qrc ├── ToolTipDemo.cpp ├── PopupDemo.ui ├── MainWindow.ui └── ToolTipDemo.ui ├── CuteComponent ├── CuteComponent.cpp ├── CuteComponent.h ├── CuteComponentExport.h ├── ToolTip │ ├── ToolTip.pri │ ├── CuteDesktopTipForm.cpp │ ├── CuteDesktopTipForm.h │ ├── CuteToolTip.h │ ├── CuteDesktopTip.h │ ├── CuteDesktopTipForm.ui │ ├── CuteToolTip.cpp │ └── CuteDesktopTip.cpp ├── Popup │ ├── Popup.pri │ ├── CuteBasicComboModel.h │ ├── CuteBasicComboModel.cpp │ ├── CuteBasicComboPopup.h │ ├── CuteBasicComboContainer.h │ ├── CuteBasicComboView.h │ ├── CuteBasicComboBox.h │ ├── CuteBasicComboContainer.cpp │ ├── CuteBasicComboPopup.cpp │ ├── CuteBasicComboView.cpp │ └── CuteBasicComboBox.cpp └── CuteComponent.pro ├── QtWidgetsComponent.pro ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /build 3 | 4 | .git 5 | .vs 6 | .vscode 7 | .DS_Store 8 | 9 | *.user 10 | -------------------------------------------------------------------------------- /Example/Image/max_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/max_gray.png -------------------------------------------------------------------------------- /Example/Image/min_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/min_gray.png -------------------------------------------------------------------------------- /Example/Image/set_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/set_gray.png -------------------------------------------------------------------------------- /Example/Image/up_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/up_blue.png -------------------------------------------------------------------------------- /Example/Image/up_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/up_white.png -------------------------------------------------------------------------------- /Example/Image/check_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/check_blue.png -------------------------------------------------------------------------------- /Example/Image/check_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/check_green.png -------------------------------------------------------------------------------- /Example/Image/check_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/check_white.png -------------------------------------------------------------------------------- /Example/Image/close_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/close_gray.png -------------------------------------------------------------------------------- /Example/Image/close_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/close_red.png -------------------------------------------------------------------------------- /Example/Image/down_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/down_blue.png -------------------------------------------------------------------------------- /Example/Image/down_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/down_orange.png -------------------------------------------------------------------------------- /Example/Image/down_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/down_white.png -------------------------------------------------------------------------------- /Example/Image/left_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/left_blue.png -------------------------------------------------------------------------------- /Example/Image/left_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/left_orange.png -------------------------------------------------------------------------------- /Example/Image/left_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/left_white.png -------------------------------------------------------------------------------- /Example/Image/max_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/max_orange.png -------------------------------------------------------------------------------- /Example/Image/min_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/min_orange.png -------------------------------------------------------------------------------- /Example/Image/normal_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/normal_gray.png -------------------------------------------------------------------------------- /Example/Image/right_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/right_blue.png -------------------------------------------------------------------------------- /Example/Image/right_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/right_white.png -------------------------------------------------------------------------------- /Example/Image/set_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/set_orange.png -------------------------------------------------------------------------------- /Example/Image/up_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/up_orange.png -------------------------------------------------------------------------------- /Example/Image/upmax_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/upmax_blue.png -------------------------------------------------------------------------------- /Example/Image/upmax_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/upmax_white.png -------------------------------------------------------------------------------- /Example/Image/check_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/check_orange.png -------------------------------------------------------------------------------- /Example/Image/checked_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/checked_blue.png -------------------------------------------------------------------------------- /Example/Image/checked_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/checked_green.png -------------------------------------------------------------------------------- /Example/Image/checked_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/checked_white.png -------------------------------------------------------------------------------- /Example/Image/downmax_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/downmax_blue.png -------------------------------------------------------------------------------- /Example/Image/downmax_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/downmax_white.png -------------------------------------------------------------------------------- /Example/Image/leftmax_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/leftmax_blue.png -------------------------------------------------------------------------------- /Example/Image/leftmax_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/leftmax_green.png -------------------------------------------------------------------------------- /Example/Image/leftmax_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/leftmax_white.png -------------------------------------------------------------------------------- /Example/Image/leftmin_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/leftmin_blue.png -------------------------------------------------------------------------------- /Example/Image/leftmin_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/leftmin_green.png -------------------------------------------------------------------------------- /Example/Image/leftmin_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/leftmin_white.png -------------------------------------------------------------------------------- /Example/Image/normal_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/normal_orange.png -------------------------------------------------------------------------------- /Example/Image/right_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/right_orange.png -------------------------------------------------------------------------------- /Example/Image/rightmax_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/rightmax_blue.png -------------------------------------------------------------------------------- /Example/Image/rightmin_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/rightmin_blue.png -------------------------------------------------------------------------------- /Example/Image/upmax_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/upmax_orange.png -------------------------------------------------------------------------------- /Example/Image/checked_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/checked_orange.png -------------------------------------------------------------------------------- /Example/Image/downmax_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/downmax_orange.png -------------------------------------------------------------------------------- /Example/Image/leftmax_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/leftmax_orange.png -------------------------------------------------------------------------------- /Example/Image/leftmin_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/leftmin_orange.png -------------------------------------------------------------------------------- /Example/Image/rightmax_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/rightmax_green.png -------------------------------------------------------------------------------- /Example/Image/rightmax_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/rightmax_orange.png -------------------------------------------------------------------------------- /Example/Image/rightmax_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/rightmax_white.png -------------------------------------------------------------------------------- /Example/Image/rightmin_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/rightmin_green.png -------------------------------------------------------------------------------- /Example/Image/rightmin_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/rightmin_orange.png -------------------------------------------------------------------------------- /Example/Image/rightmin_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gongjianbo/QtWidgetsComponent/HEAD/Example/Image/rightmin_white.png -------------------------------------------------------------------------------- /CuteComponent/CuteComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "CuteComponent.h" 2 | #include 3 | 4 | void CuteComponent::hello() 5 | { 6 | qDebug() << __FUNCTION__; 7 | } 8 | -------------------------------------------------------------------------------- /QtWidgetsComponent.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | CONFIG += ordered 3 | 4 | SUBDIRS += CuteComponent 5 | SUBDIRS += Example 6 | 7 | Example.depends += CuteComponent 8 | -------------------------------------------------------------------------------- /CuteComponent/CuteComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CuteComponentExport.h" 4 | 5 | class Cute_API CuteComponent 6 | { 7 | public: 8 | static void hello(); 9 | }; 10 | -------------------------------------------------------------------------------- /CuteComponent/CuteComponentExport.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifdef CuteComponent_Library 5 | #define Cute_API Q_DECL_EXPORT 6 | #else 7 | #define Cute_API Q_DECL_IMPORT 8 | #endif 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QtWidgets Component 2 | 3 | QtWidgets custom components. QtWidgets 自定义组件 4 | 5 | # Development Environment 6 | 7 | Windows10/11 + MSVC2019/2022 + Qt5.15.2/Qt6.x 8 | 9 | # Component List 10 | 11 | ## ToolTip 12 | 13 | - CuteToolTip:鼠标放上去时显示的提示信息 14 | - CuteDesktopTip:带关闭按钮的提示框 15 | -------------------------------------------------------------------------------- /CuteComponent/ToolTip/ToolTip.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/CuteDesktopTip.h \ 3 | $$PWD/CuteDesktopTipForm.h \ 4 | $$PWD/CuteToolTip.h 5 | 6 | SOURCES += \ 7 | $$PWD/CuteDesktopTip.cpp \ 8 | $$PWD/CuteDesktopTipForm.cpp \ 9 | $$PWD/CuteToolTip.cpp 10 | 11 | FORMS += \ 12 | $$PWD/CuteDesktopTipForm.ui 13 | -------------------------------------------------------------------------------- /Example/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include "ui_MainWindow.h" 3 | #include 4 | 5 | MainWindow::MainWindow(QWidget *parent) 6 | : QMainWindow{parent} 7 | , ui{new Ui::MainWindow} 8 | { 9 | ui->setupUi(this); 10 | } 11 | 12 | MainWindow::~MainWindow() 13 | { 14 | delete ui; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /Example/MainWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | QT_BEGIN_NAMESPACE 5 | namespace Ui { class MainWindow; } 6 | QT_END_NAMESPACE 7 | 8 | class MainWindow : public QMainWindow 9 | { 10 | Q_OBJECT 11 | public: 12 | MainWindow(QWidget *parent = nullptr); 13 | ~MainWindow(); 14 | 15 | private: 16 | Ui::MainWindow *ui; 17 | }; 18 | -------------------------------------------------------------------------------- /Example/PopupDemo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Ui { 5 | class PopupDemo; 6 | } 7 | 8 | class PopupDemo : public QWidget 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit PopupDemo(QWidget *parent = nullptr); 13 | ~PopupDemo(); 14 | 15 | private: 16 | void initComboBox(); 17 | 18 | private: 19 | Ui::PopupDemo *ui; 20 | }; 21 | -------------------------------------------------------------------------------- /CuteComponent/ToolTip/CuteDesktopTipForm.cpp: -------------------------------------------------------------------------------- 1 | #include "CuteDesktopTipForm.h" 2 | #include "ui_CuteDesktopTipForm.h" 3 | #include 4 | 5 | CuteDesktopTipForm::CuteDesktopTipForm(QWidget *parent) 6 | : QWidget{parent} 7 | , ui{new Ui::CuteDesktopTipForm} 8 | { 9 | ui->setupUi(this); 10 | } 11 | 12 | CuteDesktopTipForm::~CuteDesktopTipForm() 13 | { 14 | delete ui; 15 | } 16 | -------------------------------------------------------------------------------- /Example/ToolTipDemo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Ui { 5 | class ToolTipDemo; 6 | } 7 | 8 | class ToolTipDemo : public QWidget 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit ToolTipDemo(QWidget *parent = nullptr); 13 | ~ToolTipDemo(); 14 | 15 | private: 16 | void initToolTip(); 17 | void initDesktopTip(); 18 | 19 | private: 20 | Ui::ToolTipDemo *ui; 21 | }; 22 | -------------------------------------------------------------------------------- /Example/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CuteComponent.h" 3 | #include "MainWindow.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 8 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 9 | #endif 10 | 11 | QApplication app(argc, argv); 12 | 13 | CuteComponent::hello(); 14 | MainWindow window; 15 | window.show(); 16 | 17 | return app.exec(); 18 | } 19 | -------------------------------------------------------------------------------- /CuteComponent/Popup/Popup.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/CuteBasicComboBox.h \ 3 | $$PWD/CuteBasicComboContainer.h \ 4 | $$PWD/CuteBasicComboModel.h \ 5 | $$PWD/CuteBasicComboPopup.h \ 6 | $$PWD/CuteBasicComboView.h 7 | 8 | SOURCES += \ 9 | $$PWD/CuteBasicComboBox.cpp \ 10 | $$PWD/CuteBasicComboContainer.cpp \ 11 | $$PWD/CuteBasicComboModel.cpp \ 12 | $$PWD/CuteBasicComboPopup.cpp \ 13 | $$PWD/CuteBasicComboView.cpp 14 | 15 | -------------------------------------------------------------------------------- /CuteComponent/CuteComponent.pro: -------------------------------------------------------------------------------- 1 | QT += core 2 | QT += gui 3 | QT += widgets 4 | 5 | CONFIG += c++17 6 | CONFIG += utf8_source 7 | 8 | DEFINES += QT_DEPRECATED_WARNINGS 9 | # disables all the APIs deprecated before Qt 6.0.0 10 | DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 11 | 12 | TEMPLATE = lib 13 | TARGET = CuteComponent 14 | DESTDIR = $$PWD/../bin 15 | DEFINES += CuteComponent_Library 16 | 17 | HEADERS += \ 18 | CuteComponent.h \ 19 | CuteComponentExport.h 20 | 21 | SOURCES += \ 22 | CuteComponent.cpp 23 | 24 | include($$PWD/ToolTip/ToolTip.pri) 25 | INCLUDEPATH += $$PWD/ToolTip 26 | 27 | include($$PWD/Popup/Popup.pri) 28 | INCLUDEPATH += $$PWD/Popup 29 | -------------------------------------------------------------------------------- /CuteComponent/ToolTip/CuteDesktopTipForm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace Ui { 7 | class CuteDesktopTipForm; 8 | } 9 | 10 | /** 11 | * @brief CuteDesktopTip 的默认窗口界面 12 | * @author 龚建波 13 | * @date 2023-08-27 14 | * @note 15 | * 样式设置放在了 ui 中 16 | * @details 17 | * 将 CuteDesktopTip 的逻辑和界面拆开 18 | * 内部包含一组小部件,外部可通过 objectName 查找 19 | * icon: QLabel 20 | * title: QLabel 21 | * close: QPushButton 22 | * contet: QLabel 23 | * 如果要把 Form 做成可替换的,也可以用 objectName 或者增加一个接口类 24 | */ 25 | class CuteDesktopTipForm : public QWidget 26 | { 27 | Q_OBJECT 28 | public: 29 | explicit CuteDesktopTipForm(QWidget *parent = nullptr); 30 | ~CuteDesktopTipForm(); 31 | 32 | private: 33 | Ui::CuteDesktopTipForm *ui; 34 | }; 35 | -------------------------------------------------------------------------------- /Example/example.pro: -------------------------------------------------------------------------------- 1 | QT += core 2 | QT += gui 3 | QT += widgets 4 | 5 | CONFIG += c++17 6 | CONFIG += utf8_source 7 | 8 | DEFINES += QT_DEPRECATED_WARNINGS 9 | # disables all the APIs deprecated before Qt 6.0.0 10 | DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 11 | 12 | TEMPLATE = app 13 | TARGET = ComponentExample 14 | DESTDIR = $$PWD/../bin 15 | 16 | SOURCES += \ 17 | $$PWD/main.cpp \ 18 | $$PWD/MainWindow.cpp \ 19 | PopupDemo.cpp \ 20 | ToolTipDemo.cpp 21 | 22 | HEADERS += \ 23 | $$PWD/MainWindow.h \ 24 | PopupDemo.h \ 25 | ToolTipDemo.h 26 | 27 | FORMS += \ 28 | $$PWD/MainWindow.ui \ 29 | PopupDemo.ui \ 30 | ToolTipDemo.ui 31 | 32 | unix|win32: LIBS += -L$$PWD/../bin -lCuteComponent 33 | INCLUDEPATH += $$PWD/../CuteComponent 34 | DEPENDPATH += $$PWD/../CuteComponent 35 | 36 | RESOURCES += \ 37 | img.qrc 38 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboModel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CuteComponentExport.h" 4 | 5 | /** 6 | * @brief BasicComboBox 默认弹框的 model 7 | * @author 龚建波 8 | * @date 2020-7-6 9 | */ 10 | class Cute_API CuteBasicComboModel : public QAbstractListModel 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit CuteBasicComboModel(QObject *parent = nullptr); 16 | 17 | // item 个数 18 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 19 | // item 数据获取 20 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 21 | 22 | // 自定义接口 23 | // 对应自己的数据类型,普通的下拉框文本足矣 24 | QList getModelData() const; 25 | void setModelData(const QList &datas); 26 | // 查到内容对应行 27 | int getDataRow(const QString &text); 28 | 29 | private: 30 | // 对应自己的数据类型,普通的下拉框文本足矣 31 | QList modelData; 32 | }; 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 龚建波 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboModel.cpp: -------------------------------------------------------------------------------- 1 | #include "CuteBasicComboModel.h" 2 | 3 | CuteBasicComboModel::CuteBasicComboModel(QObject *parent) 4 | : QAbstractListModel{parent} 5 | { 6 | } 7 | 8 | int CuteBasicComboModel::rowCount(const QModelIndex &parent) const 9 | { 10 | if (parent.isValid()) 11 | return 0; 12 | 13 | return modelData.count(); 14 | } 15 | 16 | QVariant CuteBasicComboModel::data(const QModelIndex &index, int role) const 17 | { 18 | if (!index.isValid()) 19 | return QVariant(); 20 | 21 | if (role == Qt::DisplayRole) { 22 | return modelData.at(index.row()); 23 | } 24 | 25 | return QVariant(); 26 | } 27 | 28 | QList CuteBasicComboModel::getModelData() const 29 | { 30 | return modelData; 31 | } 32 | 33 | void CuteBasicComboModel::setModelData(const QList &datas) 34 | { 35 | beginResetModel(); 36 | modelData = datas; 37 | endResetModel(); 38 | } 39 | 40 | int CuteBasicComboModel::getDataRow(const QString &text) 41 | { 42 | for (int row = 0; row < modelData.count(); row++) { 43 | // 可以用qstring的匹配接口,如忽略大小写等 44 | if (text == modelData.at(row)) { 45 | return row; 46 | } 47 | } 48 | return -1; 49 | } 50 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboPopup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "CuteComponentExport.h" 5 | class CuteBasicComboContainer; 6 | 7 | /** 8 | * @brief BasicComboBox 的弹框 9 | * @author 龚建波 10 | * @date 2020-7-7 11 | */ 12 | class Cute_API CuteBasicComboPopup : public QWidget 13 | { 14 | Q_OBJECT 15 | public: 16 | explicit CuteBasicComboPopup(QWidget *parent = nullptr); 17 | 18 | // 弹框显示隐藏 19 | void showPopup(); 20 | void hidePopup(); 21 | 22 | // 绑定弹出的目标组件,在其上或其下弹出 23 | void attachTarget(QWidget *widget); 24 | // 最终弹出的组件 25 | CuteBasicComboContainer *getContainer(); 26 | void setContainer(CuteBasicComboContainer *widget); 27 | 28 | protected: 29 | void showEvent(QShowEvent *event) override; 30 | void hideEvent(QHideEvent *event) override; 31 | 32 | private: 33 | // 设置弹出框大小 34 | void setPopSize(int width, int height); 35 | 36 | signals: 37 | void containerChanged(); 38 | void visibleChanged(bool visible); 39 | 40 | private: 41 | // 绑定下拉框主体,用于计算弹出位置 42 | QWidget *targetWidget{ nullptr }; 43 | // 弹出动画 44 | QPropertyAnimation *animation{ nullptr }; 45 | // 弹出框实际展示的widget 46 | CuteBasicComboContainer *container{ nullptr }; 47 | }; 48 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboContainer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CuteComponentExport.h" 4 | class CuteBasicComboView; 5 | 6 | /** 7 | * @brief BasicComboBox 弹框中的内容 8 | * @author 龚建波 9 | * @date 2020-7-6 10 | * @details 自定义时继承该类并实现对应接口 11 | * 附带了一个 ListView 版本的默认实现供参考 12 | */ 13 | class Cute_API CuteBasicComboContainer : public QWidget 14 | { 15 | Q_OBJECT 16 | public: 17 | // init = true 则调用默认初始化 18 | explicit CuteBasicComboContainer(bool init = true, QWidget *parent = nullptr); 19 | 20 | // box需要回调的接口 21 | // 当前行 22 | virtual int getCurrentIndex() const; 23 | virtual void setCurrentIndex(int index); 24 | // 数据项 25 | virtual QList getItems() const; 26 | virtual void setItems(const QList &items); 27 | // 根据文本设置当前行,返回当前行,-1为无效 28 | virtual int checkTextRow(const QString &text); 29 | // 切换并获取当前行文本 30 | virtual QString getCurrentText() const; 31 | virtual QString getPrevText(); 32 | virtual QString getNextText(); 33 | 34 | // popup 回调的接口 35 | virtual int getContentsHeight() const; 36 | 37 | private: 38 | void initDefault(); 39 | 40 | signals: 41 | void currentIndexChanged(int index); 42 | void updateData(); 43 | 44 | private: 45 | CuteBasicComboView *defaultView{ nullptr }; 46 | }; 47 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "CuteComponentExport.h" 5 | class CuteBasicComboModel; 6 | 7 | /** 8 | * @brief BasicComboBox 默认弹框中的列表 9 | * @author 龚建波 10 | * @date 2020-7-6 11 | */ 12 | class Cute_API CuteBasicComboView : public QListView 13 | { 14 | Q_OBJECT 15 | public: 16 | explicit CuteBasicComboView(QWidget *parent = nullptr); 17 | 18 | // 获取当前行,避免和已有接口重名 19 | int getCurrentRow() const; 20 | void setCurrentRow(int row); 21 | // 根据文本设置当前行,返回当前行,-1为无效 22 | int checkTextRow(const QString &text); 23 | // 切换并获取当前行文本 24 | QString getCurrentText(); 25 | QString getNextText(); 26 | QString getPrevText(); 27 | // 设置 model 28 | CuteBasicComboModel *getBasicModel() const; 29 | void setBasicModel(CuteBasicComboModel *model); 30 | // 获取内容高度 31 | int getContentsHeight() const; 32 | 33 | protected: 34 | // 过滤一些按键操作 35 | void keyReleaseEvent(QKeyEvent *event) override; 36 | 37 | private: 38 | void initModel(); 39 | void initView(); 40 | 41 | signals: 42 | // 手动点击触发信号 43 | void rowClicked(int row); 44 | // model 重置了数据 45 | void modelReseted(); 46 | // 当前行改变 47 | void currentRowChanged(int row); 48 | 49 | private: 50 | CuteBasicComboModel *basicModel{ nullptr }; 51 | }; 52 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboBox.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CuteComponentExport.h" 4 | #include "CuteBasicComboContainer.h" 5 | #include "CuteBasicComboModel.h" 6 | #include "CuteBasicComboPopup.h" 7 | #include "CuteBasicComboView.h" 8 | class QLineEdit; 9 | class QPushButton; 10 | class QHBoxLayout; 11 | class QTimer; 12 | 13 | /** 14 | * @brief 使用 QLineEdit + QPushButton + 弹出框组合的下拉框 15 | * @author 龚建波 16 | * @date 2020-7-6 17 | * @history 18 | * [2020-7-7] 19 | * 重构弹出框部分,增加可扩展性 20 | * 基础组件:Box+Popup,继承 Container 实现接口后设置给 Popup 21 | */ 22 | class Cute_API CuteBasicComboBox : public QWidget 23 | { 24 | Q_OBJECT 25 | Q_PROPERTY(int borderWidth READ getBorderWidth WRITE setBorderWidth NOTIFY borderWidthChanged) 26 | Q_PROPERTY(bool popupVisible READ getPopupVisible WRITE setPopupVisible NOTIFY popupVisibleChanged) 27 | public: 28 | explicit CuteBasicComboBox(QWidget *parent = nullptr); 29 | ~CuteBasicComboBox(); 30 | 31 | // 边框 size,自定义属性方便 qss 设置 32 | int getBorderWidth() const; 33 | void setBorderWidth(int px); 34 | 35 | // 弹框可见 36 | bool getPopupVisible() const; 37 | void setPopupVisible(bool visible); 38 | 39 | // 当前行 40 | int getCurrentIndex() const; 41 | void setCurrentIndex(int index); 42 | // 当前文本 43 | QString getCurrentText() const; 44 | void setCurrentText(const QString &text); 45 | // 数据项 46 | QList getItems() const; 47 | void setItems(const QList &items); 48 | // 弹出框 49 | CuteBasicComboPopup *getPopup() const; 50 | 51 | protected: 52 | // 过滤组件事件 53 | bool eventFilter(QObject *watched, QEvent *event) override; 54 | 55 | private: 56 | // 初始化组件设置 57 | void initComponent(); 58 | // popup-container 59 | void initContainer(); 60 | // 编辑后查询对应行并设置 model 61 | void checkTextRow(); 62 | 63 | signals: 64 | void borderWidthChanged(int px); 65 | void popupVisibleChanged(bool visible); 66 | void currentIndexChanged(int index); 67 | void currentTextChanged(const QString text); 68 | 69 | private: 70 | // 边框 71 | int borderWidth{ 3 }; 72 | // 弹框当前可见 73 | bool popupVisible{ false }; 74 | 75 | // 文本框 76 | QLineEdit *boxEdit{ nullptr }; 77 | // 下拉按钮 78 | QPushButton *boxDown{ nullptr }; 79 | // 布局 80 | QHBoxLayout *boxLayout{ nullptr }; 81 | // 弹框 82 | CuteBasicComboPopup *boxPop{ nullptr }; 83 | // 定时器 84 | QTimer *editTimer{ nullptr }; 85 | }; 86 | -------------------------------------------------------------------------------- /Example/PopupDemo.cpp: -------------------------------------------------------------------------------- 1 | #include "PopupDemo.h" 2 | #include "ui_PopupDemo.h" 3 | #include "Popup/CuteBasicComboBox.h" 4 | #include "Popup/CuteBasicComboContainer.h" 5 | #include 6 | 7 | PopupDemo::PopupDemo(QWidget *parent) : 8 | QWidget(parent), 9 | ui(new Ui::PopupDemo) 10 | { 11 | ui->setupUi(this); 12 | initComboBox(); 13 | } 14 | 15 | PopupDemo::~PopupDemo() 16 | { 17 | delete ui; 18 | } 19 | 20 | void PopupDemo::initComboBox() 21 | { 22 | ui->comboBoxA->getPopup()->setContainer(new CuteBasicComboContainer(this)); 23 | ui->comboBoxB->getPopup()->setContainer(new CuteBasicComboContainer(this)); 24 | 25 | ui->comboBoxA->setItems({"aaa","bbb","ccc","ddd","eee","fff","ggg", 26 | "fff","iii","jjj","kkk","lll","mmm","nnn"}); 27 | connect(ui->comboBoxA, &CuteBasicComboBox::currentIndexChanged, [this](int index) { 28 | qDebug() << "CuteBasicComboBox::currentIndexChanged" << index; 29 | }); 30 | connect(ui->comboBoxA, &CuteBasicComboBox::currentTextChanged, [this](const QString &text) { 31 | qDebug() << "CuteBasicComboBox::currentTextChanged" << text; 32 | }); 33 | 34 | ui->comboBoxB->setItems({"aaa","bbb","ccc"}); 35 | 36 | const char *qss_str = R"( 37 | CuteBasicComboBox{ 38 | qproperty-borderWidth:"1"; 39 | border:1px solid white; 40 | background:rgb(20,50,70); 41 | } 42 | CuteBasicComboBox:disable{ 43 | border:1px solid gray; 44 | } 45 | CuteBasicComboBox #edit{ 46 | border:0; 47 | margin:0; 48 | padding:0px 3px; 49 | color:white; 50 | background:rgb(20,50,70); 51 | } 52 | CuteBasicComboBox #down{ 53 | border:0; 54 | padding:0; 55 | margin:0; 56 | min-width:20px; 57 | max-width:20px; 58 | min-height:20px; 59 | max-height:20px; 60 | background-color:rgb(20,50,70); 61 | subcontrol-position:center; 62 | border-image:url(:/Image/down_white.png); 63 | } 64 | CuteBasicComboBox[popupVisible="1"] #down{ 65 | border-image:url(:/Image/up_white.png); 66 | } 67 | CuteBasicComboContainer{ 68 | border:0; 69 | background:red; 70 | } 71 | CuteBasicComboView{ 72 | border:1px solid white; 73 | font:14px "宋体"; 74 | background:rgb(20,50,70); 75 | } 76 | CuteBasicComboView::item{ 77 | height:24px; 78 | color:white; 79 | background:rgb(20,50,70); 80 | } 81 | CuteBasicComboView::item:selected, 82 | CuteBasicComboView::item:hover{ 83 | color:white; 84 | background-color:rgb(255,170,0); 85 | } 86 | )"; 87 | ui->comboBoxA->setStyleSheet(qss_str); 88 | ui->comboBoxB->setStyleSheet(qss_str); 89 | } 90 | -------------------------------------------------------------------------------- /CuteComponent/ToolTip/CuteToolTip.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "CuteComponentExport.h" 6 | 7 | /** 8 | * @brief 最简易的 ToolTip 提示框 9 | * @author 龚建波 10 | * @date 2020-6-7 11 | * @details 12 | * 外部为 QDialog,设置 parent 后也能独立窗口显示 13 | * 内部套一个 QLabel 显示文字 14 | */ 15 | class Cute_API CuteToolTip : public QDialog 16 | { 17 | Q_OBJECT 18 | // 默认显示为 point 的左上角,通过属性设置偏移,左-右+,上-下+,同屏幕坐标系规则 19 | // qss 右移 1px: qproperty-xOffset:"1"; 20 | Q_PROPERTY(int xOffset READ getXOffset WRITE setXOffset NOTIFY xOffsetChanged) 21 | // qss 上移 1px: qproperty-yOffset:"-1"; 22 | Q_PROPERTY(int yOffset READ getYOffset WRITE setYOffset NOTIFY yOffsetChanged) 23 | Q_PROPERTY(QString text READ getText WRITE setText NOTIFY textChanged) 24 | Q_PROPERTY(Qt::Alignment alignment READ getAlignment WRITE setAlignment NOTIFY alignmentChanged) 25 | public: 26 | explicit CuteToolTip(const QString text = QString(), QWidget *parent = nullptr); 27 | ~CuteToolTip(); 28 | 29 | // x 轴偏移 30 | int getXOffset() const; 31 | void setXOffset(int offset); 32 | // y 轴偏移 33 | int getYOffset() const; 34 | void setYOffset(int offset); 35 | 36 | // 文本 37 | QString getText() const; 38 | void setText(const QString &text); 39 | // 对齐方式 40 | Qt::Alignment getAlignment() const; 41 | void setAlignment(Qt::Alignment alignment); 42 | 43 | // 设置锚定窗口,鼠标放上去时显示 tooltip 44 | void anchorTarget(QWidget *target); 45 | // 获取内层 label 对象 46 | const QLabel *label() const; 47 | // 显示 tip 在 widget 的左上角 48 | void showTip(const QWidget *obj); 49 | // 显示 tip 在点的左上角 50 | void showTip(const QPoint &rightBottom); 51 | // 隐藏 tip 52 | void hideTip(); 53 | 54 | protected: 55 | // 过滤锚定窗口的 enter 和 leave 事件 56 | bool eventFilter(QObject *target, QEvent *event) override; 57 | void timerEvent(QTimerEvent *event) override; 58 | void resizeEvent(QResizeEvent *event) override; 59 | 60 | signals: 61 | void xOffsetChanged(); 62 | void yOffsetChanged(); 63 | void textChanged(); 64 | void alignmentChanged(); 65 | 66 | private: 67 | // 内部套一个 QLabel 显示文字 68 | QLabel *contentLabel{ nullptr }; 69 | // 默认显示为 point 的左上角,通过属性设置偏移 70 | // 左-右+,上-下+,同屏幕坐标系规则 71 | int xOffset{ 0 }; 72 | int yOffset{ 0 }; 73 | 74 | // 锚定的窗口 75 | QWidget *targetWidget{ nullptr }; 76 | QPoint targetPoint; 77 | // show 和 hide 延迟 78 | QBasicTimer showTimer; 79 | QBasicTimer hideTimer; 80 | }; 81 | -------------------------------------------------------------------------------- /Example/img.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Image/check_blue.png 4 | Image/check_green.png 5 | Image/check_orange.png 6 | Image/check_white.png 7 | Image/checked_blue.png 8 | Image/checked_green.png 9 | Image/checked_orange.png 10 | Image/checked_white.png 11 | Image/close_gray.png 12 | Image/close_red.png 13 | Image/down_blue.png 14 | Image/down_orange.png 15 | Image/down_white.png 16 | Image/downmax_blue.png 17 | Image/downmax_orange.png 18 | Image/downmax_white.png 19 | Image/left_blue.png 20 | Image/left_orange.png 21 | Image/left_white.png 22 | Image/leftmax_blue.png 23 | Image/leftmax_green.png 24 | Image/leftmax_orange.png 25 | Image/leftmax_white.png 26 | Image/leftmin_blue.png 27 | Image/leftmin_green.png 28 | Image/leftmin_orange.png 29 | Image/leftmin_white.png 30 | Image/max_gray.png 31 | Image/max_orange.png 32 | Image/min_gray.png 33 | Image/min_orange.png 34 | Image/normal_gray.png 35 | Image/normal_orange.png 36 | Image/right_blue.png 37 | Image/right_orange.png 38 | Image/right_white.png 39 | Image/rightmax_blue.png 40 | Image/rightmax_green.png 41 | Image/rightmax_orange.png 42 | Image/rightmax_white.png 43 | Image/rightmin_blue.png 44 | Image/rightmin_green.png 45 | Image/rightmin_orange.png 46 | Image/rightmin_white.png 47 | Image/set_gray.png 48 | Image/set_orange.png 49 | Image/up_blue.png 50 | Image/up_orange.png 51 | Image/up_white.png 52 | Image/upmax_blue.png 53 | Image/upmax_orange.png 54 | Image/upmax_white.png 55 | 56 | 57 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboContainer.cpp: -------------------------------------------------------------------------------- 1 | #include "CuteBasicComboContainer.h" 2 | #include "CuteBasicComboView.h" 3 | #include "CuteBasicComboModel.h" 4 | #include 5 | 6 | CuteBasicComboContainer::CuteBasicComboContainer(bool init, QWidget *parent) 7 | : QWidget{parent} 8 | { 9 | if (init) { 10 | initDefault(); 11 | } 12 | } 13 | 14 | int CuteBasicComboContainer::getCurrentIndex() const 15 | { 16 | if (defaultView) { 17 | return defaultView->getCurrentRow(); 18 | } 19 | return -1; 20 | } 21 | 22 | void CuteBasicComboContainer::setCurrentIndex(int index) 23 | { 24 | if (defaultView) { 25 | defaultView->setCurrentRow(index); 26 | } 27 | } 28 | 29 | QList CuteBasicComboContainer::getItems() const 30 | { 31 | if (defaultView && defaultView->getBasicModel()) { 32 | return defaultView->getBasicModel()->getModelData(); 33 | } 34 | return QList(); 35 | } 36 | 37 | void CuteBasicComboContainer::setItems(const QList &items) 38 | { 39 | if (defaultView && defaultView->getBasicModel()) { 40 | defaultView->getBasicModel()->setModelData(items); 41 | } 42 | } 43 | 44 | int CuteBasicComboContainer::checkTextRow(const QString &text) 45 | { 46 | if (defaultView) { 47 | return defaultView->checkTextRow(text); 48 | } 49 | return -1; 50 | } 51 | 52 | QString CuteBasicComboContainer::getCurrentText() const 53 | { 54 | if (defaultView) { 55 | return defaultView->getCurrentText(); 56 | } 57 | return QString(); 58 | } 59 | 60 | QString CuteBasicComboContainer::getPrevText() 61 | { 62 | if (defaultView) { 63 | return defaultView->getPrevText(); 64 | } 65 | return QString(); 66 | } 67 | 68 | QString CuteBasicComboContainer::getNextText() 69 | { 70 | if (defaultView) { 71 | return defaultView->getNextText(); 72 | } 73 | return QString(); 74 | } 75 | 76 | int CuteBasicComboContainer::getContentsHeight() const 77 | { 78 | if (defaultView) { 79 | return defaultView->getContentsHeight(); 80 | } 81 | return 0; 82 | } 83 | 84 | void CuteBasicComboContainer::initDefault() 85 | { 86 | defaultView = new CuteBasicComboView(this); 87 | QVBoxLayout *layout = new QVBoxLayout(this); 88 | layout->setContentsMargins(0, 0, 0, 0); 89 | layout->addWidget(defaultView); 90 | // 91 | connect(defaultView, &CuteBasicComboView::currentRowChanged, this, &CuteBasicComboContainer::currentIndexChanged); 92 | connect(defaultView, &CuteBasicComboView::rowClicked, this, &CuteBasicComboContainer::updateData); 93 | connect(defaultView, &CuteBasicComboView::modelReseted, this, &CuteBasicComboContainer::updateData); 94 | } 95 | 96 | -------------------------------------------------------------------------------- /CuteComponent/ToolTip/CuteDesktopTip.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "CuteComponentExport.h" 7 | #include "CuteDesktopTipForm.h" 8 | 9 | /** 10 | * @brief 桌面弹框 11 | * @author 龚建波 12 | * @date 2020-6-28 13 | * @note 14 | * 可以增加 show 的 parent 参数,使模态有父子关系 15 | * 目前没有样式设置接口,可以增加一个 setForm 接口设置内部窗口 16 | * @details 17 | * show 时创建,close 时释放 18 | * 分为外层透明区域限定位置,和内层窗口样式 19 | */ 20 | class Cute_API CuteDesktopTip : public QDialog 21 | { 22 | Q_OBJECT 23 | public: 24 | // 动画模式枚举 25 | enum AnimationMode 26 | { 27 | // 无动画 28 | NoAnimation = 0x00, 29 | // 仅透明度动画 30 | OpacityAnimation = 0x01, 31 | // 仅位置动画 32 | PosAnimation = 0x02, 33 | // 全部动画 34 | AllAnimation = 0xFF 35 | }; 36 | // 显示位置枚举 37 | enum DisplayArea 38 | { 39 | // 当前窗口所在屏幕居中 40 | CenterArea = 0x00, 41 | // 主屏幕右下角 42 | RightBottomArea = 0x01 43 | }; 44 | private: 45 | explicit CuteDesktopTip(QWidget *parent = nullptr); 46 | public: 47 | ~CuteDesktopTip(); 48 | 49 | // 设置动画模式 50 | static CuteDesktopTip::AnimationMode getMode(); 51 | static void setMode(CuteDesktopTip::AnimationMode mode); 52 | 53 | // 设置显示位置 54 | static CuteDesktopTip::DisplayArea getArea(); 55 | static void setArea(CuteDesktopTip::DisplayArea area); 56 | 57 | // 显示弹框 -已显示动画重新开始, timeout <= 0 不会定时消失 58 | static void showTip(const QString &title, const QString &text, int timeout = 0); 59 | // 显示弹框 -已显示不重复动画 60 | static void keepTip(const QString &title, const QString &text); 61 | // 隐藏弹框 62 | static void hideTip(); 63 | 64 | private: 65 | // 初始化动画设置 66 | void initAnimation(); 67 | // 初始化定时器设置 68 | void initTimer(); 69 | // 准备定时器 70 | void readyTimer(int timeout); 71 | // 启动显示动画-已显示动画重新开始 72 | void showAnimation(); 73 | // 启动显示动画-已显示不重复动画 74 | void keepAnimation(); 75 | // 启动隐藏动画 76 | void hideAnimation(); 77 | // 显示的标题和文本 78 | void setText(const QString &title, const QString &text); 79 | 80 | private: 81 | // form 为独立的 widget,封装 ui 相关接口 82 | CuteDesktopTipForm *form{ nullptr }; 83 | 84 | // 单例 85 | static CuteDesktopTip *instance; 86 | // 动画设置 87 | static AnimationMode aniMode; 88 | // 显示位置 89 | static DisplayArea aniArea; 90 | 91 | // 动画组 92 | QParallelAnimationGroup *aniGroup{ nullptr }; 93 | // 透明度属性动画 94 | QPropertyAnimation *aniOpacity{ nullptr }; 95 | // 位置属性动画 96 | QPropertyAnimation *aniPos{ nullptr }; 97 | // 动画结束标志,因为每次都会创建新的弹框,所以默认 false 表示正在动画 98 | bool showAniEnd{ false }; 99 | 100 | // 定时关闭 101 | QTimer *hideTimer{ nullptr }; 102 | // 定时计数 103 | int hideCount{ 0 }; 104 | }; 105 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboPopup.cpp: -------------------------------------------------------------------------------- 1 | #include "CuteBasicComboPopup.h" 2 | #include "CuteBasicComboContainer.h" 3 | #include 4 | 5 | CuteBasicComboPopup::CuteBasicComboPopup(QWidget *parent) 6 | : QWidget{parent} 7 | { 8 | // 背景透明 FramelessWindowHint + WA_TranslucentBackground 9 | // 这样才能给上面的组件设置透明色 10 | setWindowFlags(Qt::Popup | Qt::FramelessWindowHint); 11 | setAttribute(Qt::WA_TranslucentBackground); 12 | setAttribute(Qt::WA_WindowPropagation); 13 | //setAttribute(Qt::WA_StyledBackground); 14 | 15 | animation = new QPropertyAnimation(this, "size", this); 16 | connect(animation, &QPropertyAnimation::finished, [this] { 17 | // 弹出后获得焦点 18 | if (container) 19 | container->setFocus(); 20 | }); 21 | } 22 | 23 | void CuteBasicComboPopup::showPopup() 24 | { 25 | // 没有设置 container 26 | if (!container) { 27 | qDebug() << __FUNCTION__ << "please call attachTarget first"; 28 | return; 29 | } 30 | if (!targetWidget) { 31 | qDebug() << __FUNCTION__ << "please call setContainer first"; 32 | return; 33 | } 34 | // 已显示 or 动画正在运行? 35 | if (isVisible() || animation->state() == QAbstractAnimation::Running) 36 | return; 37 | 38 | // 设置为目标 widget 的宽度 39 | setPopSize(targetWidget->width(), 1); 40 | // 先 show 再 move 位置才是正确的 41 | show(); 42 | // show 之后取到的大小才是计算好的 43 | const int view_height = container->getContentsHeight(); 44 | setPopSize(targetWidget->width(), view_height>150?150:view_height); 45 | // wrapper 复位 46 | container->move(0, 0); 47 | // 移动到目标 widget 上方或下方 48 | move(targetWidget->mapToGlobal(targetWidget->rect().bottomLeft())); 49 | 50 | // 弹出如果从0开始,点击窗口标题栏不会隐藏? 51 | animation->setStartValue(QSize(targetWidget->width(), 1)); 52 | animation->setEndValue(QSize(targetWidget->width(), container->height())); 53 | animation->setDuration(250); 54 | 55 | animation->start(); 56 | } 57 | 58 | void CuteBasicComboPopup::hidePopup() 59 | { 60 | hide(); 61 | } 62 | 63 | void CuteBasicComboPopup::attachTarget(QWidget *widget) 64 | { 65 | targetWidget = widget; 66 | } 67 | 68 | CuteBasicComboContainer *CuteBasicComboPopup::getContainer() 69 | { 70 | return container; 71 | } 72 | 73 | void CuteBasicComboPopup::setContainer(CuteBasicComboContainer *widget) 74 | { 75 | if (container == widget) 76 | return; 77 | 78 | if (container) { 79 | container->disconnect(); 80 | container->deleteLater(); 81 | } 82 | // 83 | container = widget; 84 | container->setParent(this); 85 | connect(container, &CuteBasicComboContainer::updateData, this, &CuteBasicComboPopup::hidePopup); 86 | emit containerChanged(); 87 | } 88 | 89 | void CuteBasicComboPopup::showEvent(QShowEvent *event) 90 | { 91 | QWidget::showEvent(event); 92 | emit visibleChanged(true); 93 | } 94 | 95 | void CuteBasicComboPopup::hideEvent(QHideEvent *event) 96 | { 97 | QWidget::hideEvent(event); 98 | emit visibleChanged(false); 99 | } 100 | 101 | void CuteBasicComboPopup::setPopSize(int width, int height) 102 | { 103 | // 如果会被内容撑开,可以用 fixed size 104 | resize(width, 1); 105 | if (container) 106 | container->resize(width, height); 107 | } 108 | -------------------------------------------------------------------------------- /Example/ToolTipDemo.cpp: -------------------------------------------------------------------------------- 1 | #include "ToolTipDemo.h" 2 | #include "ui_ToolTipDemo.h" 3 | #include 4 | #include "ToolTip/CuteToolTip.h" 5 | #include "ToolTip/CuteDesktopTip.h" 6 | 7 | ToolTipDemo::ToolTipDemo(QWidget *parent) 8 | : QWidget{parent}, 9 | ui{new Ui::ToolTipDemo} 10 | { 11 | ui->setupUi(this); 12 | initToolTip(); 13 | initDesktopTip(); 14 | } 15 | 16 | ToolTipDemo::~ToolTipDemo() 17 | { 18 | delete ui; 19 | } 20 | 21 | void ToolTipDemo::initToolTip() 22 | { 23 | CuteToolTip *tip_a = new CuteToolTip("Tip A", ui->btnToolTipA); 24 | // 通过 objectName 区分样式表设置 25 | tip_a->setObjectName("tipA"); 26 | tip_a->anchorTarget(ui->btnToolTipA); 27 | // 样式表设置为固定尺寸 tip 28 | tip_a->setStyleSheet(R"( 29 | .CuteToolTip#tipA{ 30 | min-width:100px; 31 | max-width:100px; 32 | min-height:30px; 33 | max-height:30px; 34 | } 35 | .CuteToolTip#tipA QLabel{ 36 | color:white; 37 | border:1px solid white; 38 | padding:0; 39 | border-radius:5px; 40 | background-color:rgba(250,170,0,150); 41 | } 42 | )"); 43 | 44 | CuteToolTip *tip_b = new CuteToolTip("Tip B", ui->btnToolTipB); 45 | tip_b->setObjectName("tipB"); 46 | tip_b->anchorTarget(ui->btnToolTipB); 47 | // 自适应的尺寸 48 | tip_b->setStyleSheet(R"( 49 | .CuteToolTip#tipB{ 50 | qproperty-xOffset:"20"; 51 | qproperty-yOffset:"3"; 52 | } 53 | .CuteToolTip#tipB QLabel{ 54 | padding:10px 30px; 55 | color:white; 56 | border:1px solid white; 57 | background-color:rgb(20,50,90); 58 | } 59 | )"); 60 | } 61 | 62 | void ToolTipDemo::initDesktopTip() 63 | { 64 | // 选择启用的动画 65 | ui->boxDesktopTipAni->setView(new QListView(this)); 66 | // 第一项用默认值 67 | ui->boxDesktopTipAni->addItems({"All", "No", "Opacity", "Pos"}); 68 | connect(ui->boxDesktopTipAni, QOverload::of(&QComboBox::currentIndexChanged), 69 | [](int index){ 70 | switch (index) { 71 | case 0: CuteDesktopTip::setMode(CuteDesktopTip::AllAnimation); break; 72 | case 1: CuteDesktopTip::setMode(CuteDesktopTip::NoAnimation); break; 73 | case 2: CuteDesktopTip::setMode(CuteDesktopTip::OpacityAnimation); break; 74 | case 3: CuteDesktopTip::setMode(CuteDesktopTip::PosAnimation); break; 75 | default: break; 76 | } 77 | }); 78 | // 选择弹出位置 79 | ui->boxDesktopTipArea->setView(new QListView(this)); 80 | // 第一项用默认值 81 | ui->boxDesktopTipArea->addItems({"RightBottom", "Center"}); 82 | connect(ui->boxDesktopTipArea, QOverload::of(&QComboBox::currentIndexChanged), 83 | [](int index){ 84 | switch (index) { 85 | case 0: CuteDesktopTip::setArea(CuteDesktopTip::RightBottomArea); break; 86 | case 1: CuteDesktopTip::setArea(CuteDesktopTip::CenterArea); break; 87 | default: break; 88 | } 89 | }); 90 | 91 | connect(ui->btnDesktopTipShow, &QPushButton::clicked, [=]{ 92 | // 只显示 n 秒就消失 93 | CuteDesktopTip::showTip("测试 showTip" 94 | , "这是 1 条信息\n这是 1 条信息\n这是 1 条信息\n这是 1 条信息" 95 | , 5); 96 | }); 97 | connect(ui->btnDesktopTipKeep, &QPushButton::clicked, [=]{ 98 | // 一直显示,直到点关闭 99 | CuteDesktopTip::keepTip("测试 keepTip" 100 | , "这是 1 条信息\n这是 1 条信息\n这是 1 条信息\n这是 1 条信息"); 101 | }); 102 | connect(ui->btnDesktopTipHide, &QPushButton::clicked, [=]{ 103 | CuteDesktopTip::hideTip(); 104 | }); 105 | } 106 | -------------------------------------------------------------------------------- /Example/PopupDemo.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | PopupDemo 4 | 5 | 6 | 7 | 0 8 | 0 9 | 623 10 | 408 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | QWidget{ 18 | font:14px "宋体"; 19 | color:white; 20 | background-color:rgb(20,50,70); 21 | } 22 | /*按钮*/ 23 | QPushButton{ 24 | border:1px solid rgb(230, 230, 230); 25 | background-color:rgb(200,150,0); 26 | } 27 | QPushButton:hover{ 28 | background-color:rgb(255,170,0); 29 | } 30 | QPushButton:pressed{ 31 | background-color:rgb(255,150,0); 32 | } 33 | QPushButton:disabled{ 34 | background-color:rgb(150,150,150); 35 | } 36 | /*下拉框*/ 37 | QComboBox{ 38 | border:1px solid rgb(230, 230, 230); 39 | } 40 | QComboBox QAbstractItemView{ 41 | border:1px solid rgb(230, 230, 230); 42 | background-color:rgb(20,50,70); 43 | } 44 | QComboBox QAbstractItemView::item{/*需要代码中-&gt;setView(new QListView(this));*/ 45 | height:26px; 46 | font:15px "宋体"; 47 | background-color:rgb(20,50,70); 48 | } 49 | QComboBox QAbstractItemView::item:selected{ 50 | background-color:rgb(255,170,0); 51 | } 52 | /*文本框*/ 53 | QLabel{ 54 | font:14px "宋体"; 55 | color:white; 56 | } 57 | 58 | 59 | 60 | 61 | 62 | 10 63 | 64 | 65 | 66 | 67 | ComboBox: 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 130 76 | 28 77 | 78 | 79 | 80 | 81 | 130 82 | 28 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 130 92 | 28 93 | 94 | 95 | 96 | 97 | 130 98 | 28 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | Qt::Horizontal 107 | 108 | 109 | 110 | 40 111 | 20 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | Qt::Vertical 122 | 123 | 124 | 125 | 20 126 | 351 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | CuteBasicComboBox 136 | QWidget 137 |
Popup/CuteBasicComboBox.h
138 | 1 139 |
140 |
141 | 142 | 143 |
144 | -------------------------------------------------------------------------------- /CuteComponent/ToolTip/CuteDesktopTipForm.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | CuteDesktopTipForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 285 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | QLabel{ 18 | color:white; 19 | font:15px 宋体; 20 | } 21 | #titleArea{ 22 | background-color:rgba(0, 85, 127, 230); 23 | border:1px solid black; 24 | border-bottom:0; 25 | } 26 | #content{ 27 | border:1px solid black; 28 | border-top:0; 29 | background-color:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(0, 117, 172, 230), stop:1 rgba(0, 85, 127, 230)); 30 | padding:6px 20px; 31 | } 32 | #close{ 33 | background-color:transparent; 34 | border:1px solid white; 35 | color:white; 36 | font:14px 宋体; 37 | } 38 | #close:hover{ 39 | background-color:white; 40 | color:rgb(0, 85, 127); 41 | } 42 | 43 | 44 | 45 | 0 46 | 47 | 48 | 0 49 | 50 | 51 | 0 52 | 53 | 54 | 0 55 | 56 | 57 | 0 58 | 59 | 60 | 61 | 62 | 63 | 0 64 | 28 65 | 66 | 67 | 68 | 69 | 16777215 70 | 28 71 | 72 | 73 | 74 | 75 | 5 76 | 77 | 78 | 5 79 | 80 | 81 | 0 82 | 83 | 84 | 10 85 | 86 | 87 | 0 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 0 101 | 0 102 | 103 | 104 | 105 | CuteDesktopTip 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 50 114 | 20 115 | 116 | 117 | 118 | 119 | 50 120 | 20 121 | 122 | 123 | 124 | Close 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 0 136 | 0 137 | 138 | 139 | 140 | 141 | 142 | 143 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboView.cpp: -------------------------------------------------------------------------------- 1 | #include "CuteBasicComboView.h" 2 | #include "CuteBasicComboModel.h" 3 | #include 4 | #include 5 | 6 | CuteBasicComboView::CuteBasicComboView(QWidget *parent) 7 | : QListView{parent} 8 | { 9 | setFocusPolicy(Qt::StrongFocus); 10 | setMouseTracking(true); 11 | 12 | initModel(); 13 | initView(); 14 | } 15 | 16 | int CuteBasicComboView::getCurrentRow() const 17 | { 18 | // 获取当前行 19 | const QModelIndex current = currentIndex(); 20 | if (current.isValid()) { 21 | return current.row(); 22 | } 23 | return -1; 24 | } 25 | 26 | void CuteBasicComboView::setCurrentRow(int row) 27 | { 28 | // 设置当前行 29 | if (row == getCurrentRow()) 30 | return; 31 | if (row >= 0 && row < basicModel->rowCount()) { 32 | setCurrentIndex(basicModel->index(row, 0)); 33 | emit currentRowChanged(row); 34 | } 35 | } 36 | 37 | int CuteBasicComboView::checkTextRow(const QString &text) 38 | { 39 | // 根据内容设置当前行 40 | const int row = basicModel->getDataRow(text); 41 | if (row >= 0) { 42 | setCurrentRow(row); 43 | return row; 44 | } 45 | return -1; 46 | } 47 | 48 | QString CuteBasicComboView::getCurrentText() 49 | { 50 | QModelIndex current = currentIndex(); 51 | // 如果当前行无效就去设置一个默认行0 52 | if (!current.isValid()) { 53 | if (basicModel->rowCount() > 0) { 54 | current = basicModel->index(0, 0); 55 | // setCurrentIndex(current); 56 | setCurrentRow(current.row()); 57 | return basicModel->data(current, Qt::DisplayRole).toString(); 58 | } 59 | return QString(); 60 | } 61 | return basicModel->data(current, Qt::DisplayRole).toString(); 62 | } 63 | 64 | QString CuteBasicComboView::getNextText() 65 | { 66 | QModelIndex current = currentIndex(); 67 | if (current.isValid()) { 68 | if (current.row() < basicModel->rowCount() - 1) { 69 | // 设置到下一行 70 | current = basicModel->index(current.row() + 1, 0); 71 | // setCurrentIndex(current); 72 | setCurrentRow(current.row()); 73 | return basicModel->data(current, Qt::DisplayRole).toString(); 74 | } 75 | } 76 | return getCurrentText(); 77 | } 78 | 79 | QString CuteBasicComboView::getPrevText() 80 | { 81 | QModelIndex current = currentIndex(); 82 | if (current.isValid()) { 83 | if (current.row() > 0) { 84 | // 设置到上一行 85 | current = basicModel->index(current.row() - 1, 0); 86 | // setCurrentIndex(current); 87 | setCurrentRow(current.row()); 88 | return basicModel->data(current, Qt::DisplayRole).toString(); 89 | } 90 | } 91 | return getCurrentText(); 92 | } 93 | 94 | CuteBasicComboModel *CuteBasicComboView::getBasicModel() const 95 | { 96 | return basicModel; 97 | } 98 | 99 | void CuteBasicComboView::setBasicModel(CuteBasicComboModel *model) 100 | { 101 | // 删除原来的 102 | if (basicModel) { 103 | basicModel->deleteLater(); 104 | } 105 | basicModel = model; 106 | setModel(basicModel); 107 | if (basicModel) { 108 | connect(basicModel, &CuteBasicComboModel::modelReset, this, &CuteBasicComboView::modelReseted); 109 | } 110 | } 111 | 112 | int CuteBasicComboView::getContentsHeight() const 113 | { 114 | return contentsSize().height() + 115 | contentsMargins().top() + 116 | contentsMargins().bottom() + 2; 117 | } 118 | 119 | void CuteBasicComboView::keyReleaseEvent(QKeyEvent *event) 120 | { 121 | switch (event->key()) { 122 | // 表示选中当前行,类似点击 123 | case Qt::Key_Return: 124 | case Qt::Key_Enter: 125 | case Qt::Key_Space: 126 | { 127 | QModelIndex index = currentIndex(); 128 | if (index.isValid()) { 129 | emit rowClicked(index.row()); 130 | emit currentRowChanged(index.row()); 131 | } 132 | } 133 | break; 134 | default: 135 | break; 136 | } 137 | QListView::keyReleaseEvent(event); 138 | } 139 | 140 | void CuteBasicComboView::initModel() 141 | { 142 | basicModel = new CuteBasicComboModel(this); 143 | setModel(basicModel); 144 | // 重置了 model data 145 | connect(basicModel, &CuteBasicComboModel::modelReset, this, &CuteBasicComboView::modelReseted); 146 | } 147 | 148 | void CuteBasicComboView::initView() 149 | { 150 | // 无数据时大小 151 | setMinimumSize(1, 1); 152 | // 单选中 153 | setSelectionMode(QAbstractItemView::SingleSelection); 154 | // 取消编辑 155 | setEditTriggers(QAbstractItemView::NoEditTriggers); 156 | // 157 | setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 158 | // 159 | connect(this, &CuteBasicComboView::clicked, this, [this](const QModelIndex &index) { 160 | if (index.isValid()) { 161 | emit rowClicked(index.row()); 162 | emit currentRowChanged(index.row()); 163 | } 164 | }); 165 | } 166 | -------------------------------------------------------------------------------- /Example/MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 720 10 | 500 11 | 12 | 13 | 14 | QtWidgets Component 15 | 16 | 17 | QWidget, 18 | QLabel{ 19 | color:white; 20 | background-color:rgb(20,50,70); 21 | font:14px "宋体"; 22 | } 23 | /*TabWidget*/ 24 | QTabWidget{ 25 | /*给tabwidget设置etAttribute(Qt::WA_StyledBackground)*/ 26 | border:1px solid rgb(230, 230, 230); 27 | background-color:rgb(20,50,70); 28 | } 29 | QTabWidget::tab-bar{ 30 | alignment:left; 31 | left:1px; 32 | } 33 | QTabWidget::pane { 34 | /*background-color:rgb(20,50,70);*/ 35 | border:1px solid rgb(230, 230, 230); 36 | } 37 | QTabBar{ 38 | /*只有有按钮的地方才是tabbar,空白处是tabwidget的*/ 39 | background-color:rgb(230, 230, 230); 40 | } 41 | QTabBar::tab{/*页签*/ 42 | min-height:28px; 43 | padding:0 10px; 44 | border:0; 45 | margin:1px 1px 0 0; 46 | background-color:rgb(20,50,70); 47 | } 48 | QTabBar::tab:first{ 49 | margin-left:1px; 50 | } 51 | QTabBar::tab:hover{ 52 | color:cyan; 53 | } 54 | QTabBar::tab:selected{ 55 | background-color:rgb(20, 100, 150); 56 | } 57 | QTabBar::tab:selected:hover{ 58 | } 59 | /*选项过多时的。。。*/ 60 | QTabBar::tear{ 61 | } 62 | QTabBar::scroller{ 63 | } 64 | /*滚动区域*/ 65 | QScrollArea{ 66 | border:0; 67 | background-color: transparent; 68 | } 69 | /*滚动条 */ 70 | QScrollBar:vertical{/*竖向*/ 71 | width:20px; 72 | padding:0 3px; 73 | margin:0; 74 | background-color:transparent; 75 | } 76 | QScrollBar::add-page:vertical, 77 | QScrollBar::sub-page:vertical{ 78 | background-color: transparent; 79 | } 80 | QScrollBar::handle:vertical{ 81 | width:10px; 82 | min-height:20px; 83 | margin:20px 0; 84 | background-color:rgb(210, 210, 210); 85 | } 86 | QScrollBar::handle:vertical:hover{ 87 | background-color:rgb(230, 230, 230); 88 | } 89 | QScrollBar::add-line:vertical{ 90 | height:20px; 91 | width:20px; 92 | subcontrol-position:bottom; 93 | border-image:url(:/Image/down_white.png); 94 | } 95 | QScrollBar::add-line:vertical:hover{ 96 | border-image:url(:/Image/down_orange.png); 97 | } 98 | QScrollBar::sub-line:vertical{ 99 | height:20px; 100 | width:20px; 101 | subcontrol-position:top; 102 | border-image:url(:/Image/up_white.png); 103 | } 104 | QScrollBar::sub-line:vertical:hover{ 105 | border-image:url(:/Image/up_orange.png); 106 | } 107 | QScrollBar:horizontal{/*横向*/ 108 | height:20px; 109 | padding:3px; 110 | margin:0; 111 | background-color:transparent; 112 | } 113 | QScrollBar::add-page:horizontal, 114 | QScrollBar::sub-page:horizontal{ 115 | background-color: transparent; 116 | } 117 | QScrollBar::handle:horizontal{ 118 | height:10px; 119 | min-width:20px; 120 | margin:0 20px; 121 | background-color:rgb(210, 210, 210); 122 | } 123 | QScrollBar::handle:horizontal:hover{ 124 | background-color:rgb(230, 230, 230); 125 | } 126 | QScrollBar::add-line:horizontal{ 127 | height:20px; 128 | width:20px; 129 | subcontrol-position:right; 130 | border-image:url(:/Image/right_white.png); 131 | } 132 | QScrollBar::add-line:horizontal:hover{ 133 | border-image:url(:/Image/right_orange.png); 134 | } 135 | QScrollBar::sub-line:horizontal{ 136 | height:20px; 137 | width:20px; 138 | subcontrol-position:left; 139 | border-image:url(:/Image/left_white.png); 140 | } 141 | QScrollBar::sub-line:horizontal:hover{ 142 | border-image:url(:/Image/left_orange.png); 143 | } 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 0 152 | 153 | 154 | 155 | ToolTip 156 | 157 | 158 | 159 | 160 | Popup 161 | 162 | 163 | 164 | 165 | Other 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | ToolTipDemo 176 | QWidget 177 |
ToolTipDemo.h
178 | 1 179 |
180 | 181 | PopupDemo 182 | QWidget 183 |
PopupDemo.h
184 | 1 185 |
186 |
187 | 188 | 189 |
190 | -------------------------------------------------------------------------------- /CuteComponent/ToolTip/CuteToolTip.cpp: -------------------------------------------------------------------------------- 1 | #include "CuteToolTip.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | //#include 9 | 10 | CuteToolTip::CuteToolTip(const QString text, QWidget *parent) 11 | : QDialog{parent} 12 | , contentLabel{new QLabel(this)} 13 | { 14 | // 把内层 label 添加到透明 dialog 15 | QHBoxLayout *layout = new QHBoxLayout(this); 16 | layout->setContentsMargins(0, 0, 0, 0); 17 | layout->setSpacing(0); 18 | layout->addWidget(contentLabel); 19 | 20 | contentLabel->setAlignment(Qt::AlignCenter); 21 | contentLabel->setText(text); 22 | 23 | // 把 dialog 设置为透明,样式表设置给 label 24 | setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip); 25 | setAttribute(Qt::WA_TranslucentBackground, true); 26 | // 默认 hide 27 | setVisible(false); 28 | // qDebug() << __FUNCTION__; 29 | } 30 | 31 | CuteToolTip::~CuteToolTip() 32 | { 33 | // qDebug() << __FUNCTION__; 34 | } 35 | 36 | int CuteToolTip::getXOffset() const 37 | { 38 | return xOffset; 39 | } 40 | 41 | void CuteToolTip::setXOffset(int offset) 42 | { 43 | if (xOffset != offset){ 44 | xOffset = offset; 45 | // 没有动态样式的处理,可自行添加 46 | // style()->unpolish(this); 47 | // style()->polish(this); 48 | emit xOffsetChanged(); 49 | } 50 | } 51 | 52 | int CuteToolTip::getYOffset() const 53 | { 54 | return yOffset; 55 | } 56 | 57 | void CuteToolTip::setYOffset(int offset) 58 | { 59 | if (yOffset != offset){ 60 | yOffset = offset; 61 | emit yOffsetChanged(); 62 | } 63 | } 64 | 65 | QString CuteToolTip::getText() const 66 | { 67 | return contentLabel->text(); 68 | } 69 | 70 | void CuteToolTip::setText(const QString &text) 71 | { 72 | if (getText() != text) { 73 | contentLabel->setText(text); 74 | emit textChanged(); 75 | } 76 | } 77 | 78 | Qt::Alignment CuteToolTip::getAlignment() const 79 | { 80 | return contentLabel->alignment(); 81 | } 82 | 83 | void CuteToolTip::setAlignment(Qt::Alignment alignment) 84 | { 85 | if (getAlignment() != alignment) { 86 | contentLabel->setAlignment(alignment); 87 | emit alignmentChanged(); 88 | } 89 | } 90 | 91 | void CuteToolTip::anchorTarget(QWidget *target) 92 | { 93 | if (!target) return; 94 | if (target != targetWidget) { 95 | if (targetWidget) { 96 | targetWidget->removeEventFilter(this); 97 | } 98 | targetWidget = target; 99 | targetWidget->installEventFilter(this); 100 | targetWidget->setMouseTracking(true); 101 | } 102 | } 103 | 104 | const QLabel *CuteToolTip::label() const 105 | { 106 | return contentLabel; 107 | } 108 | 109 | void CuteToolTip::showTip(const QWidget *obj) 110 | { 111 | if (!obj) return; 112 | showTip(obj->mapToGlobal(QPoint(0, 0))); 113 | } 114 | 115 | void CuteToolTip::showTip(const QPoint &rightBottom) 116 | { 117 | targetPoint = rightBottom; 118 | // move(rightBottom.x() - width() + xOffset, 119 | // rightBottom.y() - height() + yOffset); 120 | // 直接用size + point得到的位置可能显示不全,这里计算下 121 | 122 | int rect_left = rightBottom.x() - width() + xOffset; 123 | int rect_top = rightBottom.y() - height() + yOffset; 124 | // 根据当前所在屏幕尺寸计算,左上角不超过范围 125 | // 因为锚定的左上角显示,右下角暂不考虑 126 | // 老版本用 QDesktopWidget 127 | // QDesktopWidget *desktop = QApplication::desktop(); 128 | // QRect desk_rect=desktop->screenGeometry(targetWidget); 129 | // Qt5.11 QDesktopWidget 部分接口被废弃,Qt6 该类被移除 130 | // 新版本用 QScreen 131 | // 直接用 widget 的 screen() 获取的是整个 window 所在 screen,而不是组件的 132 | // 跨屏时在哪个屏幕占的区域最大,就以该屏幕作为组件的所属 screen 133 | QScreen *screen = nullptr; 134 | if (targetWidget) { 135 | screen = QGuiApplication::screenAt(targetWidget->mapToGlobal(targetWidget->rect().center())); 136 | } 137 | if (screen) { 138 | QRect desk_rect = screen->geometry(); 139 | if(rect_left < desk_rect.x()) 140 | rect_left = desk_rect.x(); 141 | if(rect_top < desk_rect.y()) 142 | rect_top = desk_rect.y(); 143 | } else { 144 | if (rect_left < 0) 145 | rect_left = 0; 146 | if (rect_top < 0) 147 | rect_top = 0; 148 | } 149 | 150 | move(rect_left, rect_top); 151 | if (!showTimer.isActive()) 152 | showTimer.start(200, this); 153 | } 154 | 155 | void CuteToolTip::hideTip() 156 | { 157 | if (!hideTimer.isActive()) 158 | hideTimer.start(300, this); 159 | } 160 | 161 | bool CuteToolTip::eventFilter(QObject *target, QEvent *event) 162 | { 163 | if (target == targetWidget) { 164 | switch (event->type()) { 165 | case QEvent::Enter: 166 | // showTip(QCursor::pos()); 167 | showTip(targetWidget); 168 | break; 169 | case QEvent::Leave: 170 | hideTip(); 171 | break; 172 | default: 173 | break; 174 | } 175 | } 176 | return QWidget::eventFilter(target, event); 177 | } 178 | 179 | void CuteToolTip::timerEvent(QTimerEvent *event) 180 | { 181 | if (event->timerId() == showTimer.timerId()) { 182 | showTimer.stop(); 183 | // hideTimer.stop(); 184 | if (!hideTimer.isActive() && isHidden()) { 185 | show(); 186 | } 187 | } else if (event->timerId() == hideTimer.timerId()) { 188 | showTimer.stop(); 189 | hideTimer.stop(); 190 | if (!isHidden()) { 191 | hide(); 192 | } 193 | } else { 194 | QWidget::timerEvent(event); 195 | } 196 | } 197 | 198 | void CuteToolTip::resizeEvent(QResizeEvent *event) 199 | { 200 | // 初次 show 的时候可能 size 可能还没计算好 201 | showTip(targetPoint); 202 | QWidget::resizeEvent(event); 203 | } 204 | -------------------------------------------------------------------------------- /CuteComponent/Popup/CuteBasicComboBox.cpp: -------------------------------------------------------------------------------- 1 | #include "CuteBasicComboBox.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | CuteBasicComboBox::CuteBasicComboBox(QWidget *parent) 13 | : QWidget{parent} 14 | , boxEdit{new QLineEdit(this)} 15 | , boxDown{new QPushButton(this)} 16 | , boxLayout{new QHBoxLayout(this)} 17 | , boxPop{new CuteBasicComboPopup(this)} 18 | , editTimer{new QTimer(this)} 19 | { 20 | // 支持样式表 21 | setAttribute(Qt::WA_StyledBackground); 22 | setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); 23 | 24 | initComponent(); 25 | } 26 | 27 | CuteBasicComboBox::~CuteBasicComboBox() 28 | { 29 | boxPop->hidePopup(); 30 | } 31 | 32 | int CuteBasicComboBox::getBorderWidth() const 33 | { 34 | return borderWidth; 35 | } 36 | 37 | void CuteBasicComboBox::setBorderWidth(int px) 38 | { 39 | if (borderWidth == px) 40 | return; 41 | borderWidth = px; 42 | boxLayout->setContentsMargins(borderWidth, borderWidth, borderWidth, borderWidth); 43 | emit borderWidthChanged(borderWidth); 44 | } 45 | 46 | bool CuteBasicComboBox::getPopupVisible() const 47 | { 48 | return popupVisible; 49 | } 50 | 51 | void CuteBasicComboBox::setPopupVisible(bool visible) 52 | { 53 | // qDebug() << __FUNCTION__ << popupVisible << visible; 54 | if (popupVisible == visible) 55 | return; 56 | popupVisible = visible; 57 | emit popupVisibleChanged(popupVisible); 58 | } 59 | 60 | int CuteBasicComboBox::getCurrentIndex() const 61 | { 62 | if (boxPop->getContainer()) { 63 | return boxPop->getContainer()->getCurrentIndex(); 64 | } 65 | return -1; 66 | } 67 | 68 | void CuteBasicComboBox::setCurrentIndex(int index) 69 | { 70 | if (boxPop->getContainer()) { 71 | boxPop->getContainer()->setCurrentIndex(index); 72 | } 73 | } 74 | 75 | QString CuteBasicComboBox::getCurrentText() const 76 | { 77 | return boxEdit->text(); 78 | } 79 | 80 | void CuteBasicComboBox::setCurrentText(const QString &text) 81 | { 82 | editTimer->stop(); 83 | boxEdit->setText(text); 84 | } 85 | 86 | QList CuteBasicComboBox::getItems() const 87 | { 88 | if (boxPop->getContainer()) { 89 | return boxPop->getContainer()->getItems(); 90 | } 91 | return QList(); 92 | } 93 | 94 | void CuteBasicComboBox::setItems(const QList &items) 95 | { 96 | if (boxPop->getContainer()) { 97 | boxPop->getContainer()->setItems(items); 98 | } 99 | } 100 | 101 | CuteBasicComboPopup *CuteBasicComboBox::getPopup() const 102 | { 103 | return boxPop; 104 | } 105 | 106 | bool CuteBasicComboBox::eventFilter(QObject *watched, QEvent *event) 107 | { 108 | if (watched == boxEdit) { 109 | // 过滤编辑框事件 110 | switch (event->type()) { 111 | case QEvent::KeyRelease: 112 | { 113 | if (boxPop->getContainer()) { 114 | // 这里只考虑了edit可编辑的情况 115 | QKeyEvent *key_event = static_cast(event); 116 | if (key_event->key() == Qt::Key_Up) { 117 | setCurrentText(boxPop->getContainer()->getPrevText()); 118 | } else if(key_event->key() == Qt::Key_Down) { 119 | setCurrentText(boxPop->getContainer()->getNextText()); 120 | } 121 | } 122 | } 123 | break; 124 | case QEvent::FocusAboutToChange: 125 | case QEvent::FocusIn: 126 | { 127 | // 获得焦点时全选 128 | QFocusEvent *focus_event = static_cast(event); 129 | if (focus_event->gotFocus()) { 130 | QTimer::singleShot(20, boxEdit, &QLineEdit::selectAll); 131 | } 132 | } 133 | break; 134 | default: 135 | break; 136 | } 137 | } else if(watched == boxDown) { 138 | // 过滤按钮事件 139 | } else if(watched == boxPop) { 140 | // 过滤弹框事件 141 | } 142 | return false; 143 | } 144 | 145 | void CuteBasicComboBox::initComponent() 146 | { 147 | // 按钮设置 148 | boxDown->setObjectName("down"); 149 | boxDown->setFocusPolicy(Qt::NoFocus); 150 | boxDown->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 151 | boxDown->installEventFilter(this); 152 | 153 | // 编辑框设置 154 | boxEdit->setObjectName("edit"); 155 | boxEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 156 | boxEdit->installEventFilter(this); 157 | // index 和 text 两个属性可以看成独立的 158 | connect(boxEdit, &QLineEdit::textChanged, this, &CuteBasicComboBox::currentTextChanged); 159 | // 编辑时,延迟一会儿进行查询-currentindex 160 | connect(boxEdit, &QLineEdit::textEdited, [this] { 161 | editTimer->start(300); 162 | }); 163 | // 编辑结束,进行查询-currentindex 164 | connect(boxEdit, &QLineEdit::editingFinished, this, &CuteBasicComboBox::checkTextRow); 165 | editTimer->setSingleShot(true); 166 | connect(editTimer, &QTimer::timeout, this, &CuteBasicComboBox::checkTextRow); 167 | 168 | // 弹框容器设置 169 | boxPop->attachTarget(this); 170 | boxPop->installEventFilter(this); 171 | initContainer(); 172 | connect(boxPop, &CuteBasicComboPopup::containerChanged, this, &CuteBasicComboBox::initContainer); 173 | connect(boxPop, &CuteBasicComboPopup::visibleChanged, this, &CuteBasicComboBox::setPopupVisible); 174 | 175 | // 布局 176 | boxLayout->setContentsMargins(borderWidth, borderWidth, borderWidth, borderWidth); 177 | boxLayout->setSpacing(0); 178 | boxLayout->addWidget(boxEdit); 179 | boxLayout->addWidget(boxDown); 180 | // 点击按钮,弹出 181 | // 这里有个问题,切换焦点导致弹框自动关闭,再进入该逻辑则visible已经是false,于是又弹出了 182 | connect(boxDown, &QPushButton::pressed, [this]() { 183 | // qDebug() << "toggled" << getPopupVisible(); 184 | if (getPopupVisible()) { 185 | boxPop->hidePopup(); 186 | } else { 187 | boxPop->showPopup(); 188 | } 189 | 190 | }); 191 | } 192 | 193 | void CuteBasicComboBox::initContainer() 194 | { 195 | if(!boxPop->getContainer()) 196 | return; 197 | 198 | connect(boxPop->getContainer(), &CuteBasicComboContainer::currentIndexChanged, this, &CuteBasicComboBox::currentIndexChanged); 199 | connect(boxPop->getContainer(), &CuteBasicComboContainer::updateData, [this] { 200 | setCurrentText(boxPop->getContainer()->getCurrentText()); 201 | }); 202 | } 203 | 204 | void CuteBasicComboBox::checkTextRow() 205 | { 206 | // 如果 model 中有匹配的文本,就修改 view 的 currentIndex 207 | if (boxPop->getContainer() && boxPop->getContainer()->checkTextRow(boxEdit->text()) >= 0){ 208 | setCurrentText(boxPop->getContainer()->getCurrentText()); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /Example/ToolTipDemo.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ToolTipDemo 4 | 5 | 6 | 7 | 0 8 | 0 9 | 611 10 | 364 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | QWidget{ 18 | font:14px "宋体"; 19 | color:white; 20 | background-color:rgb(20,50,70); 21 | } 22 | /*按钮*/ 23 | QPushButton{ 24 | border:1px solid rgb(230, 230, 230); 25 | background-color:rgb(200,150,0); 26 | } 27 | QPushButton:hover{ 28 | background-color:rgb(255,170,0); 29 | } 30 | QPushButton:pressed{ 31 | background-color:rgb(255,150,0); 32 | } 33 | QPushButton:disabled{ 34 | background-color:rgb(150,150,150); 35 | } 36 | /*下拉框*/ 37 | QComboBox{ 38 | border:1px solid rgb(230, 230, 230); 39 | } 40 | QComboBox QAbstractItemView{ 41 | border:1px solid rgb(230, 230, 230); 42 | background-color:rgb(20,50,70); 43 | } 44 | QComboBox QAbstractItemView::item{/*需要代码中-&gt;setView(new QListView(this));*/ 45 | height:26px; 46 | font:15px "宋体"; 47 | background-color:rgb(20,50,70); 48 | } 49 | QComboBox QAbstractItemView::item:selected{ 50 | background-color:rgb(255,170,0); 51 | } 52 | /*文本框*/ 53 | QLabel{ 54 | font:14px "宋体"; 55 | color:white; 56 | } 57 | 58 | 59 | 60 | 61 | 62 | 10 63 | 64 | 65 | 66 | 67 | ToolTip: 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 80 76 | 28 77 | 78 | 79 | 80 | 81 | 80 82 | 28 83 | 84 | 85 | 86 | Enable 87 | 88 | 89 | 90 | 91 | 92 | 93 | false 94 | 95 | 96 | 97 | 80 98 | 28 99 | 100 | 101 | 102 | 103 | 80 104 | 28 105 | 106 | 107 | 108 | Disable 109 | 110 | 111 | 112 | 113 | 114 | 115 | Qt::Horizontal 116 | 117 | 118 | 119 | 40 120 | 20 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 10 131 | 132 | 133 | 134 | 135 | DesktopTip: 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 100 144 | 28 145 | 146 | 147 | 148 | 149 | 100 150 | 28 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 100 160 | 28 161 | 162 | 163 | 164 | 165 | 100 166 | 28 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 80 176 | 28 177 | 178 | 179 | 180 | 181 | 80 182 | 28 183 | 184 | 185 | 186 | Show 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 80 195 | 28 196 | 197 | 198 | 199 | 200 | 80 201 | 28 202 | 203 | 204 | 205 | Keep 206 | 207 | 208 | 209 | 210 | 211 | 212 | true 213 | 214 | 215 | 216 | 80 217 | 28 218 | 219 | 220 | 221 | 222 | 80 223 | 28 224 | 225 | 226 | 227 | Hide 228 | 229 | 230 | 231 | 232 | 233 | 234 | Qt::Horizontal 235 | 236 | 237 | 238 | 40 239 | 20 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | Qt::Vertical 250 | 251 | 252 | 253 | 20 254 | 280 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | -------------------------------------------------------------------------------- /CuteComponent/ToolTip/CuteDesktopTip.cpp: -------------------------------------------------------------------------------- 1 | #include "CuteDesktopTip.h" 2 | #include 3 | #include 4 | //#include 5 | 6 | CuteDesktopTip *CuteDesktopTip::instance = nullptr; 7 | CuteDesktopTip::AnimationMode CuteDesktopTip::aniMode = CuteDesktopTip::AllAnimation; 8 | CuteDesktopTip::DisplayArea CuteDesktopTip::aniArea = CuteDesktopTip::RightBottomArea; 9 | 10 | CuteDesktopTip::CuteDesktopTip(QWidget *parent) 11 | : QDialog{parent} 12 | , form{new CuteDesktopTipForm(this)} 13 | , aniGroup{new QParallelAnimationGroup(this)} 14 | { 15 | setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip); 16 | setAttribute(Qt::WA_TranslucentBackground); 17 | setAttribute(Qt::WA_DeleteOnClose); 18 | // setWindowModality(Qt::WindowModal); 19 | 20 | // resize 会被 label 撑开 21 | this->setFixedSize(310,210); 22 | form->setFixedSize(310,210); 23 | 24 | // 关闭 25 | QPushButton *btn_close = form->findChild("close"); 26 | if (btn_close) { 27 | connect(btn_close, &QPushButton::clicked, this, &CuteDesktopTip::hideTip); 28 | } 29 | // 程序退出时释放 30 | connect(qApp, &QApplication::aboutToQuit, this, &CuteDesktopTip::close); 31 | // 动画设置 32 | initAnimation(); 33 | // 定时器设置 34 | initTimer(); 35 | // qDebug() << __FUNCTION__; 36 | } 37 | 38 | CuteDesktopTip::~CuteDesktopTip() 39 | { 40 | // qDebug() << __FUNCTION__; 41 | } 42 | 43 | CuteDesktopTip::AnimationMode CuteDesktopTip::getMode() 44 | { 45 | return aniMode; 46 | } 47 | 48 | void CuteDesktopTip::setMode(AnimationMode mode) 49 | { 50 | if (aniMode != mode) { 51 | aniMode = mode; 52 | } 53 | } 54 | 55 | CuteDesktopTip::DisplayArea CuteDesktopTip::getArea() 56 | { 57 | return aniArea; 58 | } 59 | 60 | void CuteDesktopTip::setArea(DisplayArea area) 61 | { 62 | if (aniArea != area) { 63 | aniArea = area; 64 | } 65 | } 66 | 67 | void CuteDesktopTip::showTip(const QString &title, const QString &text, int timeout) 68 | { 69 | if (!instance) { 70 | // 仅在ui线程 71 | instance = new CuteDesktopTip; 72 | } 73 | instance->readyTimer(timeout); 74 | // 模态框 75 | instance->setWindowModality(Qt::WindowModal); 76 | instance->setText(title, text); 77 | instance->showAnimation(); 78 | } 79 | 80 | void CuteDesktopTip::keepTip(const QString &title, const QString &text) 81 | { 82 | if (!instance) { 83 | // 仅在ui线程 84 | instance = new CuteDesktopTip; 85 | } 86 | instance->readyTimer(0); 87 | // 模态框 88 | instance->setWindowModality(Qt::WindowModal); 89 | instance->setText(title, text); 90 | instance->keepAnimation(); 91 | } 92 | 93 | void CuteDesktopTip::hideTip() 94 | { 95 | if (!instance) { 96 | return; 97 | } 98 | instance->hideAnimation(); 99 | } 100 | 101 | void CuteDesktopTip::initAnimation() 102 | { 103 | // 透明度动画,窗口才能设置透明度 104 | aniOpacity = new QPropertyAnimation(this, "windowOpacity"); 105 | // 判断是否设置了此模式的动画 106 | if (aniMode & AnimationMode::OpacityAnimation) { 107 | aniOpacity->setDuration(1500); 108 | aniOpacity->setStartValue(0); 109 | } else { 110 | aniOpacity->setDuration(0); 111 | aniOpacity->setStartValue(1); 112 | } 113 | aniOpacity->setEndValue(1); 114 | aniGroup->addAnimation(aniOpacity); 115 | 116 | // 位置动画 117 | aniPos = new QPropertyAnimation(form, "pos"); 118 | // 右下角放主屏,居中默认在当前窗口所在屏幕 119 | if (aniArea == DisplayArea::RightBottomArea) { 120 | QScreen *screen = QGuiApplication::primaryScreen(); 121 | if (screen) { 122 | QRect rect = screen->availableGeometry(); 123 | move(rect.right() - width(), rect.bottom() - height()); 124 | } 125 | } 126 | const QPoint hide_pos{0, form->height()}; 127 | const QPoint show_pos{0, 0}; 128 | // 判断是否设置了此模式的动画 129 | if (aniMode & AnimationMode::PosAnimation){ 130 | aniPos->setDuration(1500); 131 | aniPos->setStartValue(hide_pos); 132 | } else { 133 | aniPos->setDuration(0); 134 | aniPos->setStartValue(show_pos); 135 | } 136 | aniPos->setEndValue(show_pos); 137 | aniGroup->addAnimation(aniPos); 138 | // 139 | connect(aniGroup, &QParallelAnimationGroup::finished, [this]{ 140 | // back 消失动画结束关闭窗口 141 | if (aniGroup->direction() == QAbstractAnimation::Backward) { 142 | // Qt::WA_DeleteOnClose 后手动设置为 nullptr 143 | instance = nullptr; 144 | qApp->disconnect(this); 145 | // 关闭时设置为非模态,方式主窗口被遮挡,待测试 146 | this->setWindowModality(Qt::NonModal); 147 | this->close(); 148 | } else { 149 | // 配合 keepAnimation 150 | showAniEnd = true; 151 | //配合定时关闭 152 | if (hideCount > 0) { 153 | hideTimer->start(); 154 | } 155 | } 156 | }); 157 | } 158 | 159 | void CuteDesktopTip::initTimer() 160 | { 161 | hideTimer = new QTimer(this); 162 | // 1s 间隔 163 | hideTimer->setInterval(1000); 164 | connect(hideTimer, &QTimer::timeout, [this]{ 165 | QPushButton *btn_close = form->findChild("close"); 166 | if (hideCount > 1) { 167 | hideCount--; 168 | if (btn_close) { 169 | btn_close->setText(QString("%1 S").arg(hideCount)); 170 | } 171 | } else { 172 | if (btn_close) { 173 | btn_close->setText("Close"); 174 | } 175 | hideTimer->stop(); 176 | hideTip(); 177 | } 178 | }); 179 | } 180 | 181 | void CuteDesktopTip::readyTimer(int timeout) 182 | { 183 | // 先设置,在显示动画结束再 start 开始计时器 184 | hideCount = timeout; 185 | hideTimer->stop(); 186 | 187 | QPushButton *btn_close = form->findChild("close"); 188 | if (hideCount > 0) { 189 | if (btn_close) { 190 | btn_close->setText(QString("%1 S").arg(hideCount)); 191 | } 192 | } else { 193 | if (btn_close) { 194 | btn_close->setText("Close"); 195 | } 196 | } 197 | } 198 | 199 | void CuteDesktopTip::showAnimation() 200 | { 201 | aniGroup->setDirection(QAbstractAnimation::Forward); 202 | // 停止正在进行的动画重新 203 | if (aniGroup->state() == QAbstractAnimation::Running) { 204 | aniGroup->stop(); 205 | } 206 | aniGroup->start(); 207 | show(); 208 | } 209 | 210 | void CuteDesktopTip::keepAnimation() 211 | { 212 | // show 没有完成,或者正在动画中才进入 213 | if (!showAniEnd || aniGroup->state()!=QAbstractAnimation::Stopped) { 214 | aniGroup->setDirection(QAbstractAnimation::Forward); 215 | aniGroup->start(); 216 | show(); 217 | } 218 | } 219 | 220 | void CuteDesktopTip::hideAnimation() 221 | { 222 | // Backward 反向执行动画 223 | aniGroup->setDirection(QAbstractAnimation::Backward); 224 | aniGroup->start(); 225 | } 226 | 227 | void CuteDesktopTip::setText(const QString &title, const QString &text) 228 | { 229 | QLabel *title_label = form->findChild("title"); 230 | if (title_label) { 231 | title_label->setText(title); 232 | } 233 | QLabel *content_label = form->findChild("content"); 234 | if (content_label) { 235 | QString tip_text("

"); 236 | QStringList tip_list = text.split("\n"); 237 | for (const QString &line : tip_list) 238 | { 239 | if (line.isEmpty()) 240 | continue; 241 | tip_text += line + "
"; 242 | } 243 | tip_text += "

"; 244 | content_label->setText(tip_text); 245 | } 246 | } 247 | --------------------------------------------------------------------------------