探索qt的信号
ref: http://crazyeddiecpp.blogspot.hk/2011/01/quest-for-sane-signals-in-qt-step-1.html

If it wasn't for the particular implementation of signals that Qt has, it would be a quite wonderful library. So much about it has been made very easy in comparison to most other UI libraries for C++. I really enjoy working with the library except for its signal architecture. Don't get me wrong, the signal/slot idea is a vast improvement over every other thing out there; what I don't like is Qt's way of doing it.

The way I see it, there's two fundamental problems with Qt's approach:
qt的信号机制有两个根本问题

1) If I wanted Python I'd use it. C++ is a strongly typed language and this feature is extremely powerful in that it provides much opportunity to catch bugs before they ever happen. The designers of Qt apparently don't like this feature though and spent a lot of time and effort making QObjects dynamic types. You can connect slots to signals without knowing whether or not either one is actually real. The problem with this is that you don't know that you've spelled something wrong until you run the program and happen upon the problem; this can be damn difficult to debug in some cases too, which is one good reason why I'm NOT using Python.
没有了强类型
2) Qt slots can only exist in Q_OBJECT classes. This has more implications than simply being bound to QObject because Q_OBJECT classes must be processed by the moc. The moc, in turn, implements an incomplete C++ preprocessor and is not compatible with template classes. Since only slots can be connected to signals you're stuck having to implement a hand-coded Q_OBJECT for each one. This means you can't auto-generate slot classes. Furthermore, since slots have to be complete objects and not just functors as with other C++ implementations of the signal/slot architecture, you can't connect to binds or lambda expressions.
你不能自动生成槽类
您无法连接到绑定或lambda表达式
The first of these is frustrating and slows me down, but the second is actually fairly debilitating compared to other signal/slot implementations. The really great thing about implementations like boost::signals (or signals2 - even better) is that you can connect signals to objects that don't even know anything about signals or slots. This means that your model and data classes don't have to be bound to this kind of use and you don't need to hand-code in-between objects to connect them (as you do in Qt). In fact, these mechanisms allow you to even connect to free functions, giving you even more possibilities for expression without creating new, pointless coupling.

However, like I said, the rest of the Qt library is great and since the developers actually cared about commercial development on Windows operating systems, it makes the single best C++ option that exists for UI development on that system. Even though it is "cross-platform" it is still the best for native development that you never intend to use anywhere else. The simple fact is that native options, such as MFC, are horrible to use. The GTKmm library uses something similar to boost::signals but unfortunately doesn't provide accessibility on Windows, unlike Qt. This feature is absolutely needed by anyone who intends to auto-drive their UI through testing scripts on that system since all such test suites use the accessibility framework to do their thing.
但是qt支持ui测试啊
So, given that I hate the Qt signal system but need to use Qt, my quest is to find a method to sanitize Qt's signals. I don't intend to "fix" them, they'll still be there and being used, but I do intend to fix the interface to them. I want static typing back and I want to be able to connect to any function like interface, just like boost::signals. Thus the real goal here is to turn a Qt signal into a boost signal. We don't have to go the other way around because Qt slots are just functions (with some junk about them in some meta-information) so we can connect them to any boost signal freely.
所以虽然我很恨他的slot机制,但也必须用他
我想搞掉slot
It would be nice to be able to do this on the fly. So I'm looking for a use case something like so:
我想实现如下功能:

connect_static(qt_object, qt_signal, [](args){ ... });

Of course the problem I have at this point is that whatever does the translation MUST be a Q_OBJECT. Of course it can't be because I need to be able to generate the translation functor from the parameter description. The only ways to do that is of course to extend the moc in some way, use the preprocessor, or (my preferred choice) template meta-programming. The first is simply not practical and the later two are incompatible with the moc. Thus, what we need to do here is create a Q_OBJECT without using the moc. Today I pulled this off and it actually turned out to be a LOT easier than looking at the source code and various web sites would indicate.

