Qt 学习

Qt 学习

C++ 模版

QObject 提供一个十分有用的 api,T findChild(QString, Qt::FindChildOptions),这个函数接收一个模版参数,返回模版参数的类型(如果子对象可以造型成 T ),也就是说返回值已经做了 cast 造型处理,这样就可以直接用特定的子类指针接收,使用起来非常方便。可以在对象的子类中寻找特定名称(objectName)的对象,而 Qt::FindChildOptions 参数用于设置搜索范围,Qt::FindDirectChildrenOnly 可以设置搜索范围仅限于当前对象的 children,并且不迭代 children 搜索,默认选项 Qt::FindChildrenRecursively 将迭代搜索所有子对象。

以下内容摘自官方示例:

// 返回最匹配的对象指针,该对象指针可以造型成 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)
{
    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;
    }
    for (i = 0; i < children.size(); ++i) {
        obj = qt_qFindChild_helper(children.at(i), name, mo);
        if (obj)
            return obj;
    }
    return 0;
}

需要注意,类模版中成员函数的定义和声明都要放在 .h 文件中,防止编译器报错,参考上面的 findChild 模版成员函数,这个函数用到模版,声明和定义都放在 QObject.h 中。

该函数的实现是通过 qt_qFindChild_helper 助手函数实现的。

在 QObject.cpp 源代码中找到的两个函数定义:

  • void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QRegExp *re, const QMetaObject &mo, QList<void *> *list);
  • QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo);

似乎没有一个函数原型能够对的上 findChild 函数中的调用,可能是 moc 系统通过 options 参数实现对重载函数以及是否执行递归调用。

在源代码实现中,判断能否返回对象指针的判断条件是 mo.cast(obj) && (name.isNull() || obj->objectName() == name) 如果传入的名称参数是空字符串 "" 那么 name.isNull() 返回的是 false,

obj->objectName() == name 返回的是 false,整个判断返回 false,也就无法找到符合要求的子对象了。

Model/View 架构

关于 Qt 的 Model/View 架构,在 官方文档 中已经给出了详细的介绍。

实际项目中使用到的模型是 Table 模型,在子类化 QAbstractTableModel 时,重写其中一些函数用于显示数据。

比如重写 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 。

原文地址:https://www.cnblogs.com/brifuture/p/9171654.html

时间: 2024-10-07 04:14:45

Qt 学习的相关文章

Qt学习之路

  Qt学习之路_14(简易音乐播放器) Qt学习之路_13(简易俄罗斯方块) Qt学习之路_12(简易数据管理系统) Qt学习之路_11(简易多文档编辑器) Qt学习之路_10(Qt中statusBar,MessageBox和Timer的简单处理) Qt学习之路_9(Qt中Item Widget初步探索) Qt学习之路_8(Qt中与文件目录相关操作) Qt学习之路_7(线性布局和网格布局初步探索) Qt学习之路_6(Qt局域网聊天软件) Qt学习之路_5(Qt TCP的初步使用) Qt学习之路

QT学习之路(1):彩票绝对不中模拟器

//============================================//绝对不中,彩票开奖模拟器#include "mainwindow.h"#include "ui_mainwindow.h"#include <QHash>#include <QDebug>MainWindow::MainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::M

qt学习(三):鼠标图标改变

qt学习 (三):鼠标图标改变 当你进入一个美好的qt软件场景,比如游戏,电脑的黑白图标会让程序逊色不少, 1改图标要加光标的头文件, 2 载入光标图, 3 再设置改光标就可以了 1在头文件中加 #include <QtGui>  //光标类的父类 //再在public成员中声明换的函数void keyPressEvent(QKeyEvent *k); //声明按键换图的函数         .h文件    --注意头文件和声明 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Qt学习总结-ui篇(二)

qccs定义圆角 border-radius:10px; 如果想给特定位置定义圆角,如: 左上角:border-left-top-radius:10px; 右下角色:border-right-bottom-rasius:10px; 半透明效果 只需要在css中使用rgba(100,100,100,40)这种形式来表示颜色即可. 为可执行文件添加图标 1.新建文件:finename.rc 文件名无所谓,只要后缀为rc就可以. 2.编辑新建的文件,输入以下内容: IDI_ICON1 ICON DIS

【qt学习005】搞不明白的布局

记录一下自己在布局这一章遇见的各种狗屎问题. 问题主要出现在布局最后一节:综合布局实例,类似于一个qq管理器的界面(见下图1).看见这个时,打算动手实现一下,于是开始写代码,写着写着发现不知道怎么写了,遇见一些无法解决的问题(问题中描述的布局类之间的关系见下图2): 1. 最底层应该使用哪一类? 2. 怎么将QListWidget加入到最底层? 3. 怎么往QStackWidget加入三个页面,每个页面代表不同的信息? 4. 怎么将QHBoxLayout中的CLOSE按钮连接到退出函数,要完整地

【Qt学习笔记】13.拖放技术:Drag & Drop

1.接受拖放 Drag & Drop 是一个界面操作,用于在两个窗口间传递数据. Drag Source: 拖放源窗口 Drag Target: 拖放目标窗口 拖放操作: 1.在源窗口:选中目标,按下鼠标,移动,拖至目标窗口(Drag) 2.在目标窗口:取消鼠标,到指定位置,松开鼠标(Drop) (按下ESC取消操作) MIME: MIME(Multipurpose Internet Mail Extensions)被传递的数据以MIME格式传送,它是多组type-data数据:(type0,

QT学习第1天

QT学习第一天  坚持住!! 一 Qt概述 1.Qt发展历史 (1)1991年诞生(Haavard Nord/Eirik Chambe-Eng), (2)1994年创立Troll Tech(奇趣科技) (3)2005年QT4.0 (4)2008年被Nokia收购 (5)2009年源代码开源 (6)2012年Nokia将全部QT业务和知识产权卖给Digia公司 (7)2013年QT5.0 QT5.1 QT5.2 (8)2014年Digia公司成立 The Qt Company子公司 2.Qt5.4

QT学习之路--创建一个对话框

Q_OBJECT:这是一个宏,凡是定义信号槽的类都必须声明这个宏. 函数tr()全名是QObject::tr(),被他处理过的字符串可以使用工具提取出来翻译成其他语言,也就是做国际化使用. 对于QT学习之路:Qt学习之路(7):创建一个对话框(上)这个程序.编译出现 invalid use of incomplete type ‘class QPushButton’ findButton->setEnabled(!text.isEmpty()); ^ In file included from

qt学习(四)主窗选钮,显示新窗口。

游戏有选区这个习惯, 当然,我特指<冒险岛>了,有的时候就是打开一个主屏幕上五个按钮让你点击进入, 甚至有的时候进去了还要选哪个频道,游戏服务器都得分区,频道来完成功能.现在我们先进入想选的区,不需要的可以看以后的登陆窗口了. 这一次的主要功能是完成选区,选完进入输入账号界面. 这次用的是一个点完出啦一个所以需要两个窗口,在原有的基础上新建qt设计师界面类.选择dialogwithoutbutton. 把最后一个要显示的当作主界面, 其他的都可以选择dialog模板, 完成以后,画ui界面,

qt学习(一)qt三个文件函数的框架

学到点什么, 而不是复制着什么, 每天敲着别人给的代码,苦涩得改完bug, 就这样一天天的过去, 实质上并没有学到什么, 别人的思想只是拿来借鉴, 你的思想是好是坏都是你的, 不用急着抛弃自己. 从qt看看人家的思路. Qt编程思路: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~` 以下:xxx.h ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~