Qt之创建自定义类型
摘要: 简述 当使用Qt创建用户界面时,特别是那些带有特殊控制和特征的界面时,开发者通常需要创建新数据类型来扩展或替换Qt现有的的值类型集合。 标准类型,比如:QSize、QColor和QString都可以被存储到QVariant对象中,在基于QObject的类中可用作属性的类型,并且可以在信号-槽通信时发射。 下面,我会创建一个自定义类型,并且说明如何将它集成到Qt的对象模型
简述
当使用Qt创建用户界面时,特别是那些带有特殊控制和特征的界面时,开发者通常需要创建新数据类型来扩展或替换Qt现有的的值类型集合。
标准类型,比如:QSize、QColor和QString都可以被存储到QVariant对象中,在基于QObject的类中可用作属性的类型,并且可以在信号-槽通信时发射。
下面,我会创建一个自定义类型,并且说明如何将它集成到Qt的对象模型中,以便能够以与其他Qt标准类型相同的方式被存储。接着会展示如何注册自定义类型,使其可以在信号槽的连接中使用。
创建一个自定义类型
在开始之前,需要确保创建的这个自定义类型符合QMetaType的规定的所有要求。换句话说,它必须提供:
- 一个公有的默认构造函数
- 一个公有的拷贝构造函数
- 一个公有的析构函数
下面的Message类的定义包含了这些成员:
class Message
{
public:
Message();
Message(const Message &other);
~Message();
Message(const QString &body, const QStringList &headers);
QString body() const;
QStringList headers() const;
private:
QString m_body;
QStringList m_headers;
};
这个类同时还提供了一个经常使用的构造函数,以及两个用于获取私有数据的共有成员函数。
使用QMetaType声明类型
Message类仅需要一个合适的实现,以便可以使用。然而,如果没有其他辅助信息,Qt类型系统将无法理解如何存储、检索和序列化该类的实例。例如:我们无法将Message的值保存到QVariant中。
Qt中负责自定义类型的类是QMetaType。为了让这个类识别该类型,当定义这个类时,需要头文件中使用Q_DECLARE_METATYPE()宏:
Q_DECLARE_METATYPE(Message);
这样,就可以将Message的值保存在QVariant对象中,并在以后读取。完整代码可参见Custom Type Example中的示范代码。
所述Q_DECLARE_METATYPE()宏同时也使得这些值可以被用作信号的参数,但是仅限于direct信号槽连接。为了能在信号槽机制中使用自定义类型,我们需要做一些另外的工作。
创建和销毁自定义对象
虽然上面部分中的声明使类型可以在direct信号槽连接中使用,但是无法用于queued信号槽连接中,例如:在不同线程的对象之间所建立的连接。这是因为元对象系统不知道如何在运行时处理自定义类型对象的创建和销毁操作。
为了可以在运行时创建对象,需要调用qRegisterMetaType()模板函数在元对象系统中注册此类型。只要在使用此类型的第一次连接建立前调用注册函数,该类型可被用于queued信号槽连接。
Queued Custom Type Example示例中在main.cpp文件中声明了一个Block类:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
...
qRegisterMetaType<Block>();
...
return app.exec();
}
这个类型后来在文件window.cpp中被用于一个信号-槽连接:
Window::Window()
{
thread = new RenderThread();
...
connect(thread, SIGNAL(sendBlock(Block)), this, SLOT(addBlock(Block)));
...
setWindowTitle(tr("Queued Custom Type"));
}
如果一个没有被注册的类型被用于queued连接中,在控制台中会输出一条警告信息。例如:
QObject::connect: Cannot queue arguments of type ‘Block’ (Make sure ‘Block’ is registered using qRegisterMetaType().)
使类型可打印
出于调试目的,使一个自定义类型可打印是非常有用的,就像下面的代码一样:
Message message(body, headers);
qDebug() << "Original:" << message;
可以通过为此类型创建流操作符来达到目的,这通常定义在该类型的头文件中:
QDebug operator<<(QDebug dbg, const Message &message);
在Custom Type Example的Message类实现中,我们努力让可打印的内容尽可能的通俗易读:
QDebug operator<<(QDebug dbg, const Message &message)
{
const QString body = message.body();
QVector<QStringRef> pieces = body.splitRef("\r\n", QString::SkipEmptyParts);
if (pieces.isEmpty())
dbg.nospace() << "Message()";
else if (pieces.size() == 1)
dbg.nospace() << "Message(" << pieces.first() << ")";
else
dbg.nospace() << "Message(" << pieces.first() << " ...)";
return dbg.maybeSpace();
}
当然,输出到debug流的信息是简单还是复杂都随你的意思。需要注意的是这个函数的返回值是QDebug对象本身,尽管它通常通过调用QDebug的成员函数maybeSpace()来获得,用空白字符填充流,以使其更具可读性。
转自:https://yq.aliyun.com/articles/62082
Qt之创建自定义类型的更多相关文章
- JavaScript之面向对象学习七(动态原型模式、寄生构造函数模式、稳妥构造函数模式创建自定义类型)
一.动态原型模式 在面向对象学习六中的随笔中,了解到组合构造函数模式和原型模式创建的自定义类型可能最完善的!但是人无完人,代码亦是如此! 有其他oo语言经验的开发人员在看到独立的构造函数和原型时,很可 ...
- qt 如何注册自定义类型?
如何声明自定义类型 如果仅仅在 QVariant 中使用,则仅需要使用 Q_DECLARE_METATYPE 宏进行声明即可. class Custom_ : public QObject { Q_O ...
- Lambda语句中创建自定义类型时,也可指定某种特定类型,方法是在new与{}之间写上类型名称
如: var fc =...ChildFath = fc.Select(c => new Child_Father { child = c.child, father = c.father }) ...
- javascript面向对象--自定义类型
Javascript是基于原型实现面向对象的,因此并没有类和接口,它的对象也与其他基于类的语言中的对象有所不同.在Javascript中,每个对象都是基于一个引用类型创建的,这个引用类型可以是原生类型 ...
- sharepoint2010 创建自定义列表
转:http://boke.25k5.com/kan77298.html 如何创建自定义列表 首先了解创建自定义列表中涉及到的几个名词:栏.内容类型. ①栏:栏即列.字段(Field),MSDN中给出 ...
- Javascript 中创建自定义对象的方法(设计模式)
Javascript 中创建对象,可以有很多种方法. Object构造函数/对象字面量: 抛开设计模式不谈,使用最基本的方法,就是先调用Object构造函数创建一个对象,然后给对象添加属性. var ...
- Struts(二十):自定义类型转换器
如何自定义类型转换器: 1)为什么需要自定义类型转化器?strtuts2不能自动完成字符串到所有的类型: 2) 如何定义类型转化器? 步骤一:创建自定义类型转化器的类,并继承org.apache.st ...
- Oracle自定义类型在C#中调用示例
1.C#代码: 1)using Oracle.DataAccess.Types; using System; using System.Collections.Generic; using Syste ...
- Android进阶AIDL使用自定义类型
原文首发于微信公众号:jzman-blog,欢迎关注交流! 上篇文章中主要介绍从 AIDL 的使用方式以及 Android 开发中不同进程之间的通信,遗留的问题是如何在 AIDL 中使用自定义类型,具 ...
随机推荐
- 【iOS XMPP】使用XMPPFramewok(一):添加XMPPFramework(XCode 4.6.2)
转自:http://www.cnblogs.com/dyingbleed/archive/2013/05/09/3069145.html XMPPFramework GitHub: https://g ...
- 有用的 JS 和 CSS 库
1. Moon Moon 是一个灵感源于 Vue.js 的 JavaScript UI 库,但它却更轻量.简单.它具备优化的虚拟 DOM 引擎,对用户友好的 API,并且在 gzip 压缩后仅有 6K ...
- 10个Python面试常问的问题
概述 Python是个非常受欢迎的编程语言,随着近些年机器学习.云计算等技术的发展,Python的职位需求越来越高.下面我收集了10个Python面试官经常问的问题,供大家参考学习. 类继承 有如下的 ...
- (原创)C++11改进我们的程序之简化我们的程序(一)
C++11在很多方面可以简化我们的程序开发,我会在“简化我们的程序”这一系列的博文中一一讲到,敬请关注.这次要讲的是:C++11如何通过获取函数模板的返回值类型来简化我们的程序.在谈到简化之前,我们先 ...
- C++11 强枚举类型
在标准C++11之前的枚举是继承C的,枚举类型不是类型安全的.枚举类型被视为整数,这使得两种不同的枚举类型之间可以进行比较. 一.C中enum类型的局限语法: enum type1{a, b, c}; ...
- js把预定义的html字符串转换为 HTML 实体 htmlspecialchars 输出html实体内容包括标签,而不自动转义标签,只显示内容,类似php的htmlspecialchars
一.html字符串转换为 HTML 实体 htmlspecialchars function htmlspecialchars(str){ str = str ...
- Winsock解析
一.基本知识 1.Winsock,一种标准API,一种网络编程接口,用于两个或多个应用程序(或进程)之间通过网络进行数据通信.具有两个版本: Winsock 1: Windows CE平台支持. 头文 ...
- 实验吧 web题writeup
1.http://ctf5.shiyanbar.com/web/wonderkun/web/index.html 用户名我输入:or'xor"and"select"uni ...
- Oracle 重启数据库实例
看你当前有多少个已经启动的实例: ps -ef|grep smon ORA-27101 Shared memory realm does not existORA-01034 ORACLE not a ...
- Maven 统一指定jar包版本的方法
在看别人的源码的过程中,会遇到这种情况,就是很多jar包没有指定版本,却能够下载下来. 在后来的研究中发现,有这样一个配置. <parent> <groupId>org.spr ...