Qt之QComboBox下拉框實現勾選
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)
具體為什么這里就不過多說明,可度娘。
智能推薦
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
猜你喜歡
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...
19.vue中封裝echarts組件
19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...