qt 的核心:元对象系统、属性系统、对象树、信号槽

Qt真正的核心,元对象系统、属性系统、对象模型、对象树、信号槽

对象模型

1、一种非常强大的无缝对象通信机制,称为信号槽。

2、可查询和可设计的对象属性。

3、强大的事件Event和事件过滤器。

4、用于国际化的上下文字符串翻译。

5、高精度且先进的定时器QTimer,使得在事件驱动GUI中更优雅的集成更多任务成为可能。

6、以自然的方式组织对象所有权的分层和可查询的对象树,几乎所有的类都继承于QObject,且可通过QObject::inherits()查询某对象是否是一个类的实例,该类继承了QObject继承树中指定的类。

7、当被引用的对象被销毁时,保护指针(QPointer)会自动设置为0,不像普通的c++指针,当它们的对象被销毁时就会变成悬空指针。

8、提供qobject_cast实现跨库边界工作的动态类型转换。

9、提供Q_DECLARE_METATYPE实现自定义数据类型。

Qt的许多特性都是基于对QObject的继承,用标准的c++技术实现的。其他的,比如对象通信(信号槽)机制和动态属性系统,需要Qt的元对象编译器(moc)提供的元对象系统。

Qt元对象系统(QMetaObject)

Qt 的元对象系统叫 Mate-Object-System,提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。即使编译器不支持RTTI(RTTI的实现耗费了很大的时间和存储空间,这就会降低程序的性能),我们也能动态获取类型信息

但是,元对象是基于三个条件的:

 1、该类必须继承自QObject类

 2、必须在类的私有声明区声明Q_OBJECT宏(在类定义的时候,如果没有指定public,
则默认为private,用来启用元对象功能,比如动态属性、信号和槽)。 

 3、 元对象编译器Meta-Object Compiler(moc)为 QObject的子类实现元对象 
特性提供必要的代码。

有了元对象系统后,我们就可以使用Qt的信号和槽了。

moc(Meta-Object Compiler)元对象预编译器。

moc读取一个c++头文件。如果它找到包含Q_OBJECT宏的一个或多个类声明,它会生成一个包含这些类的元对象代码的c++源文件,并且以moc_作为前缀。

信号和槽机制、运行时类型信息和动态属性系统需要元对象代码。

由moc生成的c++源文件必须编译并与类的实现联系起来。通常,moc不是手工调用的,而是由构建系统自动调用的。

 获取类关联的元对象的函数是:metaObject

 QMetaObject  *mtobj = QObject::metaObject()

QMetaObject 的className函数可在运行时返回类的名称字符串。

    QObject *btn = new QPushButton();
    QString str = btn->metaObject()->className();
    qDebug() << str;   // "QPushButton"

属性系统

QObject的 setProperty和property 用于通过属性名称动态设置和获取属性值。其实主要实现c++和qml交互

由于元对象系统的特点,这就保证了Qt属性系统是独立于编译器和平台的。不仅如此,我们还可以使用Q_PROPERTY()宏来定义编译期的静态属性。

作用就是:当一个类的成员变量或者成员函数用属性系统处理一下,它们就从C++内部中暴露出来,而且大家都认得。

Q_PROPERTY宏用来定义可通过元对象系统访问的属性,通过它定义的属性,可以在QML中访问、修改,也可以在属性变化时发射特定的信号。

Q_PROPERTY()宏定义一个返回值类型为type,名称为name的属性,用READ、WRITE关键字定义属性的读取、写入函数,还有其他的一些关键字定义属性的一些操作特性。属性的类型可以是QVarient支持的任何类型,也可以用户自定义类型。

READ:用于读取属性值,如果未指定成员变量(通过MEMBER ),则需要读取访问器函数。

WRITE:写访问器函数是可选的。用于设置属性值。它必须返回void,并且必须只接受一个参数,要么是属性的类型,要么是指向该类型的指针或引用。

MEMBER:如果未指定读取访问器函数,则需要成员变量关联。这使得给定的成员变量可读写,而无需创建读写访问器函数。如果需要控制变量访问,除了成员变量关联(但不是两者)之外,还可以使用读或写访问器函数。

RESET:复位功能是可选的。它用于将属性设置回其特定于上下文的默认值。

NOTIFY:通知信号是可选的。如果已定义,它应该指定该类中的一个现有信号,该信号在属性值更改时发出。成员变量的通知信号必须采用零个或一个参数,这些参数必须与属性的类型相同。参数将采用属性的新值。仅当属性确实发生更改时才应发出NOTIFY信号,以避免绑定在QML中被不必要地重新计算。

头文件:
#ifndef COLORMAKER_H
#define COLORMAKER_H
#include <QObject>

class ColorMaker : public QObject
{
    Q_OBJECT
public:
    explicit ColorMaker(QObject *parent = nullptr);
    ~ColorMaker();

     Q_PROPERTY(int value READ getvalue WRITE setvalue NOTIFY valueChanged);

    int getvalue() const;
    void setvalue(const int& value);
signals:
    void valueChanged(int value);
private:
    int m_value;
};

#endif // COLORMAKER_H

源文件
#include "ColorMaker.h"

ColorMaker::ColorMaker(QObject *parent)
{
}
ColorMaker::~ColorMaker()
{

}
int ColorMaker::getvalue() const
{
    return m_value;

}
void ColorMaker::setvalue(const int &value)
{
    m_value = value;
    emit valueChanged(m_value);
}
#include "widget.h"
#include "ui_widget.h"

