开发者

Qt "connect" syntax is very long. Is it any tricks to make it shorter?

In C# in order to connect a signal to slot (delegate to method) all i do is:

first.signal += second.slot

But in Qt it is:

connect( & first, SIGNAL( signal( int, int, QString ) ), & second, SLOT( slot( int, int, QSTring ) ) );

And this one is counted short, normally they are spawned 2-3 lines. Of course i fully understood that Qt mocks only .h files and for .cpp they are bound to standard syntax, but is it any tricks / ways to make signal-slot connectons a bit shorter? I know about auto-c开发者_如何学Goonnecting signals to slots by giving them special names, but this works only for signals in .ui file. Any hints?


I know about auto-connecting signals to slots by giving them special names, but this works only for signals in .ui file

That approach can be used outside of .ui files, you can call QMetaObject::connectSlotsByName anywhere you want.


If you find that long and repetitive, you could use macros to make the syntax lighter. For example:

#define S_i_i(x) x(int, int, QString)
#define CONNECT(sx,x,tx,sy,y,ty) connect(&x, SIGNAL(tx(sx)), &y, SLOT(ty(sy)))

CONNECT(signal, first, S_i_i, slot, second, S_i_i)

The drawback is that your code will lose in readability for others unless you choose your macros carefully.


If you are doing connections from a signal in a different object to a slot in this object, you can do a shortcut, and use this:

connect( & first, SIGNAL( signal( int, int, QString ) ), SLOT( slot( int, int, QSTring ) ) );

instead of this:

connect( & first, SIGNAL( signal( int, int, QString ) ), & second, SLOT( slot( int, int, QSTring ) ) );

which removes a little bit of the connection. There are other shortcuts available as well, I believe. However, your general point is valid, and is mostly a side-effect of how Qt does their signal/slot mechanism. If you really want a more terse syntax in C++, you could look at either the Boost::Signals or SigC++ libraries, which also provide a signal/slot mechanism. Be aware of syntax conflicts, however.


One trick would be to use QtCreator as an editor, as it lets you pick signals and slots from a drop-down-list as you type.

A seemingly unrelated reflection is that Qt strives to have a rather verbose API, as it is easier to read (and to remember when writing). Thus, they avoid abbreviations and write what they mean: QAbstractItemModel, setWindowTitle, etc. Not QAbstItModel, setWinTit, etc. More typing, less misunderstandings and linker errors (missing symbols)


Personally I don't think it's that bad. You only have to write it once for each signal/slot and most of the time you don't have to touch it afterwards.

The closest thing I found that helps in someway is using boost::bind/function with the signals/slots mechanism. It doesn't provide a direct answer to your question but it is related and you might make use of it. You can read about it here.


After a few years i have found a kind of solution that can make connections shorter. Solution is based on @WildSeal 's answer and uses this simple macro:

#define QCON( a, b, c, d ) VERIFY( QObject::connect( a, SIGNAL(b), c, SLOT(d) ) )

So, the long code in question:

VERIFY( QObject::connect( first, SIGNAL(signal(int,int,QString)), second, SLOT(slot(int,int,QSTring)) ) );

Will became significantly shorter:

QCON( first, signal(int,int,QString), second, slot(int,int,QString) );

Any comments and suggestions are welcome :). The only drawbacks i have found right now is that i need a separate macro to connect SIGNAL to SIGNAL. But since such operation is kind of rare i just introduced QCONS() and it does a trick.


Another solution for Qt5 and C++11-enabled compilers:

#define Q_CONNECT(sender, signal, receiver, slot) \
    QWidget::connect( \
        sender, &boost::remove_reference<boost::mpl::identity<decltype(*sender)>::type>::type::signal, \
        receiver, &boost::remove_reference<boost::mpl::identity<decltype(*receiver)>::type>::type::slot);

#define Q_CONNECT_LAMBDA(sender, signal, receiver) \
    QWidget::connect( \
    sender, &boost::remove_reference<boost::mpl::identity<decltype(*sender)>::type>::type::signal, \
    receiver);

Note that boost::mpl::identity is only needed for compilers that don't yet handle the following (like VS2010):

decltype(expr)::member

Usage example:

Q_CONNECT(
    this, mySignalMethodName,
    &someHandler, handlerMethodName);

Q_CONNECT_LAMBDA(
    this, mySignalMethodName,
    [=]() { handlerCode(); });

Pros:

  • no need to type in argument lists;
  • no need to explicitly duplicate type information;
  • no need to use any of SIGNAL, SLOT, Q_SIGNAL, Q_SLOT macros;
  • all compatibility checks are compile-time.

Cons:

  • won't work with overloaded methods.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