Qt QComboBox之setEditable和currentTextChanged及其源碼分析

来源:https://www.cnblogs.com/codegb/archive/2022/04/05/16103788.html
-Advertisement-
Play Games

Qt QComboBox之setEditable和currentTextChanged以及其源碼分析 前言 最近做了一個QComboBox里有選項,然後選中選項之後就會自動觸發條件搜索。然後我發現,在我初始化comboBox時,由於信號連接的原因會觸發這個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)
  1. 首先,我從最簡單的來入手——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
  1. 其次,我們從第二個函數,也就是addItems
    在這裡插入圖片描述
    在這裡插入圖片描述
    到這裡,就能發現,這個部分調用的還是這個bool QStandardItemPrivate::insertRows,同樣根據條件判斷,currentIndex = 0而其他兩個分別為1和添加條目的數量,很顯然不符合要求。
    所以這也就是為什麼addItems不會觸發currentIndexChange的原因。
    至此,根據源碼的分析,所有發生的事情,都能夠正常的解釋通了。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 總述:在Win7環境下配置umijs框架,在框架中用worker線程方式使用SQL.js的wasm,在瀏覽器端實現數據的增刪改查以及資料庫導出導入。 一、安裝node.js 1、Win7系統只支持node.js v13.14.0或更早,所以從https://nodejs.org/download/r ...
  • 一、簡介 ELK日誌我們一般都是按天存儲,例如索引名為"kafkalog-2022-04-05",因為日誌量所占的存儲是非常大的,我們不能一直保存,而是要定期清理舊的,這裡就以保留7天日誌為例。 自動清理7天以前的日誌可以用定時任務的方式,這樣就需要加入多一個定時任務,可能不同服務記錄的索引名又不一 ...
  • 遇到c++非同步回調函數引用傳遞空指針異常 std::bad_function_call 錯誤的問題分析與解決方案。 發生錯誤“進程已結束,退出代碼-1073741819 (0xC0000005)”。 ...
  • mutex 的實現思想 mutex 主要有兩個 method: Lock() 和 Unlock() Lock() 可以通過一個 CAS 操作來實現 func (m *Mutex) Lock() { for !atomic.CompareAndSwapUint32(&m.locked, 0, 1) { ...
  • MybatisPlus 1.簡介 官網:https://baomidou.com/pages/24112f/#%E7%89%B9%E6%80%A7 特性 無侵入:只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑 損耗小:啟動即會自動註入基本 CURD,性能基本無損耗,直接面向對象操作 強大 ...
  • 前言 現實世界的數據中常常包含缺失的數據。原因很多,比如觀察結果沒有記錄,或數據損壞。處理缺失的數據很重要,因為許多機器學習演算法不支持具有缺失值的資料庫。 本教程將討論如何使用Python處理缺失的數據來進行機器學習。 您將瞭解到: •如何在數據集中標記無效或損壞的值。 •如何從數據集中刪除缺失數據 ...
  • 最近一段時間居家辦公,使用 Java Swing 編寫 IpChat, 基於 IP Messenger 協議,支持 IPv6。可實現簡單的文本信息傳輸,點對點直接通訊,無需中間伺服器。 ...
  • 線程組: 把多個線程組合到一起。 * 它可以對一批線程進行分類管理,Java允許程式直接對線程組進行控制。 package cn.itcast_06; public class MyRunnable implements Runnable { @Override public void run() ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...