#include "ColorMaker.h"
#include <QDebug>
#include <QMetaProperty>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    ColorMaker *cm = new ColorMaker();
    connect(cm,&ColorMaker::valueChanged,this,&Widget::recv);

    cm->setvalue(1);
    int value = cm->getvalue();
    cm->setProperty("value", 2);
    value = cm->property("value").toInt();

   QObject *object  = cm;
   const QMetaObject *metaobject = object->metaObject();
   int ncount = metaobject->propertyCount();
   for (int i = 0; i < ncount; ++i)
   {
       QMetaProperty metaproperty = metaobject->property(i);
       const char *name = metaproperty.name();
       qDebug() << name;
       QVariant value = object->property(name);
       qDebug() << value;
   }
}

Widget::~Widget()
{
    delete ui;
}

void Widget::recv(int nval)
{
    int a = nval;
    qDebug() << a;
}

使用QObject的property()方法访问属性,如果该属性定义了WRITE方法,还可以使用setProperty()修改属性。

    bool setProperty(const char *name, const QVariant &value);
    QVariant property(const char *name) const;

 QPushButton *button = new QPushButton;
 QObject *object = button;

 button->setDown(true);
 object->setProperty("down", true);

QObject *object = ...
const QMetaObject *metaobject = object->metaObject();
int count = metaobject->propertyCount();
for (int i = 0; i < count; ++i) 
{
    QMetaProperty metaproperty = metaobject->property(i);
    const char *name = metaproperty.name();
    QVariant value = object->property(name);
    ...
}

Q_PROPERTY用于c++类注册到qml交互上。在c++的变化发送信号,而在qml上接收信号,实现处理槽函数。

这个使用于qml导出到c++类,c++类获取和设置qml的属性。

    QObject* root = NULL;
     QList<QObject*> rootObjects = engine.rootObjects();
     int count = rootObjects.size();
     for(int i=0; i<count; ++i) {
         if(rootObjects.at(i)->objectName() == "rootObject") {
             root = rootObjects.at(i);
             break;
         }
     }
     
     QObject* startButton = root->findChild<QObject*>("startButton");
     startButton->setProperty("text","start");


 关于通过属性实现c++和qml通讯关联的介绍参考:qt qml与c++_小飞侠hello的博客-CSDN博客

对象树

QObject类中存在一个私有变量QList<QObject *>用来存储这个类的子类们,当给一个对象指定一个父对象时,QList会将自己加入到父对象的children()列表中,也就是加入到QList<QObject *>变量中。

使用对象树的意义:

        在父对象调用完毕被调用析构函数的时候,该父对象的子对象们也会被析构,析构顺序和构造顺序相反:

        构造顺序:父对象->子对象

        析构顺序:子对象->父对象

这样的机制在GUI编程中非常有用,可以减少代码冗余,而不用去一个一个从堆区把它们delete掉。

1.每个继承自QObject类的对象通过它的对象链表(QObjectList)来管理子类对象,当用户创建一个子对象时,其对象链表相应更新子类对象信息,对象链表可通过children()获取。

2.当父对象析构的时候,其对象链表中的所有(子)对象也会被析构,父对象会自动将其从父对象列表中删除。Qt 保证没有对象会被 delete 两次。开发中手动回收资源时建议使用deleteLater代替delete,因deleteLater多次是安全的,而delete多次是不安全的。

对象树所带来的问题:

        构造函数在创建对象时被调用,也就是说如果子对象优先于父对象被创建(调用构造函数),在析构的时候,对象树会进行两次delete操作,这时候程序会报错。因为在栈里是先进后出,即先调用构造函数,会后调用析构函数。

       延伸:如果在构造时设置父对象为 NULL,那么当前实例不会有父对象存在,Qt 也不会自动析构该实例,除非实例超出作用域导致析构函数被调用,或者用户在恰当时机使用 delete 操作符或者使用 deleteLater 方法。

qobject_cast

T qobject_cast ( QObject * object )
本方法返回object向下的转型T,如果转型不成功则返回0,如果传入的object本身就是0则返回0。

在使用时有两个限制:

    1# T类型必须继承自QObject。

    2# 在声明时必须有Q_OBJECT宏。


QMetaObject::invokeMethod()

可以使用QMetaObject::invokeMethod()调用QObject的某个注册到元对象系统中的方法。无论这个方法是公有的、保护的还是私有的

bool QMetaObjcet:invokeMethod(
						QObject* obj, 
						const char* member,
						Qt::ConnectionType type,
						QGenericReturnArgument ret,
						QGenericReturnArgument  vla0 = QGenericReturnArgument(0),
						QGenericReturnArgument  vla1 = QGenericReturnArgument(),
						QGenericReturnArgument  vla2 = QGenericReturnArgument(),
						QGenericReturnArgument  vla3 = QGenericReturnArgument(),
						QGenericReturnArgument  vla4 = QGenericReturnArgument(),
						QGenericReturnArgument  vla5 = QGenericReturnArgument(),
						QGenericReturnArgument  vla6 = QGenericReturnArgument(),
						QGenericReturnArgument  vla7 = QGenericReturnArgument(),
						QGenericReturnArgument  vla8 = QGenericReturnArgument(),
						QGenericReturnArgument  vla9 = QGenericReturnArgument());

