CMake依赖
使用CMake构建Qt程序的时候,可以使用命令find_package来定位Qt的头文件路径、库文件路径以及库文件。
如:
FIND_PACKAGE (Qt6 NAMES Qt6 COMPONENTS Core Gui Widgets REQUIRED)
*** 注意:执行成功以后,将会按照COMPONENTS列表中的项目,生成一组变量。
如头文件路径为:
CMAKE_INCLUDE_DIR(${Qt6Core_INCLUDE_DIRS}
${Qt6Gui_INCLUDE_DIRS}
${Qt6Widgets_INCLUDE_DIRS})
将要连接的路径为:
ADD_EXECUTE(helloworld helloworld.cc)
TARGET_LINK_LIBRARIES(helloworld Qt6::Core Qt6::Gui Qt6::Widgets)
另外,Qt的一些宏依赖编译开始前的moc机制,比如需要支持信号(SIGNAL)与槽(SLOT)的类,如果不进行moc,将会无法连接。
在CMake配置文件CMakeLists.txt中,可以使用AUTOMOC来自动moc。
如果要在编译时对目标helloworld的源文件自动moc,可以如下指定:
ADD_EXECUTE(helloworld helloworld.cc)
SET_PROPERTY(TARGET helloword PROPERTY AUTOMOC ON)
信号的声明
一个类如果要支持信号,需要满足以下条件:
- 类必须派生自QObject(或其子类),且在类的开头加了Q_OBJECT宏。
- 类的信号的返回值需要是void。
- 类的信号只有声明,没有定义。
- 类的信号前面用signals: 宏来修饰。
如定义一个类Hello,声明一个信号say:
public Hello: public QObject
{
Q_OBJECT
public:
Hello() = default;
……
signals:
void say(QString);
}
如此,就可以在其它地方用emit发送这个信号。
槽的连接
一个类要支持槽的连接,也需要满足一些条件:
- 类必须派生自QObject(或其子类),且在类的开头加了Q_OBJECT宏。
- 类的槽的前面用slots: 宏来修饰。
*** connect的时候,SIGNAL()宏包含的信号要包括完整正确的函数参数,但是不能包含参数名称 ***
比如,上面的Hello类的say信号,如果如下进行连接会返回没有这个信号:
QObject::connect(this, SIGNAL(say(QString message), this, SLOT(hear(QString));
正确的做法是:
QObject::connect(this, SIGNAL(say(QString), this, SLOT(hear(QString));
QObject的反射机制
Qt的QObject非常强大,已经在一定程度上实现了Java语言中的动态反射机制。
这一切都是使用QObject的元类对象QMetaObject来实现的。
QMetaObject的方法有:
QMetaClassInfo classInfo(int index) const
int classInfoCount() const
int classInfoOffset() const
const char * className() const
QMetaMethod constructor(int index) const
int constructorCount() const
QMetaEnum enumerator(int index) const
int enumeratorCount() const
int enumeratorOffset() const
int indexOfClassInfo(const char *name) const
int indexOfConstructor(const char *constructor) const
int indexOfEnumerator(const char *name) const
int indexOfMethod(const char *method) const
int indexOfProperty(const char *name) const
int indexOfSignal(const char *signal) const
int indexOfSlot(const char *slot) const
bool inherits(const QMetaObject *metaObject) const
QMetaType metaType() const
QMetaMethod method(int index) const
int methodCount() const
int methodOffset() const
QObject * newInstance(Args &&... arguments) const
QMetaProperty property(int index) const
int propertyCount() const
int propertyOffset() const
const QMetaObject * superClass() const
QMetaProperty userProperty() const
其中:
className()可以返回类的名称。
method(int index)可以获取类的方法QMetaMethod,QMetaMethod包含方法的类型、名称、参数等各种相信。
比如,下面的代码片段,可以打印出hello对象支持的所有信号,以及它的参数:
auto meta = hello->metaObject();
for (auto ind = 0; ind < meta->methodCount(); ++ ind)
{
auto method = meta->method (ind);
if (method.methodType() == QMetaMethod::MethodType::Signal)
{
auto signature = method.methodSignature().toStdString();
debug("signal %s->%s", meta->className(), signature.c_str());
}
}
inherits(const QMetaObject *metaObject)可以判断当前对象是否是某个类以及它的父类。
另外,QObject也有一个inherits(const char *)方法,可以以字符串的形式直接查询一个对象是否是某个类或者它的父类。
如:
auto layout = new QBoxLayout();
layout->inherits("QObject"); // 返回true
layout->inherits("QLayout"); // 返回true
layout->inherits("QVBoxLayout"); //返回假