目錄
- Qt QComboBox之setEditable和currentTextChanged以及其原始碼分析
- 前言
- 問題的出現
- 問題分析
- currentTextChanged信號觸發
- 原始碼分析
Qt QComboBox之setEditable和currentTextChanged以及其原始碼分析
前言
最近做了一個QComboBox里有選項,然后選中選項之后就會自動觸發條件搜索,然后我發現,在我初始化comboBox時,由于信號連接的原因會觸發這個currentTextChanged信號,代碼大致如下:
connect(ui->comboBox, &QComboBox::currentTextChanged,
this, &CountryType::slot_pageSearch);
void Country::setComboBox()
{
QStringList content;
int maxLen = 0;
QFont font;
font.setFamily("Microsoft YaHei");
font.setPixelSize(16);
QFontMetrics fontMetrics(font);
QString command = jointQueryComboBoxTextCommand();
QList<QStringList> texts = m_oracle->runSelectCommand(command);
foreach (QStringList text, texts) {
QString item = text.value(0)+"-"+text.value(1);
content.push_back(item);
// 計算最大寬度
maxLen = maxLen > fontMetrics.boundingRect(item).width() ?
maxLen :
fontMetrics.boundingRect(item).width();
}
// comboBox的寬度為 文字的最大寬度 + 下拉箭頭的寬度 + 文字兩邊的間距
ui->comboBox->setMinimumWidth(maxLen + 38 + 8);
ui->comboBox->clear();
// 填充一個空選項作為篩選所有
ui->comboBox->addItem("");
ui->comboBox->addItems(content);
}
void Country::search()
{
setComboBox();
}
問題的出現
在我每一次對頁面進行切換的時候,我發現這個search都會觸發這個slot_pageSearch槽函式,然后執行條件搜索,
但是我今天突發奇想,我是不是應該讓使用者能夠手動的輸入這個條件呢,于是我setEditable(true);,將編輯打開了,
也就是:
ui->comboBox->setEditable(true);
在設定了這個之后,我驚奇的發現,并沒有像之前一樣會觸發slot_pageSearch這個槽函式,
問題分析
因為我只修改了ui->comboBox->setEditable(true);,所以我肯定,問題就是發生在這個地方,于是我在網上搜索與這個問題有關聯的答案,
最后,我還是在QT的官方檔案中對于currentText這個部分的介紹中,找到了問題的原因,
大概意思就是說,當你將QComboBox設定成可編輯的狀態時(setEditable(true)),currentText就是當前的框內顯示的文字,當不為可編輯的狀態時,currentText就是當前的選項或者是一個空的字串,
所以我猜想,設定成不可編輯狀態時,由于我進行了一個條目的添加,所以就將當前的選項改變了,
currentTextChanged信號觸發
于是我在正常的流程下,添加了一些列印陳述句,用于證實我的猜想,
void Country::setComboBox() {
...
// 填充一個空選項作為篩選所有
qDebug() << "1";
ui->comboBox->addItem("");
qDebug() << "2";
ui->comboBox->addItems(content);
qDebug() << "3";
...
}
void CountryType::slot_pageSearch()
{
...
qDebug() << "111";
...
}
輸出的結果為:
1
111
2
3
這也就表明了,我是在setItem之后,就會觸發槽函式,但是具體為啥是這樣的,為啥addItems不會觸發currentTextChanged呢?
所以我帶著問題,決定去原始碼里找答案
原始碼分析
// 代碼呼叫結構
1. QComboBox::addItem(int , const QIcon &, const QString &, const QVariant &)
----> QStandardItem::setData(const QVariant &, int )
----> QStandardItemModelPrivate::itemChanged(QStandardItem *, const QVector<int> &)
----> signal: QStandardItemModel::dataChanged(QModelIndex,QModelIndex) slot: QComboBox::_q_dataChanged(QModelIndex,QModelIndex)
----> if (lineEdit) lineEdit->setText(); else emit currentTextChanged(QString);
2. QComboxBox::addItems(QStringList)
----> QComboxBox::insertItems(int, QStringList)
----> QStandardItem::insertRows(int, QList<QStandardItem*>)
----> QStandardItemPrivate::insertRows(int, QList<QStandardItem*>)
----> rowsAboutToBeInserted(QStandardItem *, int , int)
----> QAbstractItemModel::beginInsertRows(const QModelIndex &, int , int )
----> signal: rowsAboutToBeInserted(const QModelIndex &, int , int ) slot:
----> QAbstractItemModelPrivate::rowsAboutToBeInserted(const QModelIndex &, int , int )
----> QStandardItemModelPrivate::rowsInserted(QStandardItem *, int , int )
----> QAbstractItemModel::endInsertRows()
----> void QAbstractItemModelPrivate::rowsInserted(const QModelIndex &, int , int )
----> signal: QAbstractItemModel::rowsInserted(QModelIndex,int,int) slot: QComboBox::_q_rowsInserted(QModelIndex,int,int)
- 首先,我從最簡單的來入手——
addItem

在上面這張圖里可以知道,addItem呼叫的是insertItem這個函式,這個是用來插入條目的一個函式;
然后就是insertItem這個函式,我們可以看到,這個函式會根據你的是不是原始的QStandardItemModel,是的話,就會去設定資料;

這里有兩個分支,
setData


隨著函式的呼叫程序,信號dataChanged被發射了,同時,在qcombobox.cpp中有對這個信號的連接,


我們進到這個_q_dataChanged()函式里面,

這里有一段代碼:
if (currentIndex.row() >= topLeft.row() && currentIndex.row() <= bottomRight.row()) {
const QString text = q->itemText(currentIndex.row());
if (lineEdit) {
lineEdit->setText(text);
updateLineEditGeometry();
} else {
emit q->currentTextChanged(text);
}
q->update();
#ifndef QT_NO_ACCESSIBILITY
QAccessibleValueChangeEvent event(q, text);
QAccessible::updateAccessibility(&event);
#endif
}
在這里,我們就找到了我們的目標currentTextChanged這個信號,但是發射這個信號的前提條件是:
currentIndex.row() >= topLeft.row() && currentIndex.row() <= bottomRight.row()也就是說,當前的下標的值需要在范圍內- 當前的狀態必須是不可編輯狀態才會發射信號
所以這里就是設定成可編輯狀態后,不會觸發信號的原因;
insertRow



現在關鍵的函式要來了,這個函式bool QStandardItemPrivate::insertRows,在待會addItems這個函式分析時也會用到,


在這里發射了這個rowInserted()信號,這個信號,又在QComboBox中進行了槽函式的連接


所以在這個函式里面,如果是插入的第一個條目,就會把當前的下表設定成0,這時候就會觸發另外一個信號currentIndexChanged,

至此,我們就能明白,為什么addItem會觸發currentTextChanged的信號,同時,如果設定成可編輯狀態,又是為何不會觸發currentTextChanged
- 其次,我們從第二個函式,也就是
addItems


到這里,就能發現,這個部分呼叫的還是這個bool QStandardItemPrivate::insertRows,同樣根據條件判斷,currentIndex = 0而其他兩個分別為1和添加條目的數量,很顯然不符合要求,
所以這也就是為什么addItems不會觸發currentIndexChange的原因,
至此,根據原始碼的分析,所有發生的事情,都能夠正常的解釋通了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/456135.html
標籤:其他
