#include "MultiSelectComboBox.h" #include #include #include #include #include #include #include #include MultiSelectComboBox::MultiSelectComboBox(QWidget *parent) : QComboBox(parent), skipNextHide(false) { initialize(); } MultiSelectComboBox::~MultiSelectComboBox() {} void MultiSelectComboBox::initialize() { // Set up the model setModel(new QStandardItemModel(this)); // Set up the view QListView *listView = new QListView(this); setView(listView); // Make the combo box read-only but clickable setEditable(true); setInsertPolicy(QComboBox::NoInsert); lineEdit()->setReadOnly(true); // 设置输入框样式,使其看起来可点击 lineEdit()->setCursor(Qt::PointingHandCursor); lineEdit()->setStyleSheet("QLineEdit { background-color: white; }"); // Install event filter to handle mouse events view()->viewport()->installEventFilter(this); lineEdit()->installEventFilter(this); // Connect to the item changed signal connect(model(), &QStandardItemModel::itemChanged, this, &MultiSelectComboBox::onItemChanged); // Set minimum width for better display setMinimumWidth(150); // Set the default text updateText(); } void MultiSelectComboBox::addItem(const QString &key, const QString &value) { QStandardItem *item = new QStandardItem(value); item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); item->setData(Qt::Unchecked, Qt::CheckStateRole); item->setData(key, Qt::UserRole); model()->appendRow(item); updateText(); } void MultiSelectComboBox::addItems(const QList> &items) { for (const auto &item : items) { addItem(item.first, item.second); } } QStringList MultiSelectComboBox::checkedKeys() const { QStringList keys; for (int i = 0; i < model()->rowCount(); ++i) { QStandardItem *item = model()->item(i); if (item->checkState() == Qt::Checked) { keys.append(item->data(Qt::UserRole).toString()); } } return keys; } QList> MultiSelectComboBox::checkedItemsWithKeys() const { QList> items; for (int i = 0; i < model()->rowCount(); ++i) { QStandardItem *item = model()->item(i); if (item->checkState() == Qt::Checked) { items.append({item->data(Qt::UserRole).toString(), item->text()}); } } return items; } void MultiSelectComboBox::setCheckedKeys(const QStringList &keys) { for (int i = 0; i < model()->rowCount(); ++i) { QStandardItem *item = model()->item(i); QString key = item->data(Qt::UserRole).toString(); item->setData(keys.contains(key) ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); } updateText(); } bool MultiSelectComboBox::eventFilter(QObject *object, QEvent *event) { if (object == view()->viewport()) { if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::LeftButton) { QModelIndex index = view()->indexAt(mouseEvent->pos()); if (index.isValid()) { // 切换选中状态 QStandardItem *item = model()->itemFromIndex(index); if (item) { Qt::CheckState currentState = static_cast(item->data(Qt::CheckStateRole).toInt()); Qt::CheckState newState = (currentState == Qt::Checked) ? Qt::Unchecked : Qt::Checked; item->setData(newState, Qt::CheckStateRole); // 防止点击选项后立即关闭弹出菜单 skipNextHide = true; return true; // 阻止默认处理 } } } } if (event->type() == QEvent::MouseButtonRelease) { // 防止点击选项后立即关闭弹出菜单 skipNextHide = true; return false; } } else if (object == lineEdit()) { if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::LeftButton) { if (!view()->isVisible()) { showPopup(); } else { hidePopup(); } return true; // 事件已处理 } } } return QComboBox::eventFilter(object, event); } void MultiSelectComboBox::showPopup() { QComboBox::showPopup(); } void MultiSelectComboBox::hidePopup() { if (skipNextHide) { skipNextHide = false; return; } QComboBox::hidePopup(); } void MultiSelectComboBox::mousePressEvent(QMouseEvent *event) { // 如果点击的是输入框区域,显示弹出菜单 if (event->button() == Qt::LeftButton) { if (!view()->isVisible()) { showPopup(); } else { hidePopup(); } event->accept(); return; } // 其他情况调用父类方法 QComboBox::mousePressEvent(event); } void MultiSelectComboBox::onItemChanged(QStandardItem *item) { Q_UNUSED(item); updateText(); } void MultiSelectComboBox::updateText() { QStringList texts; for (int i = 0; i < model()->rowCount(); ++i) { QStandardItem *item = model()->item(i); if (item->checkState() == Qt::Checked) { texts.append(item->text()); } } displayText = texts.isEmpty() ? "请选择..." : texts.join(", "); setEditText(displayText); emit selectionChanged(); } void MultiSelectComboBox::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QStylePainter painter(this); painter.setPen(palette().color(QPalette::Text)); // Draw the combobox frame, focusrect and selected etc. QStyleOptionComboBox opt; initStyleOption(&opt); // If we have selected items, use displayText, otherwise use placeholderText if (!displayText.isEmpty()) { opt.currentText = displayText; } else { opt.currentText = "Select items..."; } painter.drawComplexControl(QStyle::CC_ComboBox, opt); painter.drawControl(QStyle::CE_ComboBoxLabel, opt); } QStandardItemModel *MultiSelectComboBox::model() const { return qobject_cast(QComboBox::model()); }