From 63a3ea43a27ca4b88a70d7c619fbd4e0794ff560 Mon Sep 17 00:00:00 2001 From: wangqiang Date: Mon, 18 Nov 2024 11:05:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(QelSelect):=20=E6=B7=BB=E5=8A=A0=E4=B8=8B?= =?UTF-8?q?=E6=8B=89=E9=80=89=E6=8B=A9=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现了一个自定义的 QelSelect 组件,支持各种下拉选择功能 - 添加了 placeholder、clearable、disabled 和 filterable 属性 - 实现了自定义样式和鼠标事件处理 - 添加了测试用例和相关资源文件 --- QelSelect/QelSelect.cpp | 204 ++++++++++++++++++++++++ QelSelect/QelSelect.h | 54 +++++++ QelSelect/QelSelect.pri | 7 + QelSelect/QelSelect.pro | 21 +++ QelSelect/QelSelectTester.h | 82 ++++++++++ QelSelect/icons/arrow-down-disabled.svg | 3 + QelSelect/icons/arrow-down.svg | 3 + QelSelect/main.cpp | 10 ++ QelSelect/qelselect.qrc | 6 + QelSelectTester/main.cpp | 0 QelSelectTester/mainwindow.cpp | 0 QelSelectTester/mainwindow.h | 0 QelShow/QelShow.pro | 1 + QelShow/selectpage.h | 0 QtElementUI.pro | 2 +- 15 files changed, 392 insertions(+), 1 deletion(-) create mode 100644 QelSelect/QelSelect.cpp create mode 100644 QelSelect/QelSelect.h create mode 100644 QelSelect/QelSelect.pri create mode 100644 QelSelect/QelSelect.pro create mode 100644 QelSelect/QelSelectTester.h create mode 100644 QelSelect/icons/arrow-down-disabled.svg create mode 100644 QelSelect/icons/arrow-down.svg create mode 100644 QelSelect/main.cpp create mode 100644 QelSelect/qelselect.qrc create mode 100644 QelSelectTester/main.cpp create mode 100644 QelSelectTester/mainwindow.cpp create mode 100644 QelSelectTester/mainwindow.h create mode 100644 QelShow/selectpage.h diff --git a/QelSelect/QelSelect.cpp b/QelSelect/QelSelect.cpp new file mode 100644 index 0000000..9f9b8c4 --- /dev/null +++ b/QelSelect/QelSelect.cpp @@ -0,0 +1,204 @@ +#include "QelSelect.h" +#include +#include +#include + +QelSelect::QelSelect(QWidget* parent) + : QComboBox(parent) + , m_placeholder("") + , m_clearable(false) + , m_disabled(false) + , m_filterable(false) +{ + initUI(); + setupStyle(); +} + +void QelSelect::initUI() +{ + setEditable(true); + m_lineEdit = new QLineEdit(this); + setLineEdit(m_lineEdit); + + // 设置默认最小尺寸 + setMinimumSize(240, 32); + + // 设置下拉框弹出方式 + setMaxVisibleItems(6); // 最多显示6个选项 + setSizeAdjustPolicy(QComboBox::AdjustToContents); + view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + // 设置下拉框样式 + view()->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint); + view()->setAttribute(Qt::WA_TranslucentBackground); + + // 禁用 QLineEdit 的编辑功能,但保持其可见 + m_lineEdit->setReadOnly(true); + + // 连接信号槽 + connect(this, QOverload::of(&QComboBox::activated), + this, &QelSelect::handleActivated); +} + +void QelSelect::setupStyle() +{ + // 更新样式 + QString style = R"( + QelSelect { + border: 1px solid #dcdfe6; + border-radius: 4px; + padding: 0 30px 0 15px; + background-color: #ffffff; + min-height: 32px; + } + QelSelect:hover { + border-color: #c0c4cc; + } + QelSelect:focus { + border-color: #409eff; + } + QelSelect[disabled="true"] { + background-color: #f5f7fa; + border-color: #e4e7ed; + color: #c0c4cc; + cursor: not-allowed; + } + QelSelect::drop-down { + border: none; + width: 20px; + padding-right: 5px; + } + QelSelect::down-arrow { + image: url(:/icons/arrow-down.svg); + width: 12px; + height: 12px; + } + QelSelect::down-arrow:disabled { + image: url(:/icons/arrow-down-disabled.svg); + } + QelSelect QLineEdit { + border: none; + background: transparent; + padding: 0; + } + QelSelect QListView { + border: 1px solid #e4e7ed; + background: white; + border-radius: 4px; + padding: 6px 0; + margin-top: 5px; + } + QelSelect QListView::item { + height: 34px; + padding: 0 20px; + color: #606266; + } + QelSelect QListView::item:hover { + background: #f5f7fa; + } + QelSelect QListView::item:selected { + background: #f5f7fa; + color: #409eff; + } + )"; + + setStyleSheet(style); +} + +QString QelSelect::placeholder() const +{ + return m_placeholder; +} + +void QelSelect::setPlaceholder(const QString& placeholder) +{ + m_placeholder = placeholder; + if (m_lineEdit) + { + m_lineEdit->setPlaceholderText(placeholder); + } +} + +bool QelSelect::clearable() const +{ + return m_clearable; +} + +void QelSelect::setClearable(bool clearable) +{ + m_clearable = clearable; + if (m_lineEdit) + { + m_lineEdit->setClearButtonEnabled(clearable); + } +} + +bool QelSelect::isDisabled() const +{ + return m_disabled; +} + +void QelSelect::setDisabled(bool disabled) +{ + m_disabled = disabled; + QComboBox::setDisabled(disabled); +} + +bool QelSelect::filterable() const +{ + return m_filterable; +} + +void QelSelect::setFilterable(bool filterable) +{ + m_filterable = filterable; + setEditable(filterable); +} + +void QelSelect::paintEvent(QPaintEvent* event) +{ + QComboBox::paintEvent(event); + + // 绘制自定义样式 + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + + // 如果需要绘制其他内容,在这里添加 +} + +void QelSelect::focusInEvent(QFocusEvent* event) +{ + QComboBox::focusInEvent(event); + update(); +} + +void QelSelect::focusOutEvent(QFocusEvent* event) +{ + QComboBox::focusOutEvent(event); + update(); +} + +// 添加新的槽函数 +void QelSelect::handleActivated(int index) +{ + if (m_lineEdit && index >= 0) { + m_lineEdit->setText(itemText(index)); + } +} + +// 重写鼠标事件 +void QelSelect::mousePressEvent(QMouseEvent* event) +{ + if (!isEnabled()) { + return; + } + + // 显示或隐藏下拉列表 + if (!view()->isVisible()) { + showPopup(); + } else { + hidePopup(); + } + + event->accept(); +} diff --git a/QelSelect/QelSelect.h b/QelSelect/QelSelect.h new file mode 100644 index 0000000..67f35ff --- /dev/null +++ b/QelSelect/QelSelect.h @@ -0,0 +1,54 @@ +#ifndef QELSELECT_H +#define QELSELECT_H + +#include +#include +#include +#include +#include +#include + +class QelSelect : public QComboBox +{ + Q_OBJECT + Q_PROPERTY(QString placeholder READ placeholder WRITE setPlaceholder) + Q_PROPERTY(bool clearable READ clearable WRITE setClearable) + Q_PROPERTY(bool disabled READ isDisabled WRITE setDisabled) + Q_PROPERTY(bool filterable READ filterable WRITE setFilterable) + +public: + explicit QelSelect(QWidget* parent = nullptr); + + QString placeholder() const; + void setPlaceholder(const QString& placeholder); + + bool clearable() const; + void setClearable(bool clearable); + + bool isDisabled() const; + void setDisabled(bool disabled); + + bool filterable() const; + void setFilterable(bool filterable); + +protected: + void paintEvent(QPaintEvent* event) override; + void focusInEvent(QFocusEvent* event) override; + void focusOutEvent(QFocusEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; + +private slots: + void handleActivated(int index); + +private: + void initUI(); + void setupStyle(); + + QString m_placeholder; + bool m_clearable; + bool m_disabled; + bool m_filterable; + QLineEdit* m_lineEdit; +}; + +#endif // QELSELECT_H diff --git a/QelSelect/QelSelect.pri b/QelSelect/QelSelect.pri new file mode 100644 index 0000000..e1fe952 --- /dev/null +++ b/QelSelect/QelSelect.pri @@ -0,0 +1,7 @@ +HEADERS += \ + $$PWD/QelSelect.h + +SOURCES += \ + $$PWD/QelSelect.cpp + +INCLUDEPATH += $$PWD diff --git a/QelSelect/QelSelect.pro b/QelSelect/QelSelect.pro new file mode 100644 index 0000000..8622f58 --- /dev/null +++ b/QelSelect/QelSelect.pro @@ -0,0 +1,21 @@ +QT += core gui widgets + +TEMPLATE = app +CONFIG += c++17 + +SOURCES += \ + QelSelect.cpp \ + main.cpp + +HEADERS += \ + QelSelect.h \ + qelselecttester.h + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +INCLUDEPATH += $$PWD/../ + +RESOURCES += qelselect.qrc diff --git a/QelSelect/QelSelectTester.h b/QelSelect/QelSelectTester.h new file mode 100644 index 0000000..71d1d85 --- /dev/null +++ b/QelSelect/QelSelectTester.h @@ -0,0 +1,82 @@ +#ifndef QELSELECTTESTER_H +#define QELSELECTTESTER_H + +#include +#include +#include +#include +#include "QelSelect.h" + +class QelSelectTester : public QMainWindow +{ + Q_OBJECT + +public: + explicit QelSelectTester(QWidget *parent = nullptr) + : QMainWindow(parent) + { + QWidget *centralWidget = new QWidget(this); + setCentralWidget(centralWidget); + + QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget); + + // 基础用法 + QLabel *basicLabel = new QLabel("基础用法", this); + basicSelect = new QelSelect(this); + basicSelect->setPlaceholder("请选择"); + + // 禁用状态 + QLabel *disabledLabel = new QLabel("禁用状态", this); + disabledSelect = new QelSelect(this); + disabledSelect->setDisabled(true); + disabledSelect->setPlaceholder("禁用状态"); + + // 可清空选项 + QLabel *clearableLabel = new QLabel("可清空选项", this); + clearableSelect = new QelSelect(this); + clearableSelect->setClearable(true); + clearableSelect->setPlaceholder("可清空"); + + // 可筛选选项 + QLabel *filterableLabel = new QLabel("可筛选选项", this); + filterableSelect = new QelSelect(this); + filterableSelect->setFilterable(true); + filterableSelect->setPlaceholder("可筛选"); + + // 添加到布局 + mainLayout->addWidget(basicLabel); + mainLayout->addWidget(basicSelect); + mainLayout->addSpacing(20); + + mainLayout->addWidget(disabledLabel); + mainLayout->addWidget(disabledSelect); + mainLayout->addSpacing(20); + + mainLayout->addWidget(clearableLabel); + mainLayout->addWidget(clearableSelect); + mainLayout->addSpacing(20); + + mainLayout->addWidget(filterableLabel); + mainLayout->addWidget(filterableSelect); + + mainLayout->addStretch(); + + // 设置窗口大小 + resize(800, 600); + + // 添加示例选项 + QStringList options = {"选项1", "选项2", "选项3", "选项4", "选项5"}; + basicSelect->addItems(options); + disabledSelect->addItems(options); + clearableSelect->addItems(options); + filterableSelect->addItems(options); + } + +private: + QelSelect *basicSelect; + QelSelect *disabledSelect; + QelSelect *clearableSelect; + QelSelect *filterableSelect; +}; + +#endif // QELSELECTTESTER_H diff --git a/QelSelect/icons/arrow-down-disabled.svg b/QelSelect/icons/arrow-down-disabled.svg new file mode 100644 index 0000000..e5b8b2e --- /dev/null +++ b/QelSelect/icons/arrow-down-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/QelSelect/icons/arrow-down.svg b/QelSelect/icons/arrow-down.svg new file mode 100644 index 0000000..827d9e7 --- /dev/null +++ b/QelSelect/icons/arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/QelSelect/main.cpp b/QelSelect/main.cpp new file mode 100644 index 0000000..d71c4b6 --- /dev/null +++ b/QelSelect/main.cpp @@ -0,0 +1,10 @@ +#include +#include "QelSelectTester.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QelSelectTester w; + w.show(); + return a.exec(); +} diff --git a/QelSelect/qelselect.qrc b/QelSelect/qelselect.qrc new file mode 100644 index 0000000..3515b56 --- /dev/null +++ b/QelSelect/qelselect.qrc @@ -0,0 +1,6 @@ + + + icons/arrow-down.svg + icons/arrow-down-disabled.svg + + diff --git a/QelSelectTester/main.cpp b/QelSelectTester/main.cpp new file mode 100644 index 0000000..e69de29 diff --git a/QelSelectTester/mainwindow.cpp b/QelSelectTester/mainwindow.cpp new file mode 100644 index 0000000..e69de29 diff --git a/QelSelectTester/mainwindow.h b/QelSelectTester/mainwindow.h new file mode 100644 index 0000000..e69de29 diff --git a/QelShow/QelShow.pro b/QelShow/QelShow.pro index 7e5ed76..bbfa8cf 100644 --- a/QelShow/QelShow.pro +++ b/QelShow/QelShow.pro @@ -42,3 +42,4 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin include($$PWD/../QelButton/QelButton.pri)) include($$PWD/../QelIcon/QelIcon.pri)) include($$PWD/../QelNumberInput/QelNumberInput.pri)) +include($$PWD/../QelSelect/QelSelect.pri)) diff --git a/QelShow/selectpage.h b/QelShow/selectpage.h new file mode 100644 index 0000000..e69de29 diff --git a/QtElementUI.pro b/QtElementUI.pro index 56e9cea..486b020 100644 --- a/QtElementUI.pro +++ b/QtElementUI.pro @@ -4,5 +4,5 @@ SUBDIRS += \ QelIcon \ QelButton \ QelNumberInput \ + QelSelect \ QelShow -