浏览代码

V1.7.2
1、新增了DialogBase弹窗基础类
2、修改了Warning弹窗的关闭按钮大小,新增了调换确定和取消按钮的功能函数

Apple 9 小时之前
父节点
当前提交
d2f5efa0de

二进制
UI/warning/ICON/close.png


二进制
UI/warning/ICON/close_hover.png


+ 4 - 4
UI/warning/qss/warning_light.qss

@@ -60,8 +60,8 @@ QPushButton#pBtn_close{
 	/* border-image: url(:/ICON/ICON/Dialog_close.png); */
     background: transparent;
     border-radius: 4px;
-    qproperty-icon: url(:/ICON/Dialog_close.png);
-    qproperty-iconSize: 20px 20px;
+    qproperty-icon: url(:/ICON/close.png);
+    qproperty-iconSize: 32px 32px;
     padding-left: 0px;
     border: 0px solid #E6E9F4;
 }
@@ -71,8 +71,8 @@ QPushButton#pBtn_close[Hover = true]
 	/* border-image: url(:/ICON/ICON/Dialog_close2.png); */
     background: transparent;
     border-radius: 4px;
-    qproperty-icon: url(:/ICON/Dialog_close2.png);
-    qproperty-iconSize: 20px 20px;
+    qproperty-icon: url(:/ICON/close_hover.png);
+    qproperty-iconSize: 32px 32px;
     padding-left: 0px;
     border: 1px solid #438EFF;
 }

+ 8 - 0
UI/warning/warning.cpp

@@ -92,6 +92,14 @@ void Warning::setTextWithOneButton(const QString &text)
     moveWarnICON();
 }
 
