Qt类 | QObject类详解

文章目录

  • 一、QObject类介绍
  • 二、Properties(属性)
  • 三、Public Functions(公共函数)
  • 四、Public Slots(公共槽函数)
  • 五、Signals(信号)
  • 六、Static Public Members(静态公共成员)
  • 七、Protected Functions(受保护的函数)
  • 八、Related Non-Members(相关非成员)
  • 九、Macros(宏)

这篇文章主要参考Qt QObject类的官方链接:https://doc.qt.io/qt-5/qobject.html

一、QObject类介绍

  所有的 Qt 控件都继承自 QObject 。其使用方式如下:

Header:
#include <QObject> 
qmake:
QT += core

QObject类的一些主要特性:

  • 事件处理QObject 提供了事件处理机制,允许对象接收和处理不同类型的事件,如鼠标点击、键盘输入等。

    QObject对象可以使用event(QEvent *_e_) 用于接收和处理各种事件,可以被子类重写以自定义事件处理。还可以通过installEventFilter()和eventFilter()函数来过滤或拦截其他对象的事件。

  • 信号和槽QObject 支持 Qt 的信号和槽机制,允许对象之间进行通信。connect() 方法用于建立信号和槽之间的连接,而 disconnect() 用于断开连接。

    注意:对于所有实现信号、槽或属性的QObject对象来说,Q_OBJECT宏是必须的

  • 定时器QObject 支持定时器功能,通过 startTimer(int _interval_)killTimer(int _id_) 方法,QObject 可以管理定时器事件。

  • 属性系统QObject 提供了属性系统,允许对象拥有属性,并通过 property(const char *_name)setProperty(const char *_name, const QVariant &_value) 进行访问和修改。

  • 线程安全:许多 QObject 的方法都是线程安全的,可以在多线程环境中使用。

  • 动态属性QObject 允许动态地添加和删除属性。

  • 元对象系统:这是 Qt 框架的核心特性之一。

  • QObject对象使用对象树来组织它们自己。

    当你以另一个对象作为父对象创建一个QObject时,这个对象会自动将自己添加到父对象的children()列表中。父对象拥有该对象的所有权,也就是说,它将在其析构函数中自动删除其子对象。

  • 宏和属性:Qt 提供了一系列宏(如 Q_OBJECT, Q_PROPERTY, Q_INVOKABLE 等),用于增强 QObject 及其子类的元对象系统功能

  • 自动连接

    Qt的元对象系统提供了一种机制,用于自动连接QObject子类的信号和槽。只要对象使用适当的对象名称定义,并且槽遵循简单的命名约定,就可以通过QMetaObject::connectSlotsByName()函数在运行时执行这种连接。

  • 国际化支持

    所有QObject子类都支持Qt的翻译特性,使得应用程序的用户界面可以翻译成不同的语言。需要将其包装在对tr()函数的调用中。

    tr(const char *_sourceText, const char *_disambiguation = nullptr, int _n = -1)
    

    用于获取翻译后的文本。

  这个类中的所有函数都是可重入的。

  下面这些函数是线程安全的。

image-20240712202017819

二、Properties(属性)

  • objectName : QString

    objectName属性存储了对象名称。对象名称是一个标识符,用于在应用程序中唯一标识一个对象。这个名称可以用来通过findChild()findChildren()方法根据名称(和类型)查找对象

    • 访问函数

      //一个常量成员函数,用来获取当前对象的名称
      QString objectName() const
      //用来设置当前对象的名称
      void setObjectName(const QString &name)
      
    • 信号

      void objectNameChanged(const QString &objectName)
      

      当对象的名称发生变化时,这个信号会被触发。这是一个私有信号,意味着它可以在信号连接中使用,但是用户不能直接发出这个信号,通常由框架内部在特定情况下自动发出。

