Qt 信号和槽:简化的连接语法?

问题描述 投票:0回答:1

Qt 文档给出了以下将信号连接到插槽的示例:

QObject::connect(lineEdit, &QLineEdit::textChanged, label, &QLabel::setText);

但是,语法有点复杂(即冗长),可以通过使用此宏来缩短:

#define CONNECT(sender, signal, receiver, method) \
    QObject::connect( \
        sender,   &std::remove_pointer_t<decltype(sender)>::signal, \
        receiver, &std::remove_pointer_t<decltype(receiver)>::method \
    )

现在,上面的连接简化为:

CONNECT(lineEdit, textChanged, label, setText);

我已经测试过了,效果很好。因此,这个宏似乎允许将基于函子的连接语法(编译时类型检查和隐式类型转换)的优点与简单的语法结合起来。当然,它不适用于“超载”信号或槽,或者当连接类型不应该是默认的“Qt::AutoConnection”时。 我的问题是:这种方法是否存在我尚未意识到的问题,这实际上是一个好主意吗?

回答我自己的问题,我现在正在使用一种修改后的方法,发现它运行良好。 (请注意,此解决方案需要支持

__VA_OPT__ 的编译器,因此可以是 C++20 或 GNU 编译器。)

#define MEMBER(object, member, ...) object, __VA_OPT__(qOverload<__VA_ARGS__>)(&std::remove_pointer_t<decltype(object)>::member) #define SENDER(object, signal, ...) MEMBER(object, signal, __VA_ARGS__) #define RECEIVER(object, method, ...) MEMBER(object, method, __VA_ARGS__)
c++ qt signals-slots qt-signals qt-connection
1个回答
0
投票
现在,以下三个示例连接

connect(lineEdit, &QLineEdit::textChanged, label, &QLabel::setText);

connect(
    spinbox, qOverload<int>(&QSpinBox::valueChanged),
    lcdNumber, qOverload<int>(&QLCDNumber::display)
);

connect(socket, &QTcpSocket::connected, [=] () { /* ... */ });

简化为:
connect(SENDER(lineEdit, textChanged), RECEIVER(label, setText));
connect(SENDER(spinbox, valueChanged, int), RECEIVER(lcdNumber, display, int));
connect(SENDER(socket, connected), [=] () { /* ... */ });

我认为这种方法有一些优点:

仍然完全支持

基于函子的连接语法
的所有优点,例如编译时类型检查和隐式类型转换。

无需显式声明发送者和接收者对象的

类名
    。无论如何,编译器已经有了这些信息,并且显式连接到虚拟槽的重写基本实现应该(几乎?)永远没有必要。另外,无论如何,变量本身应该有一个干净的名称。那么我为什么要费心重述类名呢?
  • 即使读者没有查找宏定义,像SENDER(lineEdit, textChanged)
  • 这样的代码片段也是完全可以理解的。
  • 使用重载
  • 信号和槽很容易。只需在
  • SENDER
    RECEIVER
  • 宏中声明所需的函数签名即可。例如,
  • SENDER(spinbox, valueChanged, int) 将连接到 QSpinBox::valueChanged(int)
     过载。
    可以连接到 lambda 函数,如上面的示例所示。
    可以创建所有支持的
    连接类型
    的连接。
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.