+/* 对调确定按钮和取消按钮 */
+void Warning::swapOkCancelButton()
+{
+    QPoint tempPos = ui->pBtn_ok->pos();
+    ui->pBtn_ok->move(ui->pBtn_cancel->x(), ui->pBtn_cancel->y());
+    ui->pBtn_cancel->move(tempPos);
+}
+
 /* 设置QSS */
 void Warning::setQSS(const QString& qssPath)
 {

+ 4 - 1
UI/warning/warning.h

@@ -19,7 +19,10 @@ public:
 
     void setTitle(const QString& title);
     void setText(const QString& text);
-    void setTextWithOneButton(const QString& text);     /* 只有一个确定按钮 */
+    /* 只有一个确定按钮 */
+    void setTextWithOneButton(const QString& text);
+    /* 对调确定按钮和取消按钮 */
+    void swapOkCancelButton();
     bool isOk() const { return m_isOk; }
     /* 设置QSS */
     void setQSS(const QString& qssPath);

+ 2 - 2
UI/warning/warning.qrc

@@ -5,8 +5,8 @@
     <file>Tip/Failed2x.png</file>
     <file>Tip/Tips2x.png</file>
     <file>Tip/Wait2x.png</file>
-    <file>ICON/Dialog_close.png</file>
-    <file>ICON/Dialog_close2.png</file>
+    <file>ICON/close.png</file>
+    <file>ICON/close_hover.png</file>
   </qresource>
   <qresource prefix="/">
     <file>qss/warning_light.qss</file>

+ 435 - 0
common/DialogBase/DialogBase.cpp

@@ -0,0 +1,435 @@
+#include "DialogBase.h"
+
+#include <QMouseEvent>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QBoxLayout>
+#include <QStyle>
+#include <qsize.h>
+#include <QGuiApplication>
+#include <QScreen>
+
+
+#include "OneShadowEffect.h"
+
+
+DialogBase::DialogBase(QWidget *parent)
+    : QDialog(parent)
+{
+    m_logger = spdlog::get("ACASetting");
+    if(m_logger == nullptr)
+    {
+        fmt::print("DialogBase: 未发现ACASetting日志记录器,请检查日志记录器是否已初始化。\n");
+        return;
+    }
+
+    initUI();
+    initSettings();
+    /* 设置qss */
+    connect(&UIStyle, &UIStyleManager::signal_qssChanged, this, &DialogBase::do_setQSS);
+    /* 设置默认的UI */
+    setParentQSS();
+}
+
+DialogBase::DialogBase(bool isFullScreen, QWidget *parent)
+    : QDialog(parent), m_isFullScreen(isFullScreen)
+{
+    m_logger = spdlog::get("ACASetting");
+    if(m_logger == nullptr)
+    {
+        fmt::print("DialogBase: 未发现ACASetting日志记录器,请检查日志记录器是否已初始化。\n");
+        return;
+    }
+
+    initUI();
+    initSettings();
+    /* 设置qss */
+    connect(&UIStyle, &UIStyleManager::signal_qssChanged, this, &DialogBase::do_setQSS);
+    /* 设置默认的UI */
+    setParentQSS();
+}
+
+DialogBase::~DialogBase()
+{
+
+}
+
+/* 设置标题 */
+void DialogBase::setTitle(const QString &title, QSize size)
+{
+    m_labelTitle->setText(title);
+    m_labelTitle->setFixedSize(size);
+}
+
+/* 获取标题 */
+QString DialogBase::getTitle() const
+{
+    return m_labelTitle ? m_labelTitle->text() : QString();
+}
+
+/* 设置内容容器 */
+bool DialogBase::setContentWidget(QWidget *widget)
+{
+    if(widget == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "设置内容容器失败,widget为nullptr");
+        return false;
+    }
+    if(m_widgetContent == widget)
+    {
+        return true; // 如果已经是这个widget了,就不需要重新设置
+    }
+    if(m_widgetContent != nullptr)
+    {
+        m_layoutBackground->removeWidget(m_widgetContent);
+        delete m_widgetContent;
+        m_widgetContent = nullptr;
+    }
+    m_widgetContent = widget;
+    m_layoutBackground->insertWidget(1, m_widgetContent);
+    return true;
+}
+
+/* 设置低栏容器 */
+bool DialogBase::setBottomWidget(QWidget *widget)
+{
+    if(widget == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "设置底部容器失败,widget为nullptr");
+        return false;
+    }
+    if(m_widgetBottom != nullptr)
+    {
+        m_layoutBackground->removeWidget(m_widgetBottom);
+        delete m_widgetBottom;
+        m_widgetBottom = nullptr;
+    }
+    m_widgetBottom = widget;
+    m_layoutBackground->insertWidget(2, m_widgetBottom);
+
+    return true;
+}
+
+/* 移除底栏 */
+bool DialogBase::removeBottomWidget()
+{
+    if(m_widgetBottom == nullptr)
+    {
+        return true;
+    }
+    m_layoutBackground->removeWidget(m_widgetBottom);
+    delete m_widgetBottom;
+    m_widgetBottom = nullptr;
+
+    return true;
+}
+
+/* 点击确定按钮之前执行的操作 */
+bool DialogBase::isOKClicked()
+{
+    /* 默认返回true,子类可以重载这个函数来实现自定义的逻辑 */
+    return true;
+}
+
+/* 点击关闭按钮之后执行的操作 */
+bool DialogBase::isCloseClicked()
+{
+    /* 默认什么都不做,子类可以重载这个函数来实现自定义的逻辑 */
+    return true;
+}
+
+/* 设置一个控件报警,边框显示红色
+ * 注意:这个功能需要在qss里设置属性[Warn=true],并实现相应的报警样式 */
+void DialogBase::setWarn(QWidget* widget, bool isWarn)
+{
+    if(widget == nullptr)
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "设置控件报警失败,widget为nullptr");
+        return;
+    }
+    widget->setProperty("Warn", isWarn);
+    widget->style()->unpolish(widget);
+    widget->style()->polish(widget);
+    widget->update();
+}
+
+/* 初始化UI */
+void DialogBase::initUI()
+{
+    /*--------------------- 设置对话框的属性 -----------------------*/
+    this->setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
+    this->setAttribute(Qt::WA_TranslucentBackground, true);
+    // this->setObjectName("DialogBase");
+
+
+    /*--------------------- 初始化背景容器 -----------------------*/
+    /* 如果需要背后接近透明的全屏遮罩,就设置为true,在this和m_widgetBackground之间添加
+     * 一层接近透明的遮罩 */
+    if(m_isFullScreen)
+    {
+        auto screenRect = QGuiApplication::screenAt(QCursor::pos())->geometry();
+        this->resize(screenRect.width(), screenRect.height());
+        /* 创建最外层的透明背景 */ 
+        m_widgetTransparent = new QWidget(this);
+        m_widgetTransparent->setObjectName("widget_transparent");
+        m_widgetTransparent->setStyleSheet(R"(
+            QWidget#widget_transparent {background: rgba(0, 0, 0, 0.01)};
+        )");
+
+        m_widgetTransparent->resize(screenRect.width(), screenRect.height());
+        m_widgetTransparent->move(0, 0);
+    }
+
+    /* 创建真正的容器 */
+    m_widgetBackground = new QWidget(this);
+    m_widgetBackground->setObjectName("widget_content__");
+    // m_widgetBackground->resize(400, 300);
+    /* 判断m_widgetBackground是哪一层 */
+    if(m_isFullScreen)
+    {
+        m_widgetBackground->setParent(m_widgetTransparent);
+        /* 设置设置区域居中显示 */
+        m_widgetBackground->move(m_widgetTransparent->width() / 2 - m_widgetBackground->width() / 2,
+            m_widgetTransparent->height() / 2 - m_widgetBackground->height() / 2);
+    }else {
+        QVBoxLayout* layout = new QVBoxLayout(this);
+        /* 设置边距,就是阴影的宽度 */
+        layout->setContentsMargins(20, 20, 20, 20);
+        layout->setSpacing(0);
+        this->setLayout(layout);
+        layout->addWidget(m_widgetBackground);
+    }
+
+    /* 创建背景容器内部的布局 */
+    m_layoutBackground = new QVBoxLayout(m_widgetBackground);
+    m_layoutBackground->setContentsMargins(0, 0, 0, 0);
+    m_layoutBackground->setSpacing(0);
+    m_widgetBackground->setLayout(m_layoutBackground);
+
+    /*--------------------- 初始顶栏 -----------------------*/
+    /* 初始化顶部标题栏,高度56,下面分割线高度1 */
+    m_widgetTop = new QWidget(this);
+    m_widgetTop->setObjectName("widget_top");
+    m_widgetTop->setFixedHeight(56);
+    m_layoutBackground->addWidget(m_widgetTop);
+    QHBoxLayout* topHBoxLayout = new QHBoxLayout(m_widgetTop);
+    m_widgetTop->setLayout(topHBoxLayout);
+
+    /* 初始化标题栏 */
+    m_labelTitle = new QLabel(m_widgetTop);
+    m_labelTitle->setObjectName("label_title");
+    m_labelTitle->setText("Dialog Title");
+    m_labelTitle->setFixedSize(120, 18);
+    m_labelTitle->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+    /* 初始化关闭按钮 */
+    m_pBtn_Close = new QPushButton(m_widgetTop);
+    m_pBtn_Close->setObjectName("pBtn_Close");
+    m_pBtn_Close->resize(32, 32);
+    /* 安装事件过滤器,主要是处理鼠标悬停事件 */
+    m_pBtn_Close->installEventFilter(this);
+    /* 重新布局顶栏 */
+    layoutTop();
+
+    /*--------------------- 初始化内容栏 -----------------------*/
+    // m_widgetContent = new QWidget(this);
+    // m_widgetContent->resize(400, 300);
+    // m_layoutBackground->addWidget(m_widgetContent);
+
+    /*--------------------- 初始底栏 -----------------------*/
+    m_widgetBottom = new QWidget(this);
+    m_widgetBottom->setObjectName("widget_bottom");
+    m_widgetBottom->setFixedHeight(88);
+    m_layoutBackground->addWidget(m_widgetBottom);
+    QHBoxLayout* bottomHBoxLayout = new QHBoxLayout(m_widgetBottom);
+    m_widgetBottom->setLayout(bottomHBoxLayout);
+    /* 初始化取消按钮 */
+    m_pBtn_Cancel = new QPushButton(m_widgetBottom);
+    m_pBtn_Cancel->setObjectName("pBtn_Cancel");
+    m_pBtn_Cancel->setText("取消");
+    m_pBtn_Cancel->setFixedSize(60, 32);
+    bottomHBoxLayout->addWidget(m_pBtn_Cancel, 0, Qt::AlignRight | Qt::AlignVCenter);
+    /* 初始化确认按钮 */
+    m_pBtn_OK = new QPushButton(m_widgetBottom);
+    m_pBtn_OK->setObjectName("pBtn_OK");
+    m_pBtn_OK->setText("确定");
+    m_pBtn_OK->setFixedSize(60, 32);
+    bottomHBoxLayout->addWidget(m_pBtn_OK, 0, Qt::AlignRight | Qt::AlignVCenter);
+    /* 添加一个底部横向弹簧 */
+    bottomHBoxLayout->insertStretch(0, 1);
+    /* 设置底部按钮的间距 */
+    bottomHBoxLayout->setContentsMargins(32, 24, 32, 32);
+    bottomHBoxLayout->setSpacing(16);
+    
+    /*--------------------- 创建阴影 -----------------------*/
+    auto pShadow = new OneShadowEffect(this);
+    m_widgetBackground->setGraphicsEffect(pShadow);
+
+}
+
+/* 初始化其他设置 */
+void DialogBase::initSettings()
+{
+    /* 初始化变量 */
+    m_lastPos = QPoint(0, 0);
+    /* 连接信号和槽 */
+    connect(m_pBtn_Close, &QPushButton::clicked, this, &DialogBase::do_pBtn_Close_Clicked);
+    connect(m_pBtn_OK, &QPushButton::clicked, this, &DialogBase::do_pBtn_OK_Clicked);
+    connect(m_pBtn_Cancel, &QPushButton::clicked, this, &DialogBase::do_pBtnCancel_clicked);
+
+    /* 设置样式表 */
+    setParentQSS();
+}
+
+/* 加载QSS */
+void DialogBase::setParentQSS()
+{
+    /* 获取样式表路径 */
+    QString qssPath = UIStyle.getQSSPath() + "/dialogbase.qss";
+    QFile file(qssPath);
+    if(file.open(QFile::ReadOnly))
+    {
+        QString qss = file.readAll();
+        file.close();
+        m_widgetBackground->setStyleSheet(qss);
+    } else
+    {
+        SPDLOG_LOGGER_ERROR(m_logger, "打开QSS文件失败: {}", qssPath.toStdString());
+        SPDLOG_LOGGER_ERROR(m_logger, "错误信息: {}", file.errorString().toStdString());
+    }
+}
+
+/* 设置top栏的位置布局,标题和关闭按钮的高度起始位置不一样,不方便使用布局,所有手动修改坐标
+ * 标题位置32,18,高度18
+ * 关闭按钮右对齐16,y12,大小32x32 */
+void DialogBase::layoutTop()
+{
+    m_labelTitle->move(32, 18);
+    int x = m_widgetTop->width() - m_pBtn_Close->width() - 16;
+    m_pBtn_Close->move(x, 12);
+}
+
+
+/* 关闭按钮点击事件 */
+void DialogBase::do_pBtn_Close_Clicked()
+{
+    if(!isCloseClicked())
+    {
+        /* 如果子类没有重载这个函数,默认返回true */
+        return;
+    }
+    this->close();
+}
+
+/* 确认按钮点击事件 */
+void DialogBase::do_pBtn_OK_Clicked()
+{
+    if(!isOKClicked())
+    {
+        /* 如果子类没有重载这个函数,默认返回true */
+        return;
+    }
+    m_isOK = true;
+    this->accept();
+}
+
+/* 设置QSS */
+void DialogBase::do_setQSS(EUIStyle style)
+{
+    setParentQSS();
+}
+
+/* 重写鼠标按下事件 */
+void DialogBase::mousePressEvent(QMouseEvent *event)
+{
+    m_lastPos = event->globalPos();
+    event->accept();
+}
+
+/* 重写鼠标移动事件 */
+void DialogBase::mouseMoveEvent(QMouseEvent *event)
+{
+    auto point = m_widgetTop->mapToGlobal(QPoint(0, 0));
+    QRect rect(point, m_widgetTop->size());
+
+    if(!rect.contains(m_lastPos))
+    {
+        event->accept();
+        return;
+    }
+
+    int dx = event->globalX() - m_lastPos.x();
+    int dy = event->globalY() - m_lastPos.y();
+    if(m_isFullScreen)
+    {
+        m_widgetBackground->move(m_widgetBackground->x() + dx, m_widgetBackground->y() + dy);
+    }else {
+        move(x() + dx, y() + dy);
+    }
+    
+    m_lastPos = event->globalPos();
+    event->accept();
+}
+
+/* 重写鼠标释放事件 */
+void DialogBase::mouseReleaseEvent(QMouseEvent *event)
+{
+    event->accept();
+}
+
+/* 显示事件 */
+void DialogBase::showEvent(QShowEvent *event)
+{
+    QDialog::showEvent(event);
+
+    if(m_isFullScreen)
+    {
+        /* 设置设置区域居中显示 */
+        m_widgetBackground->move(m_widgetTransparent->width() / 2 - m_widgetBackground->width() / 2,
+            m_widgetTransparent->height() / 2 - m_widgetBackground->height() / 2);
+    }
+
+    /* 重新布局顶栏 */
+    layoutTop();
+    
+}
+
+
+/* 重新设置大小 */
+void DialogBase::resizeEvent(QResizeEvent *event)
+{
+    QDialog::resizeEvent(event);
+
+    if(m_isFullScreen)
+    {
+        /* 设置设置区域居中显示 */
+        m_widgetBackground->move(m_widgetTransparent->width() / 2 - m_widgetBackground->width() / 2,
+            m_widgetTransparent->height() / 2 - m_widgetBackground->height() / 2);
+    }
+    
+    /* 重新布局顶栏 */ 
+    layoutTop();
+}
+
+/* 事件过滤器 */
+bool DialogBase::eventFilter(QObject *watched, QEvent *event)
+{
+    if(watched == m_pBtn_Close && event->type() == QEvent::HoverEnter)
+    {
+        m_pBtn_Close->setProperty("Hover", true);
+        m_pBtn_Close->style()->unpolish(m_pBtn_Close);
+        m_pBtn_Close->style()->polish(m_pBtn_Close);
+        m_pBtn_Close->update();
+        return true;
+    }
+    else if(watched == m_pBtn_Close && event->type() == QEvent::HoverLeave)
+    {
+        m_pBtn_Close->setProperty("Hover", false);
+        m_pBtn_Close->style()->unpolish(m_pBtn_Close);
+        m_pBtn_Close->style()->polish(m_pBtn_Close);
+        m_pBtn_Close->update();
+        return true;
+    }
+    return QDialog::eventFilter(watched, event);
+}
+

