Quest for sane signals in Qt - step 1 (hand coding a Q_OBJECT)

探索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
?

时间: 2025-02-01 08:02:40

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

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

1.如果在编译qt项目的时候,一般头文件里都有Q_OBJECT,但是用cmake来编译的时候,就会报错,那么怎么解决呢? 解决的办法就是要在cmake里面写好配置 命令,再编译的时候,就不会报错了,写法如下: project(cmakeandqt) cmake_minimum_required(VERSION 2.8) #add qt FIND_PACKAGE(Qt4 REQUIRED) set(QT_USE_QTMAIN TRUE) INCLUDE(${QT_USE_FILE}) includ

QT 的信号与槽

转载: QT 的信号与槽机制介绍 QT 是一个跨平台的 C++ GUI 应用构架,它提供了丰富的窗口部件集,具有面向对象.易于扩展.真正的组件编程等特点,更为引人注目的是目前 Linux 上最为流行的 KDE 桌面环境就是建立在 QT 库的基础之上.QT 支持下列平台:MS/WINDOWS-95.98.NT 和 2000:UNIX/X11-Linux.Sun Solaris.HP-UX.Digital Unix.IBM AIX.SGI IRIX:EMBEDDED- 支持 framebuffer

QT的信号和槽机制简介

信号与槽作为QT的核心机制在QT编程中有着广泛的应用,本文介绍了信号与槽的一些基本概念.元对象工具以及在实际使用过程中应注意的一些问题. QT是一个跨平台的C++ GUI应用构架,它提供了丰富的窗口部件集,具有面向对象.易于扩展.真正的组件编程等特点,更为引人注目的是目前Linux上最为流行的KDE桌面环境就是建立在QT库的基础之上.QT支持下列平台:MS/WINDOWS-95.98.NT和2000:UNIX/X11-Linux.Sun Solaris.HP-UX.Digital Unix.IB

QT开发(十三)——QT信号与槽机制

QT开发(十三)--QT信号与槽机制 一.QT消息模型 QT封装了具体操作系统的消息机制,遵循经典的GUI消息驱动事件模型. QT定义了与操作系统消息相关的自己的概念,即信号与槽. 信号signal是由操作系统产生的消息. 槽slot是程序中的消息处理函数. connect将系统消息绑定到消息处理函数. 信号到槽的连接必须发生在两个QT对象间. bool QObject::connect ( const QObject * sender, //发生对象 const char * signal,

MFC和QT的区别

MFC(微软基础类库)是专门为windows设计的一个用于开发图形用户界面的类库.MFC或多或少使用了面向对象的方法包装了Win32的API,正因如此,这些API有时是C++,有时是C,甚至是C和C++的混合体. Qt这个C++的图形库由Trolltech在1994年左右开发.它可以运行在Windows,Mac OS X, Unix,还有像Sharp Zaurus这类嵌入式系统中.Qt是完全面向对象的. Document/View model: MFC编程需要使用Document/View模式以

QT的信号与槽机制介绍

信号与槽作为QT的核心机制在QT编程中有着广泛的应用,本文介绍了信号与槽的一些基本概念.元对象工具以及在实际使用过程中应注意的一些问题. QT是一个跨平台的C++ GUI应用构架,它提供了丰富的窗口部件集,具有面向对象.易于扩展.真正的组件编程等特点,更为引人注目的是目前Linux上最为流行的KDE桌面环境就是建立在QT库的基础之上.QT支持下列平台:MS/WINDOWS-95.98.NT和2000:UNIX/X11-Linux.Sun Solaris.HP-UX.Digital Unix.IB

Qt 5中信号和槽的新语法

QT 是一个跨平台的 C++ GUI 应用构架,它提供了丰富的窗口部件集,具有面向对象.易于扩展.真正的组件编程等特点,更为引人注目的是目前 Linux 上最为流行的 KDE 桌面环境就是建立在 QT 库的基础之上.QT 支持下列平台:MS/WINDOWS-95.98.NT 和 2000:UNIX/X11-Linux.Sun Solaris.HP-UX.Digital Unix.IBM AIX.SGI IRIX:EMBEDDED- 支持 framebuffer 的 Linux 平台.伴随着 KD

Inside Qt Series (全集,共十六篇,不同版本的Qt有不同的实现)

Inside Qt 系列 QObject这个 class 是 QT 对象模型的核心,绝大部分的 QT 类都是从这个类继承而来.这个模型的中心特征就是一个叫做信号和槽(signaland slot)的机制来实现对象间的通讯,你可以把一个信号和另一个槽通过 connect(…) 方法连接起来,并可以使用 disconnect(…) 方法来断开这种连接,你还可以通过调用blockSignal(…) 这个方法来临时的阻塞信号,QObject 把它们自己组织在对象树中.当你创建一个 QObject 并使用

Qt核心机制与原理

转:  https://blog.csdn.net/light_in_dark/article/details/64125085 ★了解Qt和C++的关系 ★掌握Qt的信号/槽机制的原理和使用方法 ★了解Qt的元对象系统 ★掌握Qt的架构 ★理解Qt的事件模型,掌握其使用的时机 信号与槽.元对象系统.事件模型是Qt机制的核心,如果您想要掌握Qt编程,就需要对它们有比较深入的了解.本章重点介绍了信号与槽的基本概念和用法.元对象系统.Qt的事件模型,以及它们在实际使用过程中应注意的一些问题. Qt对