返回值:返回true说明调用成功;返回false,要么是因为没有你说的那个方法,要么是参数类型不匹配;
obj:被调用对象的指针;
member:方法名字   必须是信号、槽,以及Qt元对象系统能识别的类型, 如果不是信号和槽,可以使用qRegisterMetaType()来注册数据类型。此外,使用Q_INVOKABLE来声明函数,也可以正确调用。
type:连接类型;invokeMethod为信号槽而生,你可以指定连接类型,如果被调用的对象和发起调用的线程是同一线程,那么可以使用Qt::DirectConnection、Qt::AutoConnection、Qt::QueuedConnection,如果被调用对象在另一个线程,那么建议使用Qt::QueuedConnection;
ret:接收返回值;
然后就是多达10个可以传递给被调用方法的参数;(看来信号槽的参数个数是有限制的,最好不要超过10个)

QGenericArgument和QGenericReturnArgument是内部帮助程序类,由于可以动态调用信号和槽,因此必须使用Q_ARG()和Q_RETURN_ARG()宏来封装参数

注意:此功能是线程安全的。

#ifndef COLORMAKER_H
#define COLORMAKER_H
#include <QObject>

class CTest
{
public:
    CTest(){}
    int nAge;
    QString strName;
};

Q_DECLARE_METATYPE(CTest)

class ColorMaker : public QObject
{
    Q_OBJECT
public:
    explicit ColorMaker(QObject *parent = nullptr);
    ~ColorMaker();

    Q_PROPERTY(int value READ getvalue WRITE setvalue NOTIFY valueChanged);
    Q_PROPERTY(CTest test READ gettest WRITE settest NOTIFY testChanged);//使用自定义的类

    int getvalue() const;
    void setvalue(const int& value);

    CTest gettest() const;
    void settest(const CTest& test);

signals:
    void valueChanged(int value);
    void testChanged(CTest test);
private slots:
    QString testslot(int n);
private:
    int m_value;
    CTest m_test;
};

#endif // COLORMAKER_H



QString ColorMaker::testslot(int n)
{
    return "q";
}


调用:
    ColorMaker *cm = new ColorMaker();
    QString retVal;
    QMetaObject::invokeMethod(cm,"testslot", Qt::DirectConnection,
                 Q_RETURN_ARG(QString, retVal),
                 Q_ARG(int,1));

_ENUMS宏

要导出的类定义了想在QML使用的枚举类型,可以使用Q_ENUMS宏将该枚举类型注册到元对象系统中。

Q_INVOKABLE宏

定义一个类的成员函数时使用Q_INVOKABLE宏来修饰,就可以让该方法被元对象系统调用。
这个宏必须放在返回类型前面。

延伸:普通类成员函数是不能直接在qml使用。除非是声明为槽函数或者用Q_INVOKABLE声明函数。

    Q_INVOKABLE void setAlgorithm(GenerateAlgorithm algorithm);
public slots:
     void setcolor();

所以:Q_INVOKABLE的作用有:
1.c++和qml混用。在c++类中用Q_INVOKABLE声明函数。这样可以在qml直接调用。

2.在跨线程编程中的使用。需要QMetaObject::invokeMethod()结合。将方法声明为Q_INVOKABLE,并且在另一线程中用invokeMethod唤起。

延伸:只有信号、槽以及被标记成Q_INVOKABLE的方法才能够被其它线程所触发调用。如果你不想通过跨线程的信号、槽这一方法来实现调用驻足在其他线程里的QObject方法。另一选择就是将方法声明为Q_INVOKABLE,并且在另一线程中用invokeMethod唤起。


 

信号槽

前提:如果没有消息循环,那么Qt的信号和槽无法完全使用。

信号:

signals:    
void startGetDataThread();    
void sendPointer(MainWindow*);

1.声明一个信号要使用signals关键字。

2.在signals前面不能使用public、private和protected等限定符,因为只有定义该信号的类及其子类才可以发射该信号。(个人理解为使用emit函数)

3.信号只用声明,不需要也不能对它进行定义实现。

4.信号没有返回值,只能是void类型的。

5.只有QObject类及其子类派生的类才能使用信号和槽机制,使用信号和槽,还必须在类声明的最开始处添加Q_OBJECT宏。

6.使用emit 强行发射信号

emit sendPointer(this);

 Qt之所以使用# define emit,是因为编译器并不认识emit啊,所以把它定义成一个空的宏就可以通过编译。

7. 信号是一个函数, 类的成员函数。所以可以是虚函数的重写

即在基类定义一个纯虚函数,在子类的重写该虚函数,并且声明为信号。

8.信号可以支持重载

在同一个线程中,当一个信号被emit发出时,会立即执行其槽函数,等槽函数执行完毕后,才会执行emit后面的代码。如果一个信号链接了多个槽,那么会等所有的槽函数执行完毕后才执行后面的代码,槽函数的执行顺序是按照它们链接时的顺序执行的 。

如果信号和槽不是在同一线程,默认情况下,是异步执行,不会阻塞。

怎么获取信号发送者

  当多个信号连接一个槽时,有时需要判断是哪个对象发来的,那么可以调用sender()函数获取对象指针,返回为QObject指针。

QObject* sender() ;

1.声明一个槽需要使用slots关键字。

2.一个槽可以是private、public或者protected类型的,

3.槽也可以被声明为虚函数,静态函数、全局函数,这与普通的成员函数是一样的,也可以像调用一个普通函数一样来调用槽。本质就是回调函数。

4.发送者和接受者都需要是QObject的子类(当然,槽函数是全局函数,Lambda表达式等无需接收者的时候除外

public slots:
void handleTimeout();

void GetDataFromRTDB();

void getPointer(MainWindow *pMainWindow);

connect()函数

connect()函数原型如下:
bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection )

有两种方式表达:

1.

