Qt 學習

Qt 學習

C++ 模版

QObject 提供一個十分有用的 api,T findChild(QString, Qt::FindChildOptions),這個函數接收一個模版參數,返回模版參數的類型(若是子對象能夠造型成 T ),也就是說返回值已經作了 cast 造型處理,這樣就能夠直接用特定的子類指針接收,使用起來很是方便。能夠在對象的子類中尋找特定名稱(objectName)的對象,而 Qt::FindChildOptions 參數用於設置搜索範圍,Qt::FindDirectChildrenOnly 能夠設置搜索範圍僅限於當前對象的 children,而且不迭代 children 搜索,默認選項 Qt::FindChildrenRecursively 將迭代搜索全部子對象。html

如下內容摘自官方示例:api

// 返回最匹配的對象指針,該對象指針能夠造型成 QPushButton 指針,而且該對象的 objectName 爲 button1
QPushButton *button = parentWidget->findChild<QPushButton *>("button1");
// 返回最匹配的對象指針,該對象指針能夠造型成 QListWidget 指針
QPushButton *list = parentWidget->findChild<QListWidget *>();
// 返回最匹配的對象指針,僅在 parentWidget 對象的直接子對象中查找,
// 該對象指針能夠造型成 QPushButton 指針,而且該對象的 objectName 爲 button1
QPushButton *button = parentWidget->findChild<QPushButton *>("button1", Qt::FindDirectChildrenOnly);
// 返回最匹配的對象指針,僅在 parentWidget 對象的直接子對象中查找,
// 該對象指針能夠造型成 QPushButton 指針
QListWidget *list = parentWidget->findChild<QListWidget *>(QString(), Qt::FindDirectChildrenOnly);

須要注意的是最後一種用法,這裏想要在 parentWidget 中找到可造型成 QListWidget 的直接子對象,可是不須要指定對象名,第一個參數須要用 QString() 而不能用空字符串 "",不然便沒有符合要求的子類 list,此時 list 的值爲 0x0,結果一直找不到子對象。架構

如下代碼爲 Qt5.7 版本源代碼:函數

// QObject.h
template<typename T>
inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{
    typedef typename QtPrivate::remove_cv<typename QtPrivate::remove_pointer<T>::type>::type ObjType;
    return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
}

// QObject.cpp
QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options)
{
    if (!parent)
        return 0;
    const QObjectList &children = parent->children();
    QObject *obj;
    int i;
    for (i = 0; i < children.size(); ++i) {
        obj = children.at(i);
        if (mo.cast(obj) && (name.isNull() || obj->objectName() == name))
            return obj;
    }
    if (options & Qt::FindChildrenRecursively) {
        for (i = 0; i < children.size(); ++i) {
            obj = qt_qFindChild_helper(children.at(i), name, mo, options);
            if (obj)
                return obj;
        }
    }
    return 0;
}

須要注意,類模版中成員函數的定義和聲明都要放在 .h 文件中,防止編譯器報錯,參考上面的 findChild 模版成員函數,這個函數用到模版,聲明和定義都放在 QObject.h 中。學習

該函數的實現是經過 qt_qFindChild_helper 助手函數實現的。ui

在 QObject.cpp 源代碼中找到的兩個函數定義:this

  • void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options);
  • QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options);

在源代碼實現中,判斷可否返回對象指針的判斷條件是 mo.cast(obj) && (name.isNull() || obj->objectName() == name) 若是傳入的名稱參數是空字符串 "" 那麼 name.isNull() 返回的是 false, obj->objectName() == name 返回的是 false,整個判斷返回 false,也就沒法找到符合要求的子對象了。spa

Model/View 架構

關於 Qt 的 Model/View 架構,在 官方文檔 中已經給出了詳細的介紹。指針

實際項目中使用到的模型是 Table 模型,在子類化 QAbstractTableModel 時,重寫其中一些函數用於顯示數據。code

好比重寫 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; 用於顯示標題數據。標題數據有縱向和橫向兩種選擇,Qt::Orientation 用於設置方向。若是不指定方向,對全部 role 值爲 Qt::DisplayRole 的數據進行繪製,將會看到橫向的第一個標題頭彷佛老是不顯示或者顯示的是錯誤的數據。緣由在於 TableModel 還會顯示縱向的標題頭,致使兩個方向的標題頭重疊。 role 值有 Qt 提供的一些值如 Qt::DisplayRoleQt::BackgroundRole,前者用於顯示文本或圖片,或者能夠用來設置背景。

最開始接觸 Qt 的 Model/View 架構時感受它有些複雜,除了 Model 外,在重寫函數時常常看到對 ModelIndex 的使用,ModelIndex 就是索引,包含一些數據,可是 QModelIndex 隱藏了它的構造函數(它的構造函數是用 private 修飾的),沒法經過構造函數直接構造一個 QModelIndex 對象(須要經過 createIndex 方法構造):

如下爲 Qt5.7 的部分源代碼

// qabstractitemmodel.h
friend class QAbstractItemModel;

...

private:
    inline QModelIndex(int arow, int acolumn, void *ptr, const QAbstractItemModel *amodel) Q_DECL_NOTHROW
        : r(arow), c(acolumn), i(reinterpret_cast<quintptr>(ptr)), m(amodel) {}

編寫本身的 model 類時感受無從下手,好在官方的示例不少,介紹的也很詳細。而在重寫 TableModel 時,其實也沒有怎麼使用成員函數中 QModelIndex 參數,就是直接跳過這個參數,對外提供數據。 模型比較簡單,目前僅在刷新數據時用到 QModelIndex 。

相關文章
相關標籤/搜索