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__)
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 函数,如上面的示例所示。
可以创建所有支持的连接类型
的连接。