The first thing I did was to examine the source code that is generated by the moc and try to figure it out. I actually made it pretty far but it was obvious that creating preprocessor macros (didn't think TMP would do it) to mimic the MOC would be damn daunting. Here's one website that describes the Qt metamodel:

Qt Internals & Reversing

I also tried to ask on stackoverflow and qtcentre for help to see if all of this was even necessary. The former generated few responses indicating the MOC and any of my ideas to do this where incompatible. The latter just generated a flame war in response to my frustration with a whole lot of very silly answers, such as telling me to put a particular class definition in "#ifdef" blocks (not a good place to go to for help, lots of really poor advice being handed out at that site). I did, however, eventually yank out a link from one individual that actually ended up holding what I believe is the key to getting this accomplished:

Dynamic Signals and Slots

That site alone does not contain exactly what I need, but pulling various bits from it and adding bits I learned from looking at what qt_metacall does (stepped all the way through it quite a few times trying to figure out why my slots where not being called) resulted in the ability to create a QObject derived class that responds to any signal attached to it and could then be extended to forward to a subclass, which would not have to be a Q_OBJECT:
我从这个网站学到如何写一个class能反映任何连接到她的signal,然后forward到子类,而该子类不必是qobject

struct listener2 : public QObject
{
int qt_metacall(QMetaObject::Call call, int id,void** args)
{
id = QObject::qt_metacall(call,id,args);
if (id == -1 || call != QMetaObject::InvokeMetaMethod)
return id;

assert(id == 42);

std::cout << "Funky slot!!" << std::endl;
return -1;
}

void make_connection(QObject * obj, char const* signal)
{
QByteArray sig = QMetaObject::normalizedSignature(signal);
int sigid = obj->metaObject()->indexOfSignal(sig);

QMetaObject::connect(obj, sigid, this, QObject::metaObject()->methodCount() + 42);
}
};

This object must be connected with "make_connection" rather than with connect, because otherwise the system breaks down when it tries to find the slot and doesn't, but besides that it is almost perfect. The args void* array actually points at the arguments generated by the signal and then must be reinterpret_cast to the appropriate thing (see the .moc output of any of your classes).
该object必须使用"make_connection"链接,否则系统会尝试着slot但找不到。除此之外他是完美的。参数void*指向信号产生的参数,他必须reinterpret_cast到合适的类型

The key here is to find the id of the signal you want to connect to and use QMetaObject::connect instead, supplying an id you can recognize on the other side. You must add the methodCount() of your base so that it can take care of existing slots. In the qt_metacall function you first let the base attempt to take care of it. This will subtract from the input id resulting in id's that YOUR derived object is meant to take care of. The assert is unnecessary but adds some semblance of safety. The return of -1 in standard Qt speak for, "I've handled this call."
这里的关键是找到你想连接的信号的id,然后使用QMetaObject::connect链接 (mm的,俺要学习一下具体是怎么回事)

This is a big step. A subclass to this thing could take the void** data and then use TMP to generate the correct casts and invoke a boost::signal. Implementing that will be the subject of "step 2" followed by attempts to regain static typing and safety.
POSTED BY CRAZY EDDIE AT 3:55 PM
1 COMMENT:

user117January 5, 2011 at 2:08 PM
Don't you think this Qt's explanation is reasonable:
http://doc.qt.nokia.com/4.7/templates.html
?

Quest for sane signals in Qt - step 1 (hand coding a Q_OBJECT)的更多相关文章

  1. cmake+qt+qtcreator的配置,解决Q_OBJECT的问题

    1.如果在编译qt项目的时候,一般头文件里都有Q_OBJECT,但是用cmake来编译的时候,就会报错,那么怎么解决呢? 解决的办法就是要在cmake里面写好配置 命令,再编译的时候,就不会报错了,写 ...

  2. Qt错误:类中使用Q_OBJECT宏导致undefined reference to vtable for "xxx::xxx"错误的原因和解决方法

    在进行Qt编程的时候,有时候会将类的定义和实现都写在源文件中,如果同时在该类中使用信号/槽,那么可能就会遇到 undefined reference to vtable for "xxx:: ...

  3. 深入了解Qt(二)之元对象系统(Meta-Object System)

    深入了解Qt主要内容来源于Inside Qt系列,本文做了部分删改,以便于理解.在此向原作者表示感谢! 在Qt Meta Object System-元对象系统这篇文章中,从底层实现的源码剖析了元对象 ...

  4. QT 的信号与槽

    转载: QT 的信号与槽机制介绍 QT 是一个跨平台的 C++ GUI 应用构架,它提供了丰富的窗口部件集,具有面向对象.易于扩展.真正的组件编程等特点,更为引人注目的是目前 Linux 上最为流行的 ...

  5. qt信号signal和槽slot机制

    内容: 一.概述 二.信号 三.槽 四.信号与槽的关联 五.元对象工具 六.程序样例 七.应注意的问题 信号与槽作为QT的核心机制在QT编程中有着广泛的应用,本文介绍了信号与槽的一些基本概念.元对象工 ...

  6. QT的信号与槽机制介绍

      信号与槽作为QT的核心机制在QT编程中有着广泛的应用,本文介绍了信号与槽的一些基本概念.元对象工具以及在实际使用过程中应注意的一些问题. QT是一个跨平台的C++ GUI应用构架,它提供了丰富的窗 ...

  7. Qt 的信号与槽机制介绍(10个要注意的问题)

    QT 是一个跨平台的 C++ GUI 应用构架,它提供了丰富的窗口部件集,具有面向对象.易于扩展.真正的组件编程等特点,更为引人注目的是目前 Linux 上最为流行的 KDE 桌面环境就是建立在 QT ...

  8. Qt 信号与槽

    Qt信号与槽的理解 信号和槽机制是 QT 的核心机制,要精通 QT 编程就必须对信号和槽有所了解.信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性,也是 QT 区别于其它工具包的重 ...

  9. Inside Qt Series (全集)

    Inside Qt 系列 QObject这个 class 是 QT 对象模型的核心,绝大部分的 QT 类都是从这个类继承而来.这个模型的中心特征就是一个叫做信号和槽(signaland slot)的机 ...

随机推荐

  1. Java基础-流程控制语句与运算符

    运算符 算术运算符 ++ -- 在前时先运算后取值:在后时先取值后运算 关系运算符 == !=也可以是引用类型 位运算符 逻辑运算符 赋值运算符 条件运算符 (?:) 布尔表达式 ? 表达式1 : 表 ...

  2. mvc4使用百度ueditor编辑器

    前言 配置.net mvc4项目使用ueditor编辑器,在配置过程中遇见了好几个问题,以此来记录解决办法.编辑器可以到http://ueditor.baidu.com/website/downloa ...

  3. <spark入门><Intellj环境配置><scala>rk入门><Intellj环境配置><scala>

    # 写在前面: 准备开始学spark,于是准备在IDE配一个spark的开发环境. 嫌这篇格式不好的看这里链接 用markdown写的,懒得调格式了,么么哒 # 相关配置: ## 关于系统 * mac ...

  4. java学习笔记30(IO :缓冲流)

    缓冲流: 读取数据大量的文件时,读取的速度慢,java提供了一套缓冲流,提高IO流的效率: 缓冲流分为字节缓冲流和字符缓冲流: 字节输入缓冲流和字节输出缓冲流如下: package com.zs.De ...

  5. pprof进行golang程序性能分析

    一.导入包 import _ "net/http/pprof" 二.启动监控routine go func() { http.ListenAndServe("0.0.0. ...

  6. Learning to Rank Short Text Pairs with Convolutional Deep Neural Networks(paper)

    本文重点: 和一般形式的文本处理方式一样,并没有特别大的差异,文章的重点在于提出了一个相似度矩阵 计算过程介绍: query和document中的首先通过word embedding处理后获得对应的表 ...

  7. testMk

    test test test test test test xinz 个人编程,写一个命令行程序 Red Green 功能设计,并提交文档到github 功利主义是一种在西方影响巨大的伦理学说,其原则 ...

  8. HashSet remove()

    HashSet继承自Set接口的方法:boolean remove(Object o); case1: public class ShortTest { public static void main ...

  9. java-Random类

    1.Random类的概述和方法使用 * A:Random类的概述 * 此类用于产生随机数 * 如果用相同的种子创建两个 Random 实例,则对每个实例进行相同的方法调用序列,它们将生成并返回相同的数 ...

  10. (15)javaScript入门

    什么是javaScript HTML用来做页面的架构,CSS用来做页面样式的布局 javaScript就是用来完成页面用户交互的,JS写的就是叫脚本 js就是弱语言类型,不同类型的时候可以相互转换 j ...