QComboBox下拉界面带勾选
1、前言
QComboBox每次只能选择一个,现项目中需要可以多次勾选,不想基于第三方库qxtlib进行开发,所以自己参考qxtcheckcombobox源码,在此基础上进行修改。可保持QComboBox风格,不另行设置界面。
2、实现效果如下
3、思路
主体思路就是对于下拉的数据源model的数据标志位添加可勾选属性。
下面列举一些Qt::ItemDataRole
Constant | Value | Description |
---|---|---|
Qt::FontRole | 6 | The font used for items rendered with the default delegate. (QFont) |
Qt::TextAlignmentRole | 7 | The alignment of the text for items rendered with the default delegate. (Qt::Alignment) |
Qt::BackgroundRole | 8 | The background brush used for items rendered with the default delegate. (QBrush) |
Qt::BackgroundColorRole | 8 | This role is obsolete. Use BackgroundRole instead. |
Qt::ForegroundRole | 9 | The foreground brush (text color, typically) used for items rendered with the default delegate. (QBrush) |
Qt::TextColorRole | 9 | This role is obsolete. Use ForegroundRole instead. |
Qt::CheckStateRole | 10 | This role is used to obtain the checked state of an item. (Qt::CheckState) |
Qt::InitialSortOrderRole | 14 | This role is used to obtain the initial sort order of a header view section. (Qt::SortOrder). This role was introduced in Qt 4.8. |
4、代码干货
以下代码仅供参考,可根据实际需求修改
class DSCheckComboModel : public QStandardItemModel
{
Q_OBJECT
public:
explicit DSCheckComboModel(QObject* parent = Q_NULLPTR);
virtual Qt::ItemFlags flags(const QModelIndex& index) const;
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
Q_SIGNALS:
void checkStateChanged();
};
class DSCheckComboBoxPrivate;
class DSCheckComboBox : public QComboBox
{
Q_OBJECT
Q_PROPERTY(QString separator READ separator WRITE setSeparator)
Q_PROPERTY(QString defaultText READ defaultText WRITE setDefaultText)
Q_PROPERTY(QStringList checkedItems READ checkedItems WRITE setCheckedItems)
public:
DSCheckComboBox(QWidget *parent = Q_NULLPTR);
~DSCheckComboBox();
//隐藏下拉框
virtual void hidePopup();
//获取默认文本
QString defaultText() const;
//设置默认文本
void setDefaultText(const QString& text);
//获取勾选状态
Qt::CheckState itemCheckState(int index) const;
//设置勾选状态
void setItemCheckState(int index, Qt::CheckState state);
//获取字符串分割方式
QString separator() const;
//设置字符串分割方式
void setSeparator(const QString& separator);
//获取所有勾选的文本
QStringList checkedItems() const;
//获取所有勾线的下标
QVariantList checkedIndexs() const;
public Q_SLOTS:
void setCheckedItems(const QStringList& items);
Q_SIGNALS:
void checkedItemsChanged(const QStringList& items);
protected:
virtual bool eventFilter(QObject *watched, QEvent *event);
virtual void wheelEvent(QWheelEvent *e);
private:
QScopedPointer<DSCheckComboBoxPrivate> d_ptr;
Q_DISABLE_COPY(DSCheckComboBox)
Q_DECLARE_PRIVATE(DSCheckComboBox)
Q_PRIVATE_SLOT(d_func(), void updateCheckedItems())
Q_PRIVATE_SLOT(d_func(), void toggleCheckState(int index))
};
DSCheckComboModel::DSCheckComboModel(QObject* parent /* = Q_NULLPTR */)
: QStandardItemModel(0, 1, parent) //rows,cols
{
}
Qt::ItemFlags DSCheckComboModel::flags(const QModelIndex& index) const
{
return QStandardItemModel::flags(index) | Qt::ItemIsUserCheckable;
}
QVariant DSCheckComboModel::data(const QModelIndex& index, int role /* = Qt::DisplayRole */) const
{
QVariant value = QStandardItemModel::data(index, role);
if (index.isValid() && role == Qt::CheckStateRole && !value.isValid())
value = Qt::Unchecked;
return value;
}
bool DSCheckComboModel::setData(const QModelIndex& index, const QVariant& value, int role /* = Qt::EditRole */)
{
bool ok = QStandardItemModel::setData(index, value, role);
if (ok && role == Qt::CheckStateRole)
{
emit dataChanged(index, index);
emit checkStateChanged();
}
return ok;
}
class DSCheckComboBoxPrivate : public QObject
{
Q_DECLARE_PUBLIC(DSCheckComboBox)
DSCheckComboBox* q_ptr;
public:
DSCheckComboBoxPrivate(QObject* parent = Q_NULLPTR);
bool eventFilter(QObject* obj, QEvent* e);
QString separator;
QString defaultText;
bool containerMousePress;
void updateCheckedItems();
void toggleCheckState(int index);
};
DSCheckComboBoxPrivate::DSCheckComboBoxPrivate(QObject* parent)
: containerMousePress(false)
{
separator = QLatin1String(",");
}
bool DSCheckComboBoxPrivate::eventFilter(QObject* obj, QEvent* e)
{
switch (e->type())
{
case QEvent::KeyPress:
case QEvent::KeyRelease:
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e);
if (obj == q_ptr && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down))
{
q_ptr->showPopup();
return true;
}
else if (keyEvent->key() == Qt::Key_Enter ||
keyEvent->key() == Qt::Key_Return ||
keyEvent->key() == Qt::Key_Escape)
{
q_ptr->hidePopup();
if (keyEvent->type() != Qt::Key_Escape)
return true;
}
}
case QEvent::MouseButtonPress:
containerMousePress = (obj == q_ptr->view()->window());
break;
case QEvent::MouseButtonRelease:
containerMousePress = false;
break;
default:
break;
}
return false;
}
void DSCheckComboBoxPrivate::updateCheckedItems()
{
QStringList items = q_ptr->checkedItems();
if (items.empty())
q_ptr->setEditText(defaultText);
else
q_ptr->setEditText(items.join(separator));
emit q_ptr->checkedItemsChanged(items);
}
void DSCheckComboBoxPrivate::toggleCheckState(int index)
{
QVariant value = q_ptr->itemData(index, Qt::CheckStateRole);
if (value.isValid())
{
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
q_ptr->setItemData(index, (state == Qt::Unchecked ? Qt::Checked : Qt::Unchecked), Qt::CheckStateRole);
}
}
DSCheckComboBox::DSCheckComboBox(QWidget *parent)
: QComboBox(parent)
, d_ptr(new DSCheckComboBoxPrivate)
{
d_ptr->q_ptr = this;
setModel(new DSCheckComboModel(this));
connect(this, SIGNAL(activated(int)), this, SLOT(toggleCheckState(int)));
connect(model(), SIGNAL(checkStateChanged()), this, SLOT(updateCheckedItems()));
connect(model(), SIGNAL(rowsInserted(const QModelIndex&, int, int)), this, SLOT(updateCheckedItems()));
connect(model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)), this, SLOT(updateCheckedItems()));
QLineEdit* lineEdit = new QLineEdit(this);
lineEdit->setReadOnly(true);
setLineEdit(lineEdit);
lineEdit->disconnect(this);
setInsertPolicy(QComboBox::NoInsert);
installEventFilter(this);
view()->installEventFilter(this);
view()->window()->installEventFilter(this);
view()->viewport()->installEventFilter(this);
}
DSCheckComboBox::~DSCheckComboBox()
{
}
void DSCheckComboBox::hidePopup()
{
if (d_ptr->containerMousePress)
QComboBox::hidePopup();
}
Qt::CheckState DSCheckComboBox::itemCheckState(int index) const
{
return static_cast<Qt::CheckState>(itemData(index, Qt::CheckStateRole).toInt());
}
void DSCheckComboBox::setItemCheckState(int index, Qt::CheckState state)
{
setItemData(index, state, Qt::CheckStateRole);
}
QStringList DSCheckComboBox::checkedItems() const
{
QStringList items;
if (model())
{
QModelIndex index = model()->index(0, modelColumn(), rootModelIndex());
QModelIndexList indexs = model()->match(index, Qt::CheckStateRole, Qt::Checked, -1, Qt::MatchExactly);
foreach(const QModelIndex& index, indexs)
items += index.data().toString();
}
return items;
}
QVariantList DSCheckComboBox::checkedIndexs() const
{
QVariantList indexs;
if (model())
{
QModelIndex index = model()->index(0, modelColumn(), rootModelIndex());
QModelIndexList indexs_2 = model()->match(index, Qt::CheckStateRole, Qt::Checked, -1, Qt::MatchExactly);
foreach(const QModelIndex& index, indexs_2)
indexs += index.row();
}
return indexs;
}
void DSCheckComboBox::setCheckedItems(const QStringList& items)
{
foreach(const QString& text, items)
{
const int index = findText(text);
setItemCheckState(index, index != -1 ? Qt::Checked : Qt::Unchecked);
}
}
bool DSCheckComboBox::eventFilter(QObject *watched, QEvent *event)
{
return d_ptr->eventFilter(watched,event);
}
void DSCheckComboBox::wheelEvent(QWheelEvent *e)
{
e->accept();
}
QString DSCheckComboBox::defaultText() const
{
return d_ptr->defaultText;
}
void DSCheckComboBox::setDefaultText(const QString& text)
{
if (d_ptr->defaultText != text)
{
d_ptr->defaultText = text;
d_ptr->updateCheckedItems();
}
}
QString DSCheckComboBox::separator() const
{
return d_ptr->separator;
}
void DSCheckComboBox::setSeparator(const QString& separator)
{
if (d_ptr->separator != separator)
{
d_ptr->separator = separator;
d_ptr->updateCheckedItems();
}
}
以上代码大家可只做参考。
5、注意事项
注意: 因为cpp中定义的Private类包含Q_OBJECT,所以需要在源文件中包含 #include “moc_DSCheckComboBox.cpp”,如果工程能正常编译则不需要要进行后续操作
后续操作:修改头文件编译条件为如下:
在常规中修改如下:
在commanderline中输入命令:"$(QTDIR)/bin/moc.exe" "%(FullPath)" -o "./GeneratedFiles/$(Configuration)/moc_%(Filename).cpp" -D -DQT_CORE_LIB -DQT_GUI_LIB -DQT_LARGEFILE_SUPPORT -DQT_THREAD_SUPPORT -DUNICODE -DWIN32 -I"$(QTDIR)/include" -I"$(QTDIR)/include/QtCore" -I"$(QTDIR)/include/QtGui" -I"$(QTDIR)/include/qtmain" -I"." -I"./GeneratedFiles" -I"./GeneratedFiles/$(Configuration)"
Description中输入:Moc%27ing %(Filename)%(Extension)...
OutPuts中输入:./GeneratedFiles/$(Configuration)/moc_%(Filename).cpp
AdditionnalOutPuts中输入:$(QTDIR)/bin/moc.exe;%(FullPath);%(AdditionalInputs)
具体为什么这里就不过多说明,可度娘。