+ 133 - 0
common/DialogBase/DialogBase.h

@@ -0,0 +1,133 @@
+#ifndef __DIALOGBASE_H__
+#define __DIALOGBASE_H__
+
+#include <QDialog>
+#include "spdlog/spdlog.h"
+#include "UIStyleManager.h"
+
+class QMouseEvent;
+class QVBoxLayout;
+class QPushButton;
+class QWidget;
+class QLabel;
+class QPoint;
+
+
+/**
+    这个基础类主要为了实现弹窗通用的拖动和阴影效果
+        1、父类的QSS通过信号来主动设置,避免和子类冲突
+    使用方法:
+        1、正常创建UI文件及其.h/.cpp文件
+        2、继承DialogBase类
+        3、创建一个新的QWidget初始化UI,然后通过setContentWidget()设置内容区域
+            QWidget* contentWidget = new QWidget(this);
+            ui->setupUi(contentWidget);
+            // 设置内容
+            this->setContentWidget(contentWidget);
+
+        4、默认带有两个按钮的底部区域,保存条件可以通过isOKClicked()函数重载来实现
+            如果不需要底部区域,可以通过removeBottomWidget()移除,如果底部区域需要自定义,
+            建议直接搞在内容区域里,比较方便
+
+ */
+class DialogBase : public QDialog
+{
+    Q_OBJECT
+public:
+    explicit DialogBase(QWidget *parent = nullptr);
+    explicit DialogBase(bool isFullScreen, QWidget *parent = nullptr);
+    virtual ~DialogBase();
+
+    /* 设置标题 */
+    void setTitle(const QString &title, QSize size = QSize(120, 18));
+
+    /* 获取标题 */
+    QString getTitle() const;
+    /* 获取是否点击了确定按钮 */
+    virtual bool isOK() const { return m_isOK; }
+
+protected:
+    /* --------------------------------------------------
+     * 给子类使用的内部接口
+     * --------------------------------------------------*/
+    /* 设置内容容器 */
+    bool setContentWidget(QWidget *widget);
+    /* 设置底栏容器 */
+    bool setBottomWidget(QWidget *widget);
+    /* 移除底栏 */
+    bool removeBottomWidget();
+
+    /* 获取内容指针 */
+    QWidget* getContentWidget() const { return m_widgetContent; }
+    /* 获取底部容器指针 */
+    QWidget* getBottomWidget() const { return m_widgetBottom; }
+
+    /* 点击确定按钮之后执行的操作 */
+    virtual bool isOKClicked();
+    /* 点击关闭按钮之后执行的操作 */
+    virtual bool isCloseClicked();
+
+    /* 设置一个控件报警,边框显示红色
+     * 注意:这个功能需要在qss里设置属性[Warn=true],并实现相应的报警样式 */
+    void setWarn(QWidget* widget, bool isWarn = true);
+
+protected:
+    /* 初始化UI */
+    virtual void initUI();
+    /* 初始化其他设置 */
+    virtual void initSettings();
+    /* 加载QSS */
+    virtual void setParentQSS();
+    /* 设置top栏的位置布局 */
+    void layoutTop();
+
+protected slots:
+    /* 关闭按钮点击事件 */
+    void do_pBtn_Close_Clicked();
+    /* 确认按钮点击事件 */
+    void do_pBtn_OK_Clicked();
+    /* 取消按钮点击事件 */
+    void do_pBtnCancel_clicked() { this->reject(); }
+
+    /* 设置QSS */
+    void do_setQSS(EUIStyle style);
+
+protected:
+    /* 重写鼠标按下事件 */
+    void mousePressEvent(QMouseEvent *event) override;
+    /* 重写鼠标移动事件 */
+    void mouseMoveEvent(QMouseEvent *event) override;
+    /* 重写鼠标释放事件 */
+    void mouseReleaseEvent(QMouseEvent *event) override;
+    /* 显示事件 */
+    void showEvent(QShowEvent *event) override;
+    /* 重新设置大小 */
+    void resizeEvent(QResizeEvent *event) override;
+
+    /* 事件过滤器 */
+    bool eventFilter(QObject *watched, QEvent *event) override;
+
+protected:
+    std::shared_ptr<spdlog::logger> m_logger = nullptr;
+    bool m_isOK = false;                        /* 是否点击了确认按钮 */
+private:
+    bool m_isFullScreen = false;                /* 是否全屏显示,给时间选择和日期选择弹窗使用的,设置背后透明背景全屏 */
+    QPoint m_lastPos;                           /* 鼠标点击的位置 */
+
+    QWidget* m_widgetTransparent = nullptr;     /* 透明背景容器,在m_widgetBackground下面,全屏时,
+                                                    m_widgetBackground在这个透明容器中移动 */
+    QWidget* m_widgetBackground = nullptr;      /* 背景容器,这个才是真正容纳所有内容的容器 */
+    QWidget* m_widgetTop = nullptr;             /* 顶部标题栏 */
+    QWidget* m_widgetContent = nullptr;         /* 内容区域 */
+    QWidget* m_widgetBottom = nullptr;          /* 底部按钮区域 */
+
+    QVBoxLayout* m_layoutBackground = nullptr; /* 背景容器的布局 */
+
+    QLabel* m_labelTitle = nullptr;             /* 标题标签 */
+    QPushButton* m_pBtn_Close = nullptr;        /* 关闭按钮 */
+    QPushButton* m_pBtn_OK = nullptr;           /* 确认按钮 */
+    QPushButton* m_pBtn_Cancel = nullptr;       /* 取消按钮 */
+};
+
+
+#endif // __DIALOGBASE_H__