MyDialog *dlg = new MyDialog(this); 
connect(dlg,SIGNAL(dlgReturn(int)),this,SLOT(showValue(int)));

connect(this,SIGNAL(sendPointer(MainWindow*)),m_pGetDataThreadObj,SLOT(getPointer(MainWindow*)));

2.

connect(this,&MainWindow::startGetDataThread,m_pGetDataThreadObj,&DataThreadObject::GetDataFromRTDB); connect(m_pGetDataThread,&QThread::finished,m_pGetDataThread,&QObject::deleteLater);

解绑定信号槽

  不需要信号槽连接时,可使用disconnect()进行解绑定。其写法和connect一样,只需要将connect换成disconnect即可。

信号槽的特点

1、一个信号可以和多个槽相连

 2、多个信号可以连接到一个槽

3、一个信号可以连接到另外的一个信号

4. 信号的参数类型可以与槽的参数类型对应,信号的参数可以比槽的参数多,但不可以少, 否则连接将失败

5. 槽可以被取消连接;这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽。

6.connect的第5个参数

   第5个参数一般不填,为默认值。

  1、Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。

  2、Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数和信号发送者在同一线程。效果看上去就像是直接在信号发送位置调用了槽函数,效果上看起来像函数调用,同步执行。

emit语句后面的代码将在与信号关联的所有槽函数执行完毕后才被执行。

  3、Qt::QueuedConnection:信号发出后,信号会暂时被放到一个消息队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,然后执行和信号关联的槽函数,这种方式既可以在同一线程内传递消息也可以跨线程操作。

emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕

  4、Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。而且接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

  5、Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是为了避免重复连接。

6.信号和槽的参数只能有类型,不能有变量,例如写成SLOT(showValue(int value))是不对的。

7.对于信号和槽的参数问题,基本原则是信号中的参数类型要和槽中的参数类型相对应,而且信号中的参数可以多于槽中的参数,但是不能反过来,如果信号中有多余的参数,那么它们将被忽略。

8.在槽函数中获取发射信号的对象 函数为:

QObject *sender() const;

9.信号和槽也不能携带模板类参数

如果将信号、槽声明为模板类参数的话,即使moc工具不报告错误,也不可能得到预期的结果,也可以取巧,用typedef

typedef pair IntPair;
	public slots: 
	void setLocation (IntPair location); 

10.嵌套的类不能位于信号或槽区域内,也不能有信号或槽。即类b嵌套在类a内,想在类b中声明信号与槽是不行的。 

11.友元声明不能位于信号或槽声明区内。相反,他们应该在普通C++的private、protected或public区内进行声明

信号槽机制的优缺点

优点

Qt信号与槽机制降低了Qt对象的耦合度。

观察者模式,激发信号的Qt对象无须知道是哪个对象的哪个槽函数需要接收它发出的信号,它只需要做的是在适当的时间发送适当的信号就可以了,而不需要知道也不关心它的信号有没有被接收到,更不需要知道哪个对象的哪个槽接收了信号。

缺点:

信号槽机制,同回调函数相比,信号和槽机制运行速度有些慢。遍历,通过传递一个信号来调用槽函数将会比直接调用非虚函数运行速度慢10倍。原因如下:- 需要定位接收信号的对象;- 安全地遍历所有的关联(一个信号关联多个槽的情况);- 编组/解组传递的参数;- 多线程的时候,信号可能需要排队等待。
 

在没有信号槽机制的时代,C++对象间的交互一般使用回调函数来实现。使用某对象时,用指针指向另一个对象的函数,这个函数就称为回调函数。使用回调函数有个弊端,当某个对象被多个对象通信时,需要一个容器来存放多个对象的回调函数???。维护这个容器使得代码编写效率低、扩展性弱。

qt信号槽的本质就是回调函数。???

延伸:

1.信号槽类似观察者模式,延伸到模型视图也是观察者模式。

观察者模式是一种一对多,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者关联目标,目标聚合观察者。这样就会有双向关联了。

信号与槽的具体流程

moc查找头文件中的signals,slots,标记出信号和槽。

将信号槽信息存储到类静态变量staticMetaObject中,并且按声明顺序进行存放,建立索引。

当发现有connect连接时,将信号槽的索引信息放到一个map中,彼此配对。

当调用emit时,调用信号函数,并且传递发送信号的对象指针,元对象指针,信号索引,参数列表到active函数

通过active函数找到在map中找到所有与信号对应的槽索引

根据槽索引找到槽函数,执行槽函数。

以上,便是信号槽的整个流程,总的来说就是一个“注册-索引”机制。

其他宏介绍

Qt通过Q_DECLARE开头的几个宏及几个qRegister开头的函数向Qt元系统注册一些非基本类型。一旦注册后,在Qt元系统中就可以很方便的利用这些非基本类型

Q_DECLARE_METATYPE

Q_DECLARE_METATYPE(Type)

这个宏能使Qt元系统的QMetaType知道Type类型,但前提是Type类型必须提供一个公有的默认构造函数公有的默认拷贝构造函数公有的默认析构函数。当在QVariant中使用自定义类型时,利用该宏向Qt元系统声明自定义类型是必须的,否则编译会报错。

如果MyStruct在命名空间中,Q_DECLARE_METATYPE()必须在命名空间外部。

#ifndef PUBLICDATA_H
#define PUBLICDATA_H
#include <QString>
#include <QObject>

namespace Mydatapace
{
class person
{
public:
    person() {}
    int nage;
    QString name;
};

}

Q_DECLARE_METATYPE(Mydatapace::person); // 在命名空间的作用域外部,且放在命名空间声明的最下面