三、Public Functions(公共函数)

  公共函数指的是那些可以被类的外部访问的函数,它们是类的公共接口的一部分。下面详细介绍这些函数

  • 构造函数

    QObject::QObject(QObject *parent = nullptr)
    
    • 函数说明:

      这个构造函数用于创建一个对象,并且可以指定一个父对象parent。如果没有指定父对象,或者父对象为nullptr,构造函数将创建一个无父对象的实例。

    • 注意事项:

      父对象可以被视为对象的所有者。父对象的析构函数会销毁所有的子对象。这意味着如果一个父对象被销毁,它的所有子对象也会自动被销毁。如果将parent设置为nullptr,则构造的对象将没有父对象。如果这个对象是一个窗口部件(widget),它将成为一个顶级窗口。

  • 析构函数

    [virtual] QObject::~QObject()
    
    • 函数说明:

      析构函数用于销毁对象,并删除所有子对象。析构时,与对象相关的所有信号连接将自动断开,对象的任何待处理事件将从事件队列中移除。

    • 注意事项:

      建议使用deleteLater()方法而不是直接删除QObject子类实例。deleteLater()会在适当的时候,即所有待处理事件被处理后,安全地删除对象。

      使用new在堆上分配空间来创建子对象,让父对象负责它的内存回收;如果要在栈上创建对象,就不要指定它的父对象,以免父对象回收了栈内存,导致程序崩溃。

  • blockSignals函数

    bool QObject::blockSignals(bool block)
    
    • 函数说明:

      函数用于控制对象发出的信号是否被阻塞。如果参数 blocktrue,则发出的信号将被阻塞,即不会触发任何连接到该信号的槽函数。如果 blockfalse,则信号不会被阻塞。

    • 注意事项:

      • 即使对象的信号被阻塞,destroyed 信号仍然会被发出。destroyed 信号是一个特殊的信号,用于通知对象即将被销毁。
      • 当信号被阻塞时,发出的信号不会被缓存。这意味着如果在信号被阻塞期间发出了信号,这些信号将不会被传递,一旦信号取消阻塞,之前阻塞期间的信号也不会重新发出。
    • 使用场景:

      通常用于需要临时阻止信号传递的场景

  • children函数

    const QObjectList &QObject::children() const
    
    • 函数说明:

      函数返回一个包含所有子对象的列表。这个列表是按子对象被添加的顺序排列的。QObjectList等价于QList<QObject *>

    • 注意事项:

      • 列表顺序变化:

        列表的顺序会在QWidget子对象被提升(raise)或降低(lower)时发生变化。被提升的窗口部件会成为列表中的最后一个对象,而被降低的窗口部件会成为列表中的第一个对象。

    • 使用场景:

      children() 函数通常用于遍历和操作对象的子对象,例如在需要对所有子对象执行某些操作时。

  • connect成员函数的一个重载版本

    QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type = Qt::AutoConnection) const
    

    这个函数是connect()的重载,等价于

    connect(sender, signal, this, method, type)
    
    • 函数说明:

      connect 函数用于将发送者对象(sender)的信号(signal)连接到当前对象的槽函数(method

    • 参数说明:

      • const QObject *sender:发出信号的对象。
      • const char *signal:要连接的信号的字符串表示形式。
      • const char *method:当前对象中要连接的槽函数的字符串表示形式。
      • Qt::ConnectionType type:连接类型,默认为 Qt::AutoConnection,表示自动选择连接类型。
    • 注意事项:

      每次建立连接时,都会发出一个信号。因此,重复的连接会导致发出两个信号。开发者需要确保不会无意中创建重复的连接,这可能会影响程序的行为。如果需要断开已经建立的连接,可以使用 disconnect() 函数。

  • disconnect成员函数的一个重载版本

    bool QObject::disconnect(const char *signal = nullptr, const QObject *receiver = nullptr, const char *method = nullptr) const
    
    • 函数说明:

      disconnect 函数用于断开指定的信号-槽连接。如果没有指定参数,它将断开调用对象上所有未指定的信号连接。

    • 参数说明:

      • const char *signal:要断开连接的信号的名称。如果为nullptr,则断开所有信号。
      • const QObject *receiver:接收信号的对象。如果为nullptr,则断开所有接收者的所有连接。
      • const char *method:接收者中要断开连接的槽函数的名称。如果为nullptr,则断开接收者的所有槽函数。
    • 注意事项:

      信号-槽连接会在涉及的任一对象被销毁时自动被移除。这意味着不需要手动断开连接,除非在对象销毁前需要断开。

  • disconnect成员函数的一个重载版本

    bool QObject::disconnect(const QObject *receiver, const char *method = nullptr) const
    
    • 函数说明:

      该函数用于断开当前对象(即调用 disconnect 函数的对象)发出的所有信号与指定 receiver 的连接。如果提供了 method 参数,那么只会断开与该特定槽方法的连接;如果 methodnullptr,则会断开该接收者的所有槽。

    • 参数说明:

      • const QObject *receiver:指向接收者的 QObject 指针
      • const char *method = nullptr:表示接收者中的槽名称
    • 注意事项:

      如果连接无效或已经被断开,则不执行任何操作并返回 false。

  • dumpObjectInfo函数

    void QObject::dumpObjectInfo() const
    
    • 函数说明:

      将对象的信号连接等信息输出到调试输出中。输出的信息可能包括信号名称、连接的槽函数地址、槽所在对象的信息等。

  • dumpObjectTree函数

    void QObject::dumpObjectTree() const
    
    • 函数说明:

      输出当前对象以及其所有子对象形成的树状结构到调试输出中。

      输出的信息通常包括每个对象的名称、类型、地址以及它们之间的父子关系。dumpObjectTree()dumpObjectInfo() 结合使用,可以提供更全面的调试信息。

  • dynamicPropertyNames函数

    QList<QByteArray> QObject::dynamicPropertyNames() const
    
    • 函数说明:

      返回使用 setProperty() 方法动态添加到对象的所有属性的名称

  • event函数

    [virtual] bool QObject::event(QEvent *e)
    
    • 函数说明:

      该函数负责接收事件,且如果事件被识别和处理,则应返回true 。这是一个虚函数,可以在派生类中被重写(override)。可以重写event() 函数来自定义对象的行为。在重写 event() 函数时,应根据需要处理特定事件,并对于未处理的事件调用基类的 event() 函数。

    • 参数说明:

      QEvent 类型是一个枚举,定义了多种事件类型

    • 示例:

      class MyClass : public QWidget{Q_OBJECTpublic:MyClass(QWidget *parent = nullptr);~MyClass();bool event(QEvent* ev) override{if (ev->type() == QEvent::PolishRequest) {// overwrite handling of PolishRequest if anydoThings();return true;} else  if (ev->type() == QEvent::Show) {// complement handling of Show if anydoThings2();QWidget::event(ev);return true;}// Make sure the rest of events are handledreturn QWidget::event(ev);}};
      

      event() 函数中,通常通过检查 e->type() 来识别事件类型,并执行相应的处理逻辑。

  • installEventFilter函数

    void QObject::installEventFilter(QObject *filterObj)
    
    • 函数说明:

      安装一个事件过滤器 filterObj 到当前对象上。这个过滤器将捕获发送到当前对象的所有事件。

      事件过滤器是一个对象,它会接收发送给该对象的所有事件。事件过滤器可以决定停止事件的传播或者将事件转发给当前对象。事件过滤器 filterObj 通过其 eventFilter() 函数接收事件。如果 eventFilter() 返回 true,则事件被过滤(即停止处理);如果返回 false,则事件将继续传播。如果在单个对象上安装了多个事件过滤器,那么最后安装的过滤器将首先被激活。

    • 示例:

      定义KeyPressEater类作为事件过滤器,并重写eventFilter函数来接收并处理事件

      class KeyPressEater : public QObject{Q_OBJECT...protected:bool eventFilter(QObject *obj, QEvent *event) override;};bool KeyPressEater::eventFilter(QObject *obj, QEvent *event){if (event->type() == QEvent::KeyPress) {QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);qDebug("Ate key press %d", keyEvent->key());return true;} else {// standard event processingreturn QObject::eventFilter(obj, event);}}
      

      为两个对象安装事件过滤器

      KeyPressEater *keyPressEater = new KeyPressEater(this);
      QPushButton *pushButton = new QPushButton(this);
      QListView *listView = new QListView(this);pushButton->installEventFilter(keyPressEater);
      listView->installEventFilter(keyPressEater);
      
    • 注意事项

      • 如果在 eventFilter() 函数中删除了接收者对象,请确保返回 true。如果返回 false,Qt 会将事件发送到已删除的对象,导致程序崩溃。
      • 过滤器对象必须与当前对象在同一个线程中。如果 filterObj 在不同的线程中,此函数将不执行任何操作。
  • removeEventFilter函数

    void QObject::removeEventFilter(QObject *obj)
    
    • 函数说明:

      从当前对象移除指定的事件过滤器 obj,如果指定的事件过滤器未被安装,移除请求将被忽略,不会产生任何效果。

    • 注意事项:

      • 当安装了事件过滤器的对象被销毁时,所有的事件过滤器将自动被移除。
      • installEventFilter() 类似,removeEventFilter() 要求当前对象和事件过滤器对象在同一个线程中
  • eventFilter函数

    [virtual] bool QObject::eventFilter(QObject *watched, QEvent *event)
    
    • 函数说明:

      当对象作为另一个对象的事件过滤器时,对象中的函数eventFilter会被调用来过滤事件。如果 eventFilter() 返回 true,则事件被过滤(即停止处理);如果返回 false,则事件将继续传播。可以在派生类中重写(override)eventFilter() 函数,以实现对特定事件的处理。

    • 参数说明:

      • QObject *watched:被监视的对象
      • QEvent *event:QEvent 是一个枚举,定义了多种事件类型
    • 示例:

      class MainWindow : public QMainWindow
      {
      public:MainWindow();protected:bool eventFilter(QObject *obj, QEvent *ev) override;private:QTextEdit *textEdit;
      };MainWindow::MainWindow()
      {textEdit = new QTextEdit;setCentralWidget(textEdit);textEdit->installEventFilter(this);
      }bool MainWindow::eventFilter(QObject *obj, QEvent *event)
      {if (obj == textEdit) {if (event->type() == QEvent::KeyPress) {QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);qDebug() << "Ate key press" << keyEvent->key();return true;} else {return false;}} else {// pass the event on to the parent classreturn QMainWindow::eventFilter(obj, event);}
      }
      

      注意:未处理的事件被传递给基类的 eventFilter() 函数

    • 注意事项:

      • 对于某些特定事件,如 QEvent::ShortcutOverride,需要通过调用它们的 accept() 方法来显式接受,以防止事件继续传播。
      • 如果在 eventFilter() 函数中删除了接收者对象,必须返回 true。否则,Qt 会将事件发送到已删除的对象,可能导致程序崩溃。
      • 事件过滤器对象必须与它所监视的对象在同一个线程中。如果过滤器对象或监视对象在调用 installEventFilter() 后被移动到不同的线程,则事件过滤器将不会被调用
  • findChild函数

    template <typename T> T QObject::findChild(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
    
    • 函数说明:

      返回当前对象的子对象,如果没有找到匹配的子对象,则返回 nullptr。默认情况下,递归搜索所有子对象

    • 参数说明:

      • name 参数指定要查找的子对象的名称,如果不提供名称或提供空字符串,则匹配所有名称
      • options 参数定义了搜索行为,可以是 Qt::FindChildrenRecursively(默认值,递归搜索所有子对象)或 Qt::FindDirectChildrenOnly(只搜索直接子对象)。
    • 示例:

      QPushButton *button = parentWidget->findChild<QPushButton *>("button1");
      

      返回名为 “button1” 的子 QPushButton 对象,即使该按钮不是 parentWidget 的直接子对象

      QListWidget *list = parentWidget->findChild<QListWidget *>();
      

      返回 parentWidget 的子 QListWidget 对象

      QPushButton *button = parentWidget->findChild<QPushButton *>("button1", Qt::FindDirectChildrenOnly);
      

      示例返回名为 “button1” 的 parentWidget 的直接子 QPushButton 对象

      QListWidget *list = parentWidget->findChild<QListWidget *>(QString(), Qt::FindDirectChildrenOnly);
      

      返回 parentWidget 的直接子 QListWidget 对象,其直接父对象是 parentWidget

    • 注意事项:

      • 如果有多个子对象匹配搜索条件,返回找到的直接子对象
      • 如果找到多个匹配的直接子对象,则不确定将返回哪一个。在这种情况下,应该使用 findChildren()
      • findChildren() 不同,findChild 只返回找到的第一个匹配项
  • findChildren模板函数的重载版本

    template <typename T> QList<T> QObject::findChildren(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
    
    • 函数说明:

      返回当前对象的所有子对象,这是一个模板函数,返回类型为 QList<T> 的列表,其中 T 是子对象的类型。默认情况下,递归搜索所有子对象

    • 参数说明:

      • name 参数指定要查找的子对象的名称。如果省略该参数或提供空字符串,则匹配所有名称。
      • options 参数定义了搜索的范围,可以是 Qt::FindChildrenRecursively(默认值,递归搜索所有子对象)或 Qt::FindDirectChildrenOnly(只搜索直接子对象)。
    • 示例:

      QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("widgetname");
      

      示例返回名为 widgetname 的指定 parentWidget 的所有子 QWidget 列表

      QList<QPushButton *> allPButtons = parentWidget.findChildren<QPushButton *>();
      

      示例返回 parentWidget 的所有 QPushButton 子对象

      QList<QPushButton *> childButtons = parentWidget.findChildren<QPushButton *>(QString(), Qt::FindDirectChildrenOnly);
      

      示例返回 parentWidget 的所有直接子 QPushButton 对象

    • 注意事项:

      • 当需要获取对象树中所有特定类型的子对象时,此函数非常有用,例如在复杂的用户界面中查找所有的按钮或文本框
      • 如果只关心找到的第一个子对象,可以使用 findChild(),它通常比 findChildren() 更高效。
  • findChildren模板函数的重载版本

    template <typename T> QList<T> QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
    
    • 函数说明:

      返回当前对象的所有子对象,包含所有名称与正则表达式匹配的子对象。默认情况下,递归搜索所有子对象

    • 参数说明:

      • 使用 QRegularExpression 类型的对象 re 作为匹配模式
      • options 参数定义了搜索的范围,可以是 Qt::FindChildrenRecursively(默认值,递归搜索所有子对象)或 Qt::FindDirectChildrenOnly(只搜索直接子对象)。
    • 注意事项:

      • findChild():查找单个符合条件的子对象。
      • findChildren(const QString &name, Qt::FindChildOptions options):使用普通字符串匹配来查找子对象。
      • 这个函数使用正则匹配来查找子对象
  • inherits函数

    bool QObject::inherits(const char *className) const
    
    • 函数说明:

      用于检查对象是否属于或继承自某个类。如果调用对象是 className 类的实例,或者它的类继承自 className,函数返回 true;否则返回 false。一个类被认为是继承自它自己的。

    • 示例

      QTimer *timer = new QTimer;         // QTimer inherits QObject
      timer->inherits("QTimer");          // returns true
      timer->inherits("QObject");         // returns true
      timer->inherits("QAbstractButton"); // returns false// QVBoxLayout inherits QObject and QLayoutItem
      QVBoxLayout *layout = new QVBoxLayout;
      layout->inherits("QObject");        // returns true
      layout->inherits("QLayoutItem");    // returns true (even though QLayoutItem is not a QObject)
      
    • 注意事项:

      如果你需要确定一个对象是否是特定类的实例以便进行类型转换,可以考虑使用 qobject_cast<Type *>(object)

  • isWidgetType函数

    bool QObject::isWidgetType() const
    
    • 函数说明:

      判断对象是否为 QWidget 类型或其派生类的实例。如果调用对象是一个窗口小部件(widget),即继承自 QWidget,函数返回 true;否则返回 false

      调用 isWidgetType() 函数等价于调用 inherits("QWidget") ,甚至更快。这是因为 isWidgetType() 内部实现可能利用了某些优化手段,比如直接访问对象的类型信息,而不是通过字符串比较。

    • 注意事项:

      isWidgetType() 只检查对象是否是窗口小部件类型,不检查其他类型的 QObject 派生类。如果你需要检查其他特定类型的继承关系,可能需要使用 inherits() 函数。

  • isWindowType函数

    bool QObject::isWindowType() const
    
    • 函数说明:

      判断对象是否为 QWindow 类型或其派生类的实例。如果调用对象是一个窗口(window),即继承自 QWindow,函数返回 true;否则返回 false

      调用 isWindowType() 函数比调用 inherits("QWindow") 更快。这是因为 isWindowType() 可能内部实现了优化,比如直接检查对象的类型信息,而不是通过字符串比较。

    • 注意事项:

      isWindowType() 只检查对象是否是窗口类型,不检查其他类型的 QObject 派生类。如果你需要检查其他特定类型的继承关系,可能需要使用 inherits() 函数。

  • startTimer函数重载

    int QObject::startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer)
    
    • 函数说明:

      用于启动一个定时器并返回一个定时器标识符,如果无法启动定时器则返回零。定时器事件(timerEvent)会每隔 interval 毫秒发生一次,直到调用 killTimer()

      当定时器触发时,Qt框架会调用 timerEvent(QTimerEvent *event) 函数,并传入 QTimerEvent 类型的事件参数。需要重写此函数来定义定时器触发时要执行的代码。

      如果同时运行多个定时器,可以使用 QTimerEvent::timerId() 来确定哪个定时器被激活。

    • 参数说明:

      • interval 表示定时器触发的时间间隔(毫秒)
      • timerType 表示定时器的类型,默认为 Qt::CoarseTimer
    • 示例:

       class MyObject : public QObject{Q_OBJECTpublic:MyObject(QObject *parent = nullptr);protected:void timerEvent(QTimerEvent *event) override;};MyObject::MyObject(QObject *parent): QObject(parent){startTimer(50);     // 50-millisecond timerstartTimer(1000);   // 1-second timerstartTimer(60000);  // 1-minute timerusing namespace std::chrono;startTimer(milliseconds(50));startTimer(seconds(1));startTimer(minutes(1));// since C++14 we can use std::chrono::duration literals, e.g.:startTimer(100ms);startTimer(5s);startTimer(2min);startTimer(1h);}void MyObject::timerEvent(QTimerEvent *event){qDebug() << "Timer ID:" << event->timerId();}
      
    • 注意事项:

      QTimer 的精度取决于底层操作系统和硬件。timerType 参数允许你自定义定时器的精度。大多数平台支持 20 毫秒的精度;一些平台提供更多。

      • Qt::PreciseTimer 用于需要高精度定时器的场景
      • Qt::CoarseTimer 用于对精度要求不高的场景
  • startTimer函数重载

    int QObject::startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)
    
    • 函数说明:

      使用 std::chrono::milliseconds 作为时间间隔参数来启动一个定时器,并返回一个定时器标识符。如果无法启动定时器,则返回零。定时器事件将每隔指定的时间间隔发生,直到调用 killTimer()

      当定时器触发时,Qt框架会调用 timerEvent(QTimerEvent *event) 函数,并传入 QTimerEvent 类型的事件参数。需要重写此函数来定义定时器触发时要执行的代码。

      如果同时运行多个定时器,可以使用 QTimerEvent::timerId() 来确定哪个定时器被激活。

    • 参数说明:

      std::chrono::milliseconds 作为时间间隔参数,而不是原始的毫秒整数

    • 其他同上

  • killTimer函数

    void QObject::killTimer(int id)
    
    • 函数说明:

      用于停止一个特定的定时器

    • 参数说明:

      id 是通过调用 startTimer() 函数启动定时器时返回的。每个启动的定时器都会被分配一个唯一的标识符。

  • metaObject函数

    [virtual] const QMetaObject *QObject::metaObject() const
    
    • 函数说明:

      函数返回指向该对象的元对象的指针。

      元对象包含了继承自 QObject 的类的相关信息,例如类名、超类名、属性、信号和槽。每个包含 Q_OBJECT 宏的 QObject 子类都会有一个元对象。

      元对象信息是信号-槽连接机制和属性系统所必需的。inherits() 函数也利用了元对象。

      如果没有对象实例的指针,但仍然想要访问一个类的元对象,你可以使用 staticMetaObject直接访问 QPushButton 类的静态元对象

      QObject *obj = new QPushButton;
      obj->metaObject()->className();             // 返回 "QPushButton"QPushButton::staticMetaObject.className();  // 返回 "QPushButton"
      
  • moveToThread函数

    void QObject::moveToThread(QThread *targetThread)
    
    • 函数说明:

      用于将对象移动到另一个线程。对象的事件处理将在目标线程中继续进行。

    • 参数说明:

      QThread *targetThreadQThread 类型的指针 targetThread,表示目标线程。

    • 注意事项:

      • 如果要将对象移动到应用程序的主线程,可以使用 QApplication::instance() 获取应用程序的实例,然后使用 QApplication::thread() 获取应用程序所在的线程。

        myObject->moveToThread(QApplication::instance()->thread());
        
      • 如果 targetThreadnullptr,则对象及其子对象的所有事件处理将停止,因为它们不再与任何线程关联。

      • 对象的所有活动定时器将被重置。首先在当前线程中停止定时器,然后在 targetThread 中重新启动(间隔时间相同)。

      • 在更改线程亲和性之前,会向对象发送一个 QEvent::ThreadChange 事件。可以处理此事件来执行任何特殊处理。

      • 任何新发布的事件,只要 targetThread 不是 nullptr,都将在目标线程中处理。如果 targetThreadnullptr,则对象及其子对象不再与任何线程关联,因此无法处理任何事件。

      • 线程安全性:此函数不是线程安全的;此函数只能将对象从当前线程“推”到另一个线程,不能从任何其他线程“拉”到当前线程。

  • thread函数

    QThread *QObject::thread() const
    
    • 函数说明:

      用于获取对象当前所属的线程,返回一个指向 QThread 类型的指针。

      使用 moveToThread(QThread *targetThread) 函数可以将对象移动到另一个线程,从而更改其线程亲和性。

  • objectName函数

    QString objectName() const
    
    • 函数说明:

      用于获取对象的名称。返回一个字符串,表示对象的名称。如果对象没有设置名称,返回一个空字符串。

  • setObjectName函数

    void setObjectName(const QString &name)
    
    • 函数说明:

      QObject 子类的对象设置对象名称

  • parent函数

    QObject *QObject::parent() const
    
    • 函数说明:

      返回一个指向 QObject 类型的指针,表示当前对象的父对象。

      在 Qt 中,对象可以有一个父对象,这建立了对象之间的层次关系。父对象的销毁通常会导致其所有子对象的自动销毁。

  • setParent函数

    void QObject::setParent(QObject *parent)
    
    • 函数说明:

      用于将对象设置为当前对象的子对象

    • 示例:

      QObject parentObject;
      QObject childObject;
      childObject.setParent(&parentObject);QObject *parent = childObject.parent();
      if (parent) {qDebug() << "Child has a parent";
      } else {qDebug() << "Child has no parent";
      }
      
  • property函数

    QVariant QObject::property(const char *name) const
    
    • 函数说明:

      用于获取对象的属性值。返回一个 QVariant 类型的对象,包含指定属性的值。如果指定的属性不存在,则返回一个无效的 QVariant 对象。

    • 参数说明:

      const char *name表示要获取的属性的名称。

    • 注意事项:

      • 使用 QVariant::isValid() 函数可以检查返回的 QVariant 对象是否包含有效的属性值。
      • 属性名称是区分大小写的,确保使用正确的名称来获取或设置属性。
      • 动态属性不是通过类定义的,而是在运行时添加的
      • dynamicPropertyNames() 函数返回对象所有动态属性的名称列表。
  • setProperty函数

    bool QObject::setProperty(const char *name, const QVariant &value)
    
    • 函数说明:

      用于设置对象的属性值。若要设置的属性未在类中使用Q_PROPERTY宏声明,则这个属性是个动态属性。无论是否声明,都可以使用这个函数为对象设置属性值。

    • 参数说明:

      • name 是一个指向 const char 的指针,表示要设置的属性的名称;
      • value 是一个 QVariant 类型的对象,表示要设置的属性值。
    • 返回值

      • 如果属性是通过 Q_PROPERTY 在类中定义的,则在成功设置属性值时返回 true,否则返回 false
      • 如果属性没有通过 Q_PROPERTY 定义(即不在元对象中列出),则作为动态属性添加,并返回 false
    • 注意事项

      • 属性名称是区分大小写的,确保使用正确的名称来设置属性。

      • _q_ 开头的动态属性名称是为 Qt 内部使用保留的,应避免使用这些名称。

      • 动态属性可以通过 property() 方法再次查询,并且可以通过将属性值设置为无效的 QVariant 来移除。更改动态属性的值会向对象发送一个 QDynamicPropertyChangeEvent 事件。

        QDynamicPropertyChangeEvent 是 Qt 中的一个事件类型,当对象的动态属性发生变化时,这个事件会被触发并发送给对象,以便它可以响应属性的变化。

  • signalsBlocked函数

    bool QObject::signalsBlocked() const
    
    • 函数说明:

      用于检查对象的信号是否被阻塞。如果对象的信号被阻塞,返回 true。如果对象的信号没有被阻塞,返回 false。信号默认是不被阻塞的,即它们可以正常传递给连接的槽函数。

      在 Qt 中,可以通过 blockSignals(bool) 函数来控制对象的信号是否被阻塞。当信号被阻塞时,发出的信号不会传递给任何接收者。

      • 使用 obj.blockSignals(true) 可以阻止信号的传递。
      • 使用 obj.blockSignals(false) 可以恢复信号的传递。
    • 注意事项:

      • 信号阻塞是特定于对象的,不会影响其他对象的信号传递。
      • 信号阻塞不会阻止槽函数的调用,只会阻止信号的自动传递。

四、Public Slots(公共槽函数)

  • deleteLater函数

    [slot] void QObject::deleteLater()
    
    • 函数说明:

      安排对象在将来的某个时间点被删除。

      删除时机:

      • 对象将在控制权返回到事件循环时被删除。这意味着如果调用 deleteLater() 时事件循环正在运行,对象将在当前事件处理完毕后被销毁。
      • 如果在调用 deleteLater() 时事件循环尚未启动(例如,在调用 QCoreApplication::exec() 之前),对象将在事件循环开始时被删除。
      • 如果在主事件循环停止后调用 deleteLater(),则对象不会被删除。
      • 如果在没有运行事件循环的线程中调用 deleteLater(),对象将在该线程结束时被销毁。
    • 注意事项:

      • 多次调用 deleteLater() 是安全的;

      • deleteLater() 函数是线程安全的,可以在任何线程中调用。

五、Signals(信号)

  信号,不是普通函数。信号可以被连接到槽函数上,当信号发出时,槽函数将被调用。

  • destroyed函数

    [signal] void QObject::destroyed(QObject *obj = nullptr)
    
    • 函数说明:

      用于在对象销毁之前发出通知。destroyed 信号在对象销毁之前立即发出。在 destroyed 信号发出之后,对象的所有子对象将立即被销毁。

    • 参数说明:

      obj 是一个指向 QObject 类型的指针,默认值为 nullptr。通常,这个参数是发出信号的对象自身,但在某些情况下,它可以是其他任何 QObject 派生类的对象。

    • 注意事项:

      这个信号不能被阻塞,即使使用 blockSignals(true) 也无法阻止 destroyed 信号的发出。

  • objectNameChanged函数

    [signal] void QObject::objectNameChanged(const QString &objectName)
    
    • 函数说明:

      它在对象的名称被更改后发出。这个信号提供了一个新的对象名称作为参数 objectName

    • 参数说明:

      objectName 是一个 QString 类型的参数,包含了对象更改后的新名称。

    • 注意事项:

      • 这是一个私有信号(private signal)。这意味着虽然它可以在信号连接中使用(即你可以连接这个信号到一个槽函数),但你不能直接发出(emit)这个信号。私有信号通常由框架内部使用。
      • 这是属性 objectName 的通知信号(notifier signal)。在 Qt 中,当一个属性的值发生变化时,可以发出一个通知信号,以便其他部分的代码可以知道并响应这个变化。

六、Static Public Members(静态公共成员)

  可参考:Qt信号槽的5种写法来理解connect函数的重载。

  • connect函数重载:使用宏来指定信号和方法(QT4)

    [static] QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
    
    • 函数说明:

      用于创建信号(signal)和槽(slot)之间的连接。将发送者对象中的信号连接到接收者对象中的槽函数。函数返回一个表示连接的句柄,该句柄可以用于后续断开连接。

      必须使用 SIGNAL()SLOT() 宏来指定信号和方法。

      示例:确保标签总是显示当前滚动条的值。

      QLabel *label = new QLabel;
      QScrollBar *scrollBar = new QScrollBar;
      QObject::connect(scrollBar, SIGNAL(valueChanged(int)),label,  SLOT(setNum(int)));
      

      注意信号和槽参数中不能包含任何变量名,只有类型。

      QObject::connect(scrollBar, SIGNAL(valueChanged(int value)),label, SLOT(setNum(int value)));
      

      一个信号也可以连接到另一个信号,例如:

      class MyWidget : public QWidget {Q_OBJECTpublic:MyWidget();signals:void buttonClicked();private:QPushButton *myButton;
      };MyWidget::MyWidget() {myButton = new QPushButton(this);connect(myButton, SIGNAL(clicked()),this, SIGNAL(buttonClicked()));
      }
      

      一个信号可以连接到多个槽,一个槽也可以连接多个信号。如果一个信号连接到多个槽,当信号发出时,槽将以连接创建的顺序被激活。

    • 参数说明:

      • const QObject *sender:发送者对象

      • const char *signal:信号

      • const QObject *receiver:接受者对象

      • const char *method:槽函数

      • Qt::ConnectionType type:连接类型,这是一个枚举类型

        • Qt::AutoConnection(缺省值)

          如果信号的接收者与发射者在同一个线程中,就使用 Qt:: DirectConnection 方式 ;否则使用 Qt: :QueuedConnection 方式, 在信号发射时自动确定关联方式。

        • Qt::DirectConnection

          信号被发射时槽函数立即执行, 槽函数与信号在同一个线程

        • Qt::QueuedConnection

          在事件循环回到接收者线程后执行槽函数,槽函数与信号在不同的线程。

        • Qt::BlockingQueuedConnection

          Qt::QueuedConnection 相似,只是信号线程会阻塞直到槽函数执行完毕。 当信号与槽函数在同一个线程时,绝对不能使用这种方式,否则会造成死锁。

        • Qt::UniqueConnection

          这是一个可以与上述任一连接类型结合使用的标记,使用位或(bitwise OR)操作。当设置 Qt::UniqueConnection 时,如果连接已经存在(即相同的信号已经连接到相同对象对的相同槽),QObject::connect() 将失败。

    • 函数返回值

      函数返回 QMetaObject::Connection 类型,这是一个连接的句柄。如果成功连接信号和槽,句柄有效;如果无法创建连接,句柄无效。可以通过将句柄强制转换为布尔值来检查其有效性。

    • 注意事项:

      Qt::UniqueConnections 不适用于 lambda 表达式、非成员函数和 functors;它们只适用于连接到成员函数。

  • connect函数重载:使用 QMetaMethod 对象来指定信号和方法

    [static] QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection)
    
    • 函数说明:

      用于创建信号(signal)和槽(slot)之间的连接。将发送者对象中的信号连接到接收者对象中的槽函数。函数返回一个表示连接的句柄,该句柄可以用于后续断开连接。

      与使用 SIGNALSLOT 宏的 connect 函数相比,这个版本使用 QMetaMethod 对象来指定信号和方法,这提供了更高的灵活性和动态性。

    • 参数说明:

      • sender 是发出信号的对象。
      • signalQMetaMethod 类型,表示要连接的信号。
      • receiver 是接收信号并调用方法的对象。
      • methodQMetaMethod 类型,表示信号触发时要调用的方法。
      • typeQt::ConnectionType 枚举,默认为 Qt::AutoConnection,描述连接的类型,决定信号是立即传递还是排队传递。
    • 函数返回值:

      • 成功创建连接时,返回一个 QMetaObject::Connection 类型的句柄。
      • 如果无法创建连接(例如,参数无效),返回一个无效的连接句柄。
  • connect函数重载:带 QMetaMethod 参数版本的重载,指定了接收者对象

    QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type = Qt::AutoConnection) const
    
    • 函数说明:

      这个 connect 函数是对之前提到带 QMetaMethod 参数版本的重载。它将发送者(sender)对象的信号连接到当前对象(this)的方法(method)。

      等价于

      connect(sender, signal, this, method, type)
      

      每次成功建立连接时,都会发出一个信号。因此,重复的连接会导致发出两个信号。如果需要断开已建立的连接,可以使用 disconnect() 函数。

  • connect函数重载:使用模板和成员函数指针来创建信号和槽之间的连接(QT5)

    [static] template <typename PointerToMemberFunction> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)
    
    • 函数说明:

      这个 connect 函数是一个模板函数,接受成员函数指针 PointerToMemberFunction 作为信号和方法的参数类型。

      它创建了一个指定类型的连接,将发送者对象的信号连接到接收者对象的方法。如果成功,返回一个 QMetaObject::Connection 类型的连接句柄,可用于后续断开连接;如果连接失败,返回一个无效的句柄。

      信号和槽的要求:信号必须是在头文件中声明为信号的函数。槽函数可以是任何可以连接到信号的成员函数。只要信号具有与槽对应的参数类型或存在隐式类型转换,槽就可以连接到给定的信号。

      示例:

      QLabel *label = new QLabel;
      QLineEdit *lineEdit = new QLineEdit;
      QObject::connect(lineEdit, &QLineEdit::textChanged,label,  &QLabel::setText);
      

      如果一个信号连接到多个槽,当信号发出时,槽将按照连接创建的顺序被激活。

      默认情况下,每次建立连接都会发出一个信号,重复的连接会发出两个信号。所有这些连接都可以用一个 disconnect() 调用来断开。

      如果传递 Qt::UniqueConnection 类型,只有在不是重复连接的情况下才会建立连接。如果有重复连接(完全相同的信号连接到相同对象上的相同槽),连接将失败,connect 将返回一个无效的 QMetaObject::Connection

      如果信号被排队,参数必须是 Qt 的元对象系统已知的类型,因为 Qt 需要复制参数以在后台的事件中存储它们。

    • 参数说明:

      • 模板参数 PointerToMemberFunction

        这是一个指向成员函数的指针类型。在 C++ 中,成员函数可以被当作指针来处理,这允许将它们用作模板参数。

      • sender :这是一个指向 QObject 类型的常量指针,表示发出信号的对象。

      • signal :这是一个指向成员函数的指针,表示 sender 对象将发出的信号。成员函数的签名应该与信号的签名匹配

      • receiver :这是一个指向 QObject 类型的常量指针,表示接收信号并调用相应方法的对象。

      • method :这是一个指向成员函数的指针,表示 receiver 对象中信号触发时要调用的槽函数。成员函数的签名应该与槽的签名匹配。

      • typeQt::ConnectionType 枚举,默认为 Qt::AutoConnection,描述连接的类型,决定信号是立即传递还是排队传递。

  • connect函数重载:将一个信号连接到一个 functor(函数对象或 lambda 表达式)

    [static] template <typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
    
    • 函数说明:

      创建一个从发送者对象的信号到 functor 的连接,并返回一个连接句柄。

      信号与槽的要求

        信号必须是在头文件中声明为信号的函数。槽函数可以是任何可以连接到信号的函数或 functor。如果信号至少有与槽相同数量的参数,并且信号和槽的对应参数类型之间存在隐式转换,则可以将函数连接到给定信号。如果 functor 和信号具有完全相同数量的参数,可以将 functor 连接到信号。

      示例:连接到函数对象

      void someFunction();
      QPushButton *button = new QPushButton;
      QObject::connect(button, &QPushButton::clicked, someFunction);
      

      示例:连接到lambda表达式

      QByteArray page = ...;
      QTcpSocket *socket = new QTcpSocket;
      socket->connectToHost("qt-project.org", 80);
      QObject::connect(socket, &QTcpSocket::connected, [=] () {socket->write("GET " + page + "\r\n");});
      

      如果发送者对象被销毁,连接将自动断开。但是,应当确保在信号被发出时,functor 中使用的所有对象仍然有效存活。

    • 参数说明:

      • 模板参数 PointerToMemberFunction

        指向成员函数的指针 PointerToMemberFunction,用于指定信号;

      • 模板参数 Functor

        Functor 类型,可以是任何可调用的 functor 或 lambda 表达式。

      • sender :这是一个指向 QObject 类型的常量指针,表示发出信号的对象。

      • signal :这是一个指向成员函数的指针,表示 sender 对象将发出的信号。成员函数的签名应该与信号的签名匹配

      • functorFunctor 类型,可以是任何可调用的 functor 或 lambda 表达式。

  • connect函数重载:允许将一个信号连接到一个 functor,并且指定了连接所属的事件循环上下文

    [static] template <typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)
    
    • 函数说明:

      允许将一个信号连接到一个 functor,并且指定了连接所属的事件循环上下文,返回一个连接句柄。

      信号和槽的要求

        信号必须是在类头文件中声明的信号。槽可以是任何可以连接到信号的函数或 functor。如果信号至少有与槽相同数量的参数,并且信号和槽的对应参数类型之间存在隐式转换,则可以将函数连接到信号。

      示例:函数对象

      void someFunction();
      QPushButton *button = new QPushButton;
      QObject::connect(button, &QPushButton::clicked, this, someFunction, Qt::QueuedConnection);
      

      示例:lambda函数

      QByteArray page = ...;
      QTcpSocket *socket = new QTcpSocket;
      socket->connectToHost("qt-project.org", 80);
      QObject::connect(socket, &QTcpSocket::connected, this, [=] () {socket->write("GET " + page + "\r\n");}, Qt::AutoConnection);
      

      如果发送者对象或上下文对象被销毁,连接将自动断开。需要注意:在信号发出时,functor 中使用的所有对象都应该是活跃的。如果对象已经被销毁,这可能导致未定义行为或程序崩溃。

    • 参数说明:

      • 模板参数 PointerToMemberFunction

        指向成员函数的指针 PointerToMemberFunction,用于指定信号;

      • 模板参数 Functor

        Functor 类型,可以是任何可调用的 functor 或 lambda 表达式。

      • sender :这是一个指向 QObject 类型的常量指针,表示发出信号的对象。

      • signal :这是一个指向成员函数的指针,表示 sender 对象将发出的信号。成员函数的签名应该与信号的签名匹配

      • context:指定了 functor 应当被放置在的具体事件循环中。这通常用于多线程编程,以确保 functor 在正确的线程中执行。

      • functorFunctor 类型,可以是任何可调用的 functor 或 lambda 表达式。

    • 注意事项

      • Qt::UniqueConnection 的限制Qt::UniqueConnection 不适用于 lambda 表达式、非成员函数和 functors,只适用于连接到成员函数。
  • disconnect函数重载:使用宏来指定信号和方法

    [static] bool QObject::disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
    
    • 函数说明:

      disconnect 函数用于断开发送者(sender)对象的信号与接收者(receiver)对象的方法之间的连接。如果连接成功断开,返回 true;否则返回 false

      当连接的信号或槽所在的对象被销毁时,信号-槽连接会被自动移除。

      断开连接的三种典型用法

      • 断开对象所有信号的所有连接:使用 disconnect(myObject, nullptr, nullptr, nullptr)

        myObject->disconnect();
        
      • 断开特定信号的所有连接:使用 disconnect(myObject, SIGNAL(mySignal()), nullptr, nullptr)

        myObject->disconnect(SIGNAL(mySignal()));
        
      • 断开特定接收者的所有连接:使用 disconnect(myObject, nullptr, myReceiver, nullptr)

        myObject->disconnect(myReceiver);
        

      使用 nullptr 作为通配符

      • 发送者不能为 nullptrdisconnect 函数调用中发送者参数不能为 nullptr。这意味着你不能在单个调用中断开来自多个对象的信号。
      • 信号参数 nullptr 的行为:如果信号参数为 nullptr,则会从任何信号断开接收者和方法;如果指定了信号,则只断开指定信号的连接。
      • 接收者参数 nullptr 的行为:如果接收者参数为 nullptr,则会从信号断开任何连接;如果指定了接收者,则不会断开其他对象中的槽的连接。
      • 方法参数 nullptr 的行为:如果方法参数为 nullptr,则会从接收者断开任何连接;如果指定了方法,则只断开命名为此方法的槽的连接,其他槽不受影响。如果省略了接收者,方法参数必须为 nullptr,因此你不能在所有对象上断开特定命名的槽。
  • disconnect函数重载:使用 QMetaMethod 来表示要断开连接的信号和方法

    [static] bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method)
    
    • 函数说明:

      disconnect 函数用于断开发送者(sender)对象的信号与接收者(receiver)对象的方法之间的连接。如果连接成功断开,返回 true;否则返回 false

  • disconnect函数重载

    bool QObject::disconnect(const char *signal = nullptr, const QObject *receiver = nullptr, const char *method = nullptr) const
    
    • 函数说明:
      • 此函数用于断开指定的信号和槽之间的连接。如果提供了信号、接收者和方法的名称,它将只断开与这些参数匹配的连接。
      • 如果参数为 nullptr(默认值),则所有从该对象发出的信号的连接将被断开,或者如果调用者是接收者,那么该对象的所有槽的连接将被断开。
    • 参数说明:
      • signal 是一个指向 const char 的指针,表示要断开的信号的名称。
      • receiver 是一个指向 QObject 类型的常量指针,表示接收信号的对象。
      • method 是一个指向 const char 的指针,表示信号触发时要调用的方法的名称。
    • 注意事项:
      • 断开连接是可选的,因为当涉及的对象被销毁时,Qt 会自动断开所有信号和槽的连接。
      • 如果信号或槽的参数不匹配,它们之间的连接不会建立,因此也无法被 disconnect 断开。
  • disconnect函数重载

    bool QObject::disconnect(const QObject *receiver, const char *method = nullptr) const
    
    • 函数说明:

      断开了当前对象中的所有信号与接收者的特定方法的连接。 当参与连接的任一对象被销毁时,信号-槽连接会被自动移除。

  • disconnect函数重载

    [static] bool QObject::disconnect(const QMetaObject::Connection &connection)
    
    • 函数说明:

      断开一个连接。 断开连接到 functors 或 lambda 表达式的信号。

  • disconnect函数重载:使用模板和成员函数指针来表示信号与槽

    [static] template <typename PointerToMemberFunction> bool QObject::disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method)
    
    • 函数说明:

      断开发送者对象的信号与接收者对象的方法之间的连接。如果连接成功断开,返回 true;否则返回 false

      这个 disconnect 函数是一个模板函数,使用成员函数指针 PointerToMemberFunction 来指定信号和方法。

      当连接的信号或槽所在的对象被销毁时,信号-槽连接会被自动移除。

      断开连接的三种典型方法

      • 断开对象所有信号的所有连接:使用 disconnect(myObject, nullptr, nullptr, nullptr)
      • 断开特定信号的所有连接:使用 disconnect(myObject, &MyObject::mySignal(), nullptr, nullptr)
      • 断开特定接收者的所有连接:使用 disconnect(myObject, nullptr, myReceiver, nullptr)

      使用 nullptr 作为通配符`

      • 发送者不能为 nullptrdisconnect 函数调用中发送者参数不能为 nullptr。这意味着你不能在单个调用中断开来自多个对象的信号。
      • 信号参数 nullptr 的行为:如果信号参数为 nullptr,则会从任何信号断开接收者和方法;如果指定了信号,则只断开指定信号的连接。
      • 接收者参数 nullptr 的行为:如果接收者参数为 nullptr,则会从信号断开任何连接;如果指定了接收者,则不会断开其他对象中的槽的连接。
      • 方法参数 nullptr 的行为:如果方法参数为 nullptr,则会从接收者断开任何连接;如果指定了方法,则只断开命名为此方法的槽的连接,其他槽不受影响。如果省略了接收者,方法参数必须为 nullptr,因此你不能在所有对象上断开特定命名的槽。
  • staticMetaObject静态成员变量

    const QMetaObject QObject::staticMetaObject
    
    • 说明:

      staticMetaObjectQObject 类的一个静态变量,它存储了类的元对象信息。元对象包含了继承自 QObject 的类的详细信息,例如类名、超类名、属性、信号和槽。每个包含 Q_OBJECT 宏的类都会拥有一个元对象。

      元对象的作用

      • 信号/槽连接机制:元对象信息对于 Qt 的信号和槽系统至关重要。
      • 属性系统:元对象同样支持 Qt 的属性系统。
      • inherits() 函数:该函数使用元对象来判断一个对象是否继承自特定的类。

      如果你有一个对象的指针,可以使用 metaObject() 方法来检索与该对象相关联的元对象。

      示例:

      QPushButton::staticMetaObject.className();  // returns "QPushButton"QObject *obj = new QPushButton;
      obj->metaObject()->className();             // returns "QPushButton"
      
  • tr函数:Qt多语言与国际化

    [static] QString QObject::tr(const char *sourceText, const char *disambiguation = nullptr, int n = -1)
    
    • 函数说明:

      tr函数用于获取sourceText的翻译文本。如果存在相应的翻译字符串,它将返回翻译后的文本;如果没有找到翻译,它将返回源文本的UTF-8编码形式。

      示例:

      void MainWindow::createActions()
      {QMenu *fileMenu = menuBar()->addMenu(tr("&File"));...
      
    • 参数说明:

      • sourceText:需要翻译的源文本,以C风格的字符串提供。
      • disambiguation:(可选)用于区分同一文本在不同上下文中的不同含义的字符串。如果未提供,默认值为nullptr
      • n:(可选)用于处理复数形式的整数参数。当文本需要根据数量变化而变化时使用。

七、Protected Functions(受保护的函数)

  • childEvent函数

    [virtual protected] void QObject::childEvent(QChildEvent *event)
    
    • 函数说明:

      childEvent是一个受保护的虚函数,可以在子类中被重写(reimplemented),以便接收关于子对象的事件。

      子对象事件类型

      • QEvent::ChildAdded:当子对象被添加到父对象时发出。
      • QEvent::ChildRemoved:当子对象从父对象移除时发出。
      • QEvent::ChildPolished:当子对象完成构造(polished)时发出,或者在构造期间添加了已完成构造的子对象。

      对于每个子控件,你会收到一个ChildAdded事件,零个或多个ChildPolished事件,以及一个ChildRemoved事件。

    • 参数说明:

      参数event指向一个QChildEvent对象,该对象包含了事件的详细信息。

    • 注意事项:

      虽然ChildPolished事件通常表示子对象的构造已完成,但这不是绝对的保证。开发者在处理这些事件时应考虑到这一点。

  • connectNotify函数

    [virtual protected] void QObject::connectNotify(const QMetaMethod &signal)
    
    • 函数说明:

      connectNotify是一个受保护的虚函数,当有槽连接到当前对象的某个信号时,该函数被调用。

      如果需要将signal与特定的信号进行比较,可以使用QMetaMethod::fromSignal()方法。这在确定哪个信号被连接时非常有用。

      if (signal == QMetaMethod::fromSignal(&MyObject::valueChanged)) {// signal is valueChanged
      }
      
    • 参数说明:

      参数signal是一个QMetaMethod对象,表示被连接的信号。

    • 注意事项:

      • 使用connectNotify可能会违反面向对象编程中的模块化原则,因为它依赖于类的内部实现细节。
      • onnectNotify可能在执行连接操作的线程中被调用,这个线程可能与对象所在的线程不同。这需要注意线程安全问题。
  • disconnectNotify函数

    [virtual protected] void QObject::disconnectNotify(const QMetaMethod &signal)
    
    • 函数说明:

      disconnectNotify是一个受保护的虚函数,当当前对象的某个信号的连接被断开时,该函数被调用。

      如果对象断开了所有信号(例如,调用disconnectsignal参数为nullptr),disconnectNotify只会被调用一次,并且signal将是一个无效的QMetaMethodQMetaMethod::isValid()返回false

    • 参数说明:

      参数signal是一个QMetaMethod对象,表示被断开连接的信号。

    • 注意事项:

      • 使用disconnectNotify可能会违反面向对象编程中的模块化原则,因为它依赖于类的内部实现细节。
      • disconnectNotify可能在执行断开连接操作的线程中被调用,这个线程可能与对象所在的线程不同。此外,这个函数可能在持有QObject内部互斥锁(mutex)的情况下被调用。因此,在重写时不允许重新进入任何QObject函数,如果你在重写中锁定了互斥锁,请确保不要在其他地方持有该互斥锁调用QObject函数,否则会导致死锁。
  • customEvent函数

    [virtual protected] void QObject::customEvent(QEvent *event)
    
    • 函数说明:

      customEvent是一个受保护的虚函数,可以在子类中被重写(reimplemented),以便接收自定义事件。

      自定义事件是用户定义的事件,它们具有类型值,自定义事件的类型值必须至少为QEvent::User,需要确保自定义事件的类型不会与标准Qt事件类型冲突。

    • 使用场景:

      当需要在应用程序中实现特定的、非标准的事件处理时,自定义事件非常有用。例如,当第三方库或框架需要与Qt应用程序交互时,可能会使用自定义事件。

  • isSignalConnected函数

    [protected] bool QObject::isSignalConnected(const QMetaMethod &signal) const
    
    • 函数说明:

      isSignalConnected函数用于检查指定的信号是否已经连接到至少一个槽(receiver)。如果连接存在,返回true;否则返回false

    • 参数说明:

      参数signal必须是当前对象的信号成员,否则行为是未定义的。

    • 示例:

       static const QMetaMethod valueChangedSignal = QMetaMethod::fromSignal(&MyObject::valueChanged);if (isSignalConnected(valueChangedSignal)) {QByteArray data;data = get_the_value();       // expensive operationemit valueChanged(data);}
      

      使用isSignalConnected来检查valueChangedSignal信号是否连接,根据检查结果决定是否发出valueChanged信号。

    • 注意事项:

      使用isSignalConnected可能会违反面向对象编程中的模块化原则,因为它依赖于类的内部实现细节。尽管如此,在某些情况下,它可能有助于优化资源访问,特别是当需要在连接建立时才执行昂贵的初始化操作时。

  • receivers函数

    [protected] int QObject::receivers(const char *signal) const
    
    • 函数说明:

      receivers函数返回连接到指定信号的接收者(receivers)的数量。

      由于槽和信号都可以作为信号的接收者,并且相同的连接可以多次建立,因此接收者的数量等同于从该信号发出的连接数量。

      当调用这个函数时,可以使用SIGNAL()宏来传递指定信号

      示例:

       if (receivers(SIGNAL(valueChanged(QByteArray))) > 0) {QByteArray data;get_the_value(&data);       // expensive operationemit valueChanged(data);}
      
    • 参数说明:

      signal:使用SIGNAL()宏来传递需要查询的特定信号的名称。这个宏是Qt宏系统中的一部分,用于从信号的成员函数指针中提取信号的名称。

    • 注意事项:

      使用receivers可能会违反面向对象编程中的模块化原则,因为它依赖于类的内部实现细节。尽管如此,在某些情况下,它可能有助于优化资源访问,特别是当需要在连接建立时才执行昂贵的初始化操作时。

  • sender函数

    [protected] QObject *QObject::sender() const
    
    • 函数说明:

      用于在槽函数中确定是哪个对象发出了信号。返回一个指向发送信号对象的指针。

      • 如果在由信号激活的槽中调用此函数,它返回发送信号的对象的指针。否则它将返回nullptr。该指针仅在从该对象的线程上下文中调用此函数时的槽执行期间有效。
      • 如果发送者对象被销毁,返回的指针将变为无效。
      • 如果槽与发送者的信号断开连接,返回的指针也将变为无效。
    • 注意事项:

      • 使用 sender() 函数违反了面向对象的模块化原则。然而,在许多信号连接到单个槽时,获取发送者可能会很有用。

      • 如果槽是通过 Qt::DirectConnection 从其他线程调用的,那么 sender() 返回的指针可能无效。

        Qt::DirectConnection:一种连接类型,允许信号在不同线程间直接调用槽。

  • senderSignalIndex函数

    [protected] int QObject::senderSignalIndex() const
    
    • 函数说明:

      用于在槽函数中获取当前正在执行的槽所对应的信号的元方法索引

      元方法索引是 Qt 元对象系统中用于唯一标识类成员(信号、槽、方法)的整数

      • 如果在由信号激活的槽中调用此函数,它返回信号的元方法索引。
      • 如果在没有相应信号激活的上下文中调用,返回 -1

      对于具有默认参数的信号,此函数总是返回包含所有参数的索引,不管 connect() 时使用了哪个版本。例如,如果有一个信号 destroyed(QObject *obj = nullptr),它将有两个不同的索引(带参数和不带参数),但此函数总是返回带参数的索引。

    • 使用场景:

      当一个槽被多个信号连接,且需要根据不同的信号执行不同的操作时,可以使用 senderSignalIndex 来确定是哪个信号触发了槽。

    • 注意事项:

      • 使用 senderSignalIndex 函数违反了面向对象的模块化原则。然而,在许多信号连接到单个槽时,获取信号索引可能会很有用。
      • 如果槽是通过 Qt::DirectConnection 从其他线程调用的,此函数的返回值无效。不要在此类场景中使用此函数。
  • timerEvent函数

    [virtual protected] void QObject::timerEvent(QTimerEvent *event)
    
    • 函数说明:

      这个事件处理器允许开发者为 QObject 的子类添加自定义的定时器事件处理逻辑。

      当定时器触发时,调用timerEvent 函数。可以在 timerEvent 函数中根据 event 参数中的信息来执行相应的操作。

      示例:

       class MyObject : public QObject{Q_OBJECTpublic:MyObject(QObject *parent = nullptr);protected:void timerEvent(QTimerEvent *event) override;};MyObject::MyObject(QObject *parent): QObject(parent){startTimer(50);     // 50-millisecond timerstartTimer(1000);   // 1-second timerstartTimer(60000);  // 1-minute timerusing namespace std::chrono;startTimer(milliseconds(50));startTimer(seconds(1));startTimer(minutes(1));// since C++14 we can use std::chrono::duration literals, e.g.:startTimer(100ms);startTimer(5s);startTimer(2min);startTimer(1h);}void MyObject::timerEvent(QTimerEvent *event){qDebug() << "Timer ID:" << event->timerId();}
      
    • 参数说明:

      event 是一个指向 QTimerEvent 类的实例的指针,包含了定时器事件的相关信息,如定时器的标识符。

八、Related Non-Members(相关非成员)

  • QObjectList成员

    typedef QObjectList QList<QObject *>;
    
  • qFindChildren函数

    template <typename T> QList<T> qFindChildren(const QObject *obj, const QRegExp &regExp)
    
    • 函数说明:

      查找 obj 的子对象,这些子对象的类型和名称或属性与给定的正则表达式匹配。

      这个函数的重载版本是为了兼容旧的编译器,与QObject的findChildren<T> 成员函数功能相同,建议直接使用 QObject 类的 findChildren<T> 成员函数。

    • 参数说明:

      • const QObject *obj: 一个指向 QObject 类型对象的指针,QObject 是 Qt 中所有对象的基类。
      • const QRegExp &regExp: 一个正则表达式对象,用于匹配对象的名称或属性。
  • qobject_cast函数

    template <typename T> T qobject_cast(QObject *object)
    template <typename T> T qobject_cast(const QObject *object)
    
    • 函数说明:

      用于在运行时将 QObject 派生类的对象转换为指定类型。

      这两个声明是 qobject_cast 函数的模板重载,允许将 QObject 类型的对象指针转换为类型 T 的指针。第一个是针对非 const 对象指针的重载,第二个是针对 const 对象指针的重载。

      如果给定的 object 是类型 T 或其子类的实例,函数将返回转换后的指针。如果 object 不是类型 T 或其子类的实例,或者 objectnullptr,则函数返回 nullptr

    • 参数说明:

      类型 T 必须直接或间接继承自 QObject,并且使用宏 Q_OBJECT 声明。

    • 示例:

      QObject *obj = new QTimer;          // QTimer inherits QObjectQTimer *timer = qobject_cast<QTimer *>(obj);
      // timer == (QObject *)objQAbstractButton *button = qobject_cast<QAbstractButton *>(obj);
      // button == nullptr
      
    • 注意事项:

      如果类型 T 没有使用 Q_OBJECT 宏声明,使用 qobject_cast 的返回值是未定义的。这是因为 qobject_cast 依赖于 Q_OBJECT 宏来正确地进行类型转换

九、Macros(宏)

这一部分后续再写

  • QT_NO_NARROWING_CONVERSIONS_IN_CONNECT

  • Q_CLASSINFO(Name, Value)

    • 说明

      这个宏将额外的信息与类关联起来,这些信息可以通过QObject::metaObject()获取。

      额外的信息以名称字符串(Name string)和值字面量字符串(Value literal string)的形式存在。

      示例:

       class MyClass : public QObject{Q_OBJECTQ_CLASSINFO("Author", "Pierre Gendron")Q_CLASSINFO("URL", "http://www.my-organization.qc.ca")public:...};
      

      这些附加信息可以通过QObject::metaObject()获取。

      [virtual] const QMetaObject *QObject::metaObject() const
      

      还可以使用QMetaObject::classInfo()获取某个附加信息:

      QMetaClassInfo QMetaObject::classInfo(int index) const
      

      返回给定索引的类信息项目的元数据。QMetaClassInfo有两个函数:name()value(),获得类附加信息的名称和值。

  • Q_DISABLE_COPY(Class)

  • Q_DISABLE_COPY_MOVE(Class)

  • Q_DISABLE_MOVE(Class)

  • Q_EMIT

  • Q_ENUM(…)

  • Q_ENUM_NS(…)

  • Q_FLAG(…)

  • Q_FLAG_NS(…)

  • Q_GADGET

  • Q_INTERFACES(…)

  • Q_INVOKABLE

  • Q_NAMESPACE

  • Q_NAMESPACE_EXPORT(EXPORT_MACRO)

  • Q_OBJECT

  • Q_PROPERTY(…)

    • 说明:

      Q_PROPERTY(...) 宏用于在继承自 QObject 的类中声明属性。属性的行为类似于类的成员变量,但它们具有通过元对象系统访问的附加特性。

      使用格式如下:

       Q_PROPERTY(type name(READ getFunction [WRITE setFunction] |MEMBER memberName [(READ getFunction | WRITE setFunction)])[RESET resetFunction][NOTIFY notifySignal][REVISION int][DESIGNABLE bool][SCRIPTABLE bool][STORED bool][USER bool][CONSTANT][FINAL][REQUIRED])
      

      Q_PROPERTY宏定义属性的一些主要关键字的意义

      • READ 指定一个读取属性值的函数,没有 MEMBER关键字时必须设置 READ
      • WRITE指定一个设定属性值的函数,只读属性没有WRITE设置
      • MEMBER 指定一个成员变量与属性关联,成为可读可写的属性,无需再设置 READ和WRITE,可以使用property()setProperty()进行属性读写
      • RESET 是可选的, 用于指定一个设置属性缺省值的函数。
      • NOTIFY是可选的,用于设置一个信号,当属性值变化时发射此信号。
      • DESIGNABLE表示属性是否在 Qt Designer 里可见, 缺省为 true
      • CONSTANT表示属性值是一个常数,对于一个对象实例,READ指定的函数返回值是常数,但是每个实例的返回值可以不一样。具有 CONSTANT 关键字的属性不能有WRlTE和NOTIFY 关键字。
      • FINAL表示所定义的属性不能被子类重载

      属性名称(name)、类型(type)和 READ 函数是必需的。类型(type)可以是 QVariant 支持的任何类型,也可以是用户定义的类型。其他项是可选的,但 WRITE 函数很常见。属性默认值为 true,除了 USER,其默认值为 false

      示例:QWidget 类定义的属性

      Q_PROPERTY(bool focus READ hasFocus) 
      Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) 
      Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
      

      解析:定义enabled属性时用READ和WRITE指定了接口函数,因此,既可以通过property()setProperty()进行属性读写,也可以直接使用接口函数进行读写。直接使用接口函数速度更快。

  • Q_REVISION

  • Q_SET_OBJECT_NAME(Object)

  • Q_SIGNAL

  • Q_SIGNALS

  • Q_SLOT

  • Q_SLOTS

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/46413.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react Ant Design 动态表头添加操作列

模拟后端返回的表头、列表数据 注意&#xff1a;我们要在表头数据中添加一个 render 函数&#xff0c;里面就是你操作列的内容&#xff0c;value是你数据列表每行的对象 &#xff0c;item 是你表头的对象 页面中去处理这个两个数组 dataList.forEach((item, index) > {item.…

昇思25天学习打卡营第24天 | RNN实现情感分类

概述 情感分类是自然语言处理中的经典任务&#xff0c;是典型的分类问题。本节使用MindSpore实现一个基于RNN网络的情感分类模型&#xff0c;实现如下的效果&#xff1a; 输入: This film is terrible 正确标签: Negative 预测标签: Negative输入: This film is great 正确标…

dmasmtool工具详细用法

DMASMTOOL 是 DMASM 文件系统管理工具&#xff0c;提供了一套类 Linux 文件操作命令&#xff0c;用于管理 ASM 文件&#xff0c;是管理、维护 DMASM 的好帮手。DMASMTOOL 工具使用 DMASMAPI 连接到 DMASMSVR&#xff0c;并调用相应的 DMASMAPI 函数&#xff0c;实现创建、拷贝、…

C1W2.LAB.Visualizing Naive Bayes

理论课&#xff1a;C1W2.Sentiment Analysis with Nave Bayes 文章目录 导入包Calculate the likelihoods for each tweetUsing Confidence Ellipses to interpret Nave Bayes 理论课&#xff1a; C1W2.Sentiment Analysis with Nave Bayes 导入包 在下面的练习中&#xff0…

everything搜索不到任何文件-设置

版本&#xff1a; V1.4.1.1024 (x64) 问题&#xff1a;搜索不到任何文件 click:[工具]->[选项]->下图所示 将本地磁盘都选中包含

Python爬虫速成之路(3):下载图片

hello hello~ &#xff0c;这里是绝命Coding——老白~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;绝命Coding-CSDN博客 &a…

SpringMVC源码解析(一):web容器启动流程

SpringMVC源码系列文章 SpringMVC源码解析(一)&#xff1a;web容器启动流程 目录 一、SpringMVC全注解配置1、pom文件2、web容器初始化类(代替web.xml)3、SpringMVC配置类(代替springmvc.xml)4、测试Controller 二、SpringServletContainerInitializer1、web容器初始化入口2、…

从本地到全局:基于图的RAG方法进行查询聚焦原理摘要

摘要 使用检索增强生成&#xff08;RAG&#xff09;从外部知识源检索相关信息&#xff0c;使大型语言模型&#xff08;LLMs&#xff09;能够回答有关私有和/或以前未见过的文档集合的问题。然而&#xff0c;当针对整个文本文档库提出全局问题时&#xff0c;例如“数据集中的主…

音视频入门基础:H.264专题(13)——FFmpeg源码中通过SPS属性获取视频色彩格式的实现

一、引言 通过FFmpeg命令可以获取到H.264裸流文件的色彩格式&#xff08;又译作色度采样结构、像素格式&#xff09;&#xff1a; 在vlc中也可以获取到色彩格式&#xff08;vlc底层也使用了FFmpeg进行解码&#xff09;&#xff1a; 这个色彩格式就是之前的文章《音视频入门基础…

【精品资料】模块化数据中心解决方案(33页PPT)

引言&#xff1a;模块化数据中心解决方案是一种创新的数据中心设计和部署策略&#xff0c;旨在提高数据中心的灵活性、可扩展性和效率。这种方案通过将数据中心的基础设施、计算、存储和网络资源封装到标准化的模块中&#xff0c;实现了快速部署、易于管理和高效运维的目标 方案…

2024最新Cloudways主机使用教程(含最新Cloudways折扣码)

Cloudways是一家提供云托管服务的公司&#xff0c;可以帮助你轻松管理和运行你的网站。本教程是Cloudways主机注册和使用教程。Cloudways界面简洁&#xff0c;使用方便&#xff0c;不需要复杂的设置&#xff0c;就能快速搭建一个WordPress网站。它的主机功能包括高级缓存和Bree…

DepthAnything(2): 基于ONNXRuntime在ARM(aarch64)平台部署DepthAnything

DepthAnything(1): 先跑一跑Depth Anything_depth anything离线怎么跑-CSDN博客 目录 1. 写在前面 2. 安装推理组件 3. 生成ONNX 4. 准备ONNXRuntime库 5. API介绍 6. 例程 1. 写在前面 DepthAnything是一种能在任何情况下处理任何图像的简单却又强大的深度估计模型。 …

KingbaseES数据库逻辑备份还原

数据库版本&#xff1a;KingbaseES V008R006C008B0014 简介 介绍2个KingbaseES用于备份还原的工具&#xff1a; sys_dump&#xff1a;逻辑备份sys_restore&#xff1a;逻辑还原 sys_dump 是 KingbaseES 用于逻辑备份的工具&#xff0c;可以将数据备份为不同类型的文件。支持数据…

ARM功耗管理标准接口之SCMI

安全之安全(security)博客目录导读 思考&#xff1a;功耗管理有哪些标准接口&#xff1f;ACPI&PSCI&SCMI&#xff1f; Advanced Configuration and Power Interface Power State Coordination Interface System Control and Management Interface 下图示例说明了实现…

docker部署canal 并监听mysql

1.部署mysql 需要开启mysql的binlong&#xff0c;和创建好用户等 可以参考这个 Docker部署Mysql数据库详解-CSDN博客 2.部署canal 参考这一篇&#xff1a; docker安装Canal&#xff0c;开启MySQL binlog &#xff0c;连接Java&#xff0c;监控MySQL变化_docker canal-CSD…

内网信息收集——MSF信息收集浏览器记录配置文件敏感信息

文章目录 一、配置文件敏感信息收集二、浏览器密码&记录三、MSF信息收集 域控&#xff1a;windows server 2008 域内机器&#xff1a;win7 攻击机&#xff1a;kali 就是红日靶场&#xff08;一&#xff09;的虚拟机。 一、配置文件敏感信息收集 使用searchall64.exe&#…

【错题集-编程题】四个选项(DFS + 剪枝 + 哈希表)

牛客对应题目链接&#xff1a;四个选项 (nowcoder.com) 一、分析题目 用递归枚举出所有的情况&#xff0c;注意剪枝&#xff1a; 填写某个数时&#xff0c;要看看还有没有剩余次数。填写某个数时&#xff0c;要看看符不符合若干题的选项必须相同。 二、代码 // 值得学习的代码…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(六)-人工智能控制的自主无人机用例

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

SparkStreaming--scala

文章目录 第1关&#xff1a;QueueStream代码 第2关&#xff1a;File Streams代码 第1关&#xff1a;QueueStream 任务描述 本关任务&#xff1a;编写一个清洗QueueStream数据的SparkStreaming程序。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.如何使用S…

OrangePi AI Pro 实测:感受 AI 应用的独特魅力与强大性能

OrangePi AiPro介绍和初始化配置 小寒有话说一、OrangePi AiPro介绍1. 主板详情2. 开发配置3. 镜像烧录4. 设备连接5. WiFi连接6. NVMe SSD的安装和挂载7. 更新下载源并下载必要的软件8. 扩展内存 二、Jupyter Lab AI测评应用案例1. 获取Jupyter Lab 网址链接2. 图像提取文字3.…