#endif // PUBLICDATA_H





#include "publicdata.h"
using namespace Mydatapace;
void Dialog::on_pushButton_clicked()
{
    person s;
    s.nage = 10;
    s.name = "qq";
    QVariant varTest;
    varTest.setValue(s);

    person p = varTest.value<person>();

}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
c++/qt写的项目,项目都经测试过,真实可靠,可供自己学习c++/qtQt是一个用标准C++编写的跨平台开发类库,它对标准C++进行了扩展,引入了对象系统信号属性等特性,使应用程序的开发变得更高效。 Qt类库中大量的类以模块形式分类组织的,包括基本模块和扩展模块等。一个模块通常就是一个编程主题,如数据库、图表、网络等。 一、Qt核心特点 1.1.概述 Qt本身并不是一种编程语言,它本质上是一个跨平台的C++开发类库,是用标准C++编写的类库,它为开发GUI应用程序和非GUI应用程序提供了各种类。 Qt对标准C++进行了扩展,引入了一些新概念和功能,例如信号对象属性等。Qt对象编译器(Meta-Object Compiler,MOC)是一个预处理器,在源程序被编译前先将这些Qt特性的程序转换为标准C++兼容的形式,然后再由标准C++编译器进行编译。这就是为什么在使用信号机制的类里,必须添加一个Q_OBJECT宏的原因,只有添加了这个宏,moc才能对类里的信号的代码进行预处理。 Qt Core模块是Qt类库的核心,所有其他模块都依赖于此模块,如果使用qmake来构建项目,Qt Core模块则是被自动加入的。 QtC++语言增加的特性就是在Qt Core模块里实现的,这些扩展特性由Qt对象系统实现,包括信号机制、属性系统、动态类型转换等。 1.2.对象系统 Qt对象系统(Meta-Object-System)提供了对象之间通信的信号机制、运行时类型信息和动态属性系统对象系统由以下三个基础组成: 1.QObject类是所有使用对象系统的类的基类; 2.在一个类的private部分声明Q_OBJECT宏,使得类可以使用对象的特性,如动态属性信号。 3.MOC(对象编译器)为每个QObject的子类提供必要的代码来实现对象系统的特征。 构建项目时,MOC工具读取C++源文件,当它发现类的定义里有Q_OBJECT宏时,它就会为这个类生成另外一个包含有对象支持代码的C++源文件,这个生成的源文件连同类的实现文件一起被编译和连接。 除了信号机制外,对象还提供如下一些功能。 1.QObject::metaObject()函数返回类关联的对象对象类QMetaObject包含了访问对象的一些接口函数,例如QMetaObject::className()函数可在运行时返回类的名称字符串。 QObject obj=new QPushButton; obj->metaObject()->className(); 2.QMetaObject::newInstance()函数创建类的一个新的实例。 3.QObject::inherits(const charclassName)函数判断一个对象实例是否是名称为className的类或QObject的子类的实例。 1.3.属性系统 1.属性定义 Qt提供一个Q_PROPERTY()宏可以定义属性,它也是属于对象系统实现的。Qt属性系统C++编译器无关,可以用任何标准的C++编译器编译定义了属性Qt C++程序。 2.属性的使用 不管是否用READ和WRITE定义了接口函数,只要知道属性名称,就可以通过QObject::property()读取属性值,并通过QObject::setProperty()设置属性值。 3.动态属性 QObject::setProperty()函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的。 动态属性可以使用QObject::property()查询,就如在类定义里用Q_PROPERTY宏定义的属性一样。 例如,在数据表编辑界面上,一些字段是必填字段,就可以在初始化界面时为这些字段的关联显示组件定义一个新的required属性,并设置值为“true"。 4.类的附加信息 属性系统还有一个宏Q_CLASSINFO(),可以为类的对象定义”名称——值“信息。
c++/qt写的项目,项目都经测试过,真实可靠,可供自己学习c++/qtQt是一个用标准C++编写的跨平台开发类库,它对标准C++进行了扩展,引入了对象系统信号属性等特性,使应用程序的开发变得更高效。 Qt类库中大量的类以模块形式分类组织的,包括基本模块和扩展模块等。一个模块通常就是一个编程主题,如数据库、图表、网络等。 一、Qt核心特点 1.1.概述 Qt本身并不是一种编程语言,它本质上是一个跨平台的C++开发类库,是用标准C++编写的类库,它为开发GUI应用程序和非GUI应用程序提供了各种类。 Qt对标准C++进行了扩展,引入了一些新概念和功能,例如信号对象属性等。Qt对象编译器(Meta-Object Compiler,MOC)是一个预处理器,在源程序被编译前先将这些Qt特性的程序转换为标准C++兼容的形式,然后再由标准C++编译器进行编译。这就是为什么在使用信号机制的类里,必须添加一个Q_OBJECT宏的原因,只有添加了这个宏,moc才能对类里的信号的代码进行预处理。 Qt Core模块是Qt类库的核心,所有其他模块都依赖于此模块,如果使用qmake来构建项目,Qt Core模块则是被自动加入的。 QtC++语言增加的特性就是在Qt Core模块里实现的,这些扩展特性由Qt对象系统实现,包括信号机制、属性系统、动态类型转换等。 1.2.对象系统 Qt对象系统(Meta-Object-System)提供了对象之间通信的信号机制、运行时类型信息和动态属性系统对象系统由以下三个基础组成: 1.QObject类是所有使用对象系统的类的基类; 2.在一个类的private部分声明Q_OBJECT宏,使得类可以使用对象的特性,如动态属性信号。 3.MOC(对象编译器)为每个QObject的子类提供必要的代码来实现对象系统的特征。 构建项目时,MOC工具读取C++源文件,当它发现类的定义里有Q_OBJECT宏时,它就会为这个类生成另外一个包含有对象支持代码的C++源文件,这个生成的源文件连同类的实现文件一起被编译和连接。 除了信号机制外,对象还提供如下一些功能。 1.QObject::metaObject()函数返回类关联的对象对象类QMetaObject包含了访问对象的一些接口函数,例如QMetaObject::className()函数可在运行时返回类的名称字符串。 QObject obj=new QPushButton; obj->metaObject()->className(); 2.QMetaObject::newInstance()函数创建类的一个新的实例。 3.QObject::inherits(const charclassName)函数判断一个对象实例是否是名称为className的类或QObject的子类的实例。 1.3.属性系统 1.属性定义 Qt提供一个Q_PROPERTY()宏可以定义属性,它也是属于对象系统实现的。Qt属性系统C++编译器无关,可以用任何标准的C++编译器编译定义了属性Qt C++程序。 2.属性的使用 不管是否用READ和WRITE定义了接口函数,只要知道属性名称,就可以通过QObject::property()读取属性值,并通过QObject::setProperty()设置属性值。 3.动态属性 QObject::setProperty()函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的。 动态属性可以使用QObject::property()查询,就如在类定义里用Q_PROPERTY宏定义的属性一样。 例如,在数据表编辑界面上,一些字段是必填字段,就可以在初始化界面时为这些字段的关联显示组件定义一个新的required属性,并设置值为“true"。 4.类的附加信息 属性系统还有一个宏Q_CLASSINFO(),可以为类的对象定义”名称——值“信息。
c++/qt写的项目,项目都经测试过,真实可靠,可供自己学习c++/qtQt是一个用标准C++编写的跨平台开发类库,它对标准C++进行了扩展,引入了对象系统信号属性等特性,使应用程序的开发变得更高效。 Qt类库中大量的类以模块形式分类组织的,包括基本模块和扩展模块等。一个模块通常就是一个编程主题,如数据库、图表、网络等。 一、Qt核心特点 1.1.概述 Qt本身并不是一种编程语言,它本质上是一个跨平台的C++开发类库,是用标准C++编写的类库,它为开发GUI应用程序和非GUI应用程序提供了各种类。 Qt对标准C++进行了扩展,引入了一些新概念和功能,例如信号对象属性等。Qt对象编译器(Meta-Object Compiler,MOC)是一个预处理器,在源程序被编译前先将这些Qt特性的程序转换为标准C++兼容的形式,然后再由标准C++编译器进行编译。这就是为什么在使用信号机制的类里,必须添加一个Q_OBJECT宏的原因,只有添加了这个宏,moc才能对类里的信号的代码进行预处理。 Qt Core模块是Qt类库的核心,所有其他模块都依赖于此模块,如果使用qmake来构建项目,Qt Core模块则是被自动加入的。 QtC++语言增加的特性就是在Qt Core模块里实现的,这些扩展特性由Qt对象系统实现,包括信号机制、属性系统、动态类型转换等。 1.2.对象系统 Qt对象系统(Meta-Object-System)提供了对象之间通信的信号机制、运行时类型信息和动态属性系统对象系统由以下三个基础组成: 1.QObject类是所有使用对象系统的类的基类; 2.在一个类的private部分声明Q_OBJECT宏,使得类可以使用对象的特性,如动态属性信号。 3.MOC(对象编译器)为每个QObject的子类提供必要的代码来实现对象系统的特征。 构建项目时,MOC工具读取C++源文件,当它发现类的定义里有Q_OBJECT宏时,它就会为这个类生成另外一个包含有对象支持代码的C++源文件,这个生成的源文件连同类的实现文件一起被编译和连接。 除了信号机制外,对象还提供如下一些功能。 1.QObject::metaObject()函数返回类关联的对象对象类QMetaObject包含了访问对象的一些接口函数,例如QMetaObject::className()函数可在运行时返回类的名称字符串。 QObject obj=new QPushButton; obj->metaObject()->className(); 2.QMetaObject::newInstance()函数创建类的一个新的实例。 3.QObject::inherits(const charclassName)函数判断一个对象实例是否是名称为className的类或QObject的子类的实例。 1.3.属性系统 1.属性定义 Qt提供一个Q_PROPERTY()宏可以定义属性,它也是属于对象系统实现的。Qt属性系统C++编译器无关,可以用任何标准的C++编译器编译定义了属性Qt C++程序。 2.属性的使用 不管是否用READ和WRITE定义了接口函数,只要知道属性名称,就可以通过QObject::property()读取属性值,并通过QObject::setProperty()设置属性值。 3.动态属性 QObject::setProperty()函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的。 动态属性可以使用QObject::property()查询,就如在类定义里用Q_PROPERTY宏定义的属性一样。 例如,在数据表编辑界面上,一些字段是必填字段,就可以在初始化界面时为这些字段的关联显示组件定义一个新的required属性,并设置值为“true"。 4.类的附加信息 属性系统还有一个宏Q_CLASSINFO(),可以为类的对象定义”名称——值“信息。
c++/qt写的项目,项目都经测试过,真实可靠,可供自己学习c++/qtQt是一个用标准C++编写的跨平台开发类库,它对标准C++进行了扩展,引入了对象系统信号属性等特性,使应用程序的开发变得更高效。 Qt类库中大量的类以模块形式分类组织的,包括基本模块和扩展模块等。一个模块通常就是一个编程主题,如数据库、图表、网络等。 一、Qt核心特点 1.1.概述 Qt本身并不是一种编程语言,它本质上是一个跨平台的C++开发类库,是用标准C++编写的类库,它为开发GUI应用程序和非GUI应用程序提供了各种类。 Qt对标准C++进行了扩展,引入了一些新概念和功能,例如信号对象属性等。Qt对象编译器(Meta-Object Compiler,MOC)是一个预处理器,在源程序被编译前先将这些Qt特性的程序转换为标准C++兼容的形式,然后再由标准C++编译器进行编译。这就是为什么在使用信号机制的类里,必须添加一个Q_OBJECT宏的原因,只有添加了这个宏,moc才能对类里的信号的代码进行预处理。 Qt Core模块是Qt类库的核心,所有其他模块都依赖于此模块,如果使用qmake来构建项目,Qt Core模块则是被自动加入的。 QtC++语言增加的特性就是在Qt Core模块里实现的,这些扩展特性由Qt对象系统实现,包括信号机制、属性系统、动态类型转换等。 1.2.对象系统 Qt对象系统(Meta-Object-System)提供了对象之间通信的信号机制、运行时类型信息和动态属性系统对象系统由以下三个基础组成: 1.QObject类是所有使用对象系统的类的基类; 2.在一个类的private部分声明Q_OBJECT宏,使得类可以使用对象的特性,如动态属性信号。 3.MOC(对象编译器)为每个QObject的子类提供必要的代码来实现对象系统的特征。 构建项目时,MOC工具读取C++源文件,当它发现类的定义里有Q_OBJECT宏时,它就会为这个类生成另外一个包含有对象支持代码的C++源文件,这个生成的源文件连同类的实现文件一起被编译和连接。 除了信号机制外,对象还提供如下一些功能。 1.QObject::metaObject()函数返回类关联的对象对象类QMetaObject包含了访问对象的一些接口函数,例如QMetaObject::className()函数可在运行时返回类的名称字符串。 QObject obj=new QPushButton; obj->metaObject()->className(); 2.QMetaObject::newInstance()函数创建类的一个新的实例。 3.QObject::inherits(const charclassName)函数判断一个对象实例是否是名称为className的类或QObject的子类的实例。 1.3.属性系统 1.属性定义 Qt提供一个Q_PROPERTY()宏可以定义属性,它也是属于对象系统实现的。Qt属性系统C++编译器无关,可以用任何标准的C++编译器编译定义了属性Qt C++程序。 2.属性的使用 不管是否用READ和WRITE定义了接口函数,只要知道属性名称,就可以通过QObject::property()读取属性值,并通过QObject::setProperty()设置属性值。 3.动态属性 QObject::setProperty()函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的。 动态属性可以使用QObject::property()查询,就如在类定义里用Q_PROPERTY宏定义的属性一样。 例如,在数据表编辑界面上,一些字段是必填字段,就可以在初始化界面时为这些字段的关联显示组件定义一个新的required属性,并设置值为“true"。 4.类的附加信息 属性系统还有一个宏Q_CLASSINFO(),可以为类的对象定义”名称——值“信息。
c++/qt写的项目,项目都经测试过,真实可靠,可供自己学习c++/qtQt是一个用标准C++编写的跨平台开发类库,它对标准C++进行了扩展,引入了对象系统信号属性等特性,使应用程序的开发变得更高效。 Qt类库中大量的类以模块形式分类组织的,包括基本模块和扩展模块等。一个模块通常就是一个编程主题,如数据库、图表、网络等。 一、Qt核心特点 1.1.概述 Qt本身并不是一种编程语言,它本质上是一个跨平台的C++开发类库,是用标准C++编写的类库,它为开发GUI应用程序和非GUI应用程序提供了各种类。 Qt对标准C++进行了扩展,引入了一些新概念和功能,例如信号对象属性等。Qt对象编译器(Meta-Object Compiler,MOC)是一个预处理器,在源程序被编译前先将这些Qt特性的程序转换为标准C++兼容的形式,然后再由标准C++编译器进行编译。这就是为什么在使用信号机制的类里,必须添加一个Q_OBJECT宏的原因,只有添加了这个宏,moc才能对类里的信号的代码进行预处理。 Qt Core模块是Qt类库的核心,所有其他模块都依赖于此模块,如果使用qmake来构建项目,Qt Core模块则是被自动加入的。 QtC++语言增加的特性就是在Qt Core模块里实现的,这些扩展特性由Qt对象系统实现,包括信号机制、属性系统、动态类型转换等。 1.2.对象系统 Qt对象系统(Meta-Object-System)提供了对象之间通信的信号机制、运行时类型信息和动态属性系统对象系统由以下三个基础组成: 1.QObject类是所有使用对象系统的类的基类; 2.在一个类的private部分声明Q_OBJECT宏,使得类可以使用对象的特性,如动态属性信号。 3.MOC(对象编译器)为每个QObject的子类提供必要的代码来实现对象系统的特征。 构建项目时,MOC工具读取C++源文件,当它发现类的定义里有Q_OBJECT宏时,它就会为这个类生成另外一个包含有对象支持代码的C++源文件,这个生成的源文件连同类的实现文件一起被编译和连接。 除了信号机制外,对象还提供如下一些功能。 1.QObject::metaObject()函数返回类关联的对象对象类QMetaObject包含了访问对象的一些接口函数,例如QMetaObject::className()函数可在运行时返回类的名称字符串。 QObject obj=new QPushButton; obj->metaObject()->className(); 2.QMetaObject::newInstance()函数创建类的一个新的实例。 3.QObject::inherits(const charclassName)函数判断一个对象实例是否是名称为className的类或QObject的子类的实例。 1.3.属性系统 1.属性定义 Qt提供一个Q_PROPERTY()宏可以定义属性,它也是属于对象系统实现的。Qt属性系统C++编译器无关,可以用任何标准的C++编译器编译定义了属性Qt C++程序。 2.属性的使用 不管是否用READ和WRITE定义了接口函数,只要知道属性名称,就可以通过QObject::property()读取属性值,并通过QObject::setProperty()设置属性值。 3.动态属性 QObject::setProperty()函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的。 动态属性可以使用QObject::property()查询,就如在类定义里用Q_PROPERTY宏定义的属性一样。 例如,在数据表编辑界面上,一些字段是必填字段,就可以在初始化界面时为这些字段的关联显示组件定义一个新的required属性,并设置值为“true"。 4.类的附加信息 属性系统还有一个宏Q_CLASSINFO(),可以为类的对象定义”名称——值“信息。
### 回答1: Qt是一款流行的跨平台C++框架,有着强大的功能和丰富的类库。Qt核心机制包括Qt对象系统信号机制。 Qt对象系统Qt的一个重要特性,它是Qt实现反射的基础。在C++中,反射能够在运行时获取类的信息,如类名、属性、方法等,并在运行时动态地创建、调用对象Qt对象系统通过为每个QObject派生的子类生成一个对象,实现了C++的反射机制。对象系统使得Qt能够在运行时获取QObject派生类的信息,并提供了一系列函数来操作这些对象Qt信号机制是Qt核心机制之一,它用于实现对象之间的通信。信号机制基于发布-订阅模式,其中一个对象发送信号,而另一个对象通过连接到这个信号函数来接收信号并进行相应的处理。信号机制具有松耦合的特性,可以实现对象之间的解耦。 在信号机制中,信号是由QObject派生类定义的特殊函数,用于声明某个特定事件发生时要发送的信号函数是QObject派生类中的普通函数,用于接收这个信号,并且执行相应的处理逻辑。信号通过信号连接函数进行连接,这样当信号触发时,与之连接的函数就会被自动调用。 Qt对象系统信号机制是Qt强大功能的基石。对象系统实现了C++的反射机制,允许在运行时获取和操作对象的信息。信号机制使对象之间的通信变得简单和易用,提供了一种灵活而高效的方式来实现对象间的解耦。通过这些核心机制,Qt能够帮助开发人员更快速、更简便地开发高质量的跨平台应用程序。 ### 回答2: qt核心机制是指Qt框架的底层机制,主要包括Qt对象系统Qt信号原理。 Qt对象系统Qt框架中的一个重要概念,它在C++语言的基础上添加了一套对象(Meta Object)系统对象系统在编译过程中生成了额外的代码,使得我们可以在运行时获得更多的对象信息。通过对象系统Qt实现了信号机制、宏(MOC)编译和反射等功能。对象系统实际上是一种面向对象的编程方式,通过它可以实现Qt特有的功能,如动态属性、动态信号等。 Qt信号原理是Qt框架中的一个重要特性,用于对象间的通信。信号是一种异步通信方式,通过信号发送者(Sender)发送信号,接收者(Receiver)通过函数(Slot)响应信号信号是通过对象系统实现的,编译器会在MOC编译阶段解析信号的声明,并在运行时建立连接关系。这种机制使得Qt程序的耦合性更低,灵活性更高,同时也为多线程编程提供了一种方便的方式。 总的来说,Qt核心机制包括了Qt对象系统信号原理。对象系统Qt框架提供了反射、动态属性和动态信号等功能,信号机制实现了对象间的异步通信。这些机制使得Qt框架具有高度的可扩展性、灵活性和跨平台性,为开发者提供了一种便捷、高效的方式来构建应用程序。 ### 回答3: Qt是一种跨平台的应用程序框架,具有丰富的功能和强大的性能。Qt核心机制是指Qt框架的基础机制,包括Qt对象系统Qt信号原理。 Qt对象系统Qt框架的核心组成之一,用于实现Qt的一些特殊功能,如信号机制和动态属性Qt对象系统通过将所有的类对象都派生自QObject基类,实现了一种反射机制,使得对象之间可以动态地连接和交互。通过使用对象系统Qt可以实现面向对象编程的高级特性,如对象间的信号的连接,对象属性系统以及对象的内省(即动态获取对象属性和方法信息)等。 Qt信号原理是Qt框架实现事件驱动的关键机制。信号机制允许不同对象之间进行松散的耦合,通过信号的方式进行通信。信号是一种特殊的成员函数,用于表示某个事件的发生,是一种普通的成员函数,用于响应信号的发出。当一个信号被发出时,Qt框架会自动将信号进行匹配,并调用对应的函数。这种机制使得对象之间的通信更加灵活和高效,可以实现事件的传递和处理,避免了显式的函数调用和回调函数的使用。 综上所述,Qt核心机制包括Qt对象系统Qt信号原理。通过对象系统Qt实现了一种反射机制,使得对象之间可以动态地连接和交互;通过信号机制,Qt实现了一种松散耦合的事件处理方式,提高了对象之间的通信效率和灵活性。这些机制是Qt框架的重要组成部分,为开发者提供了更加强大和易用的工具和功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值