为啥可以连接到未声明为 Q_SLOTS 的函数?

Posted

技术标签:

【中文标题】为啥可以连接到未声明为 Q_SLOTS 的函数?【英文标题】:Why is it possible to connect to a function that is not declared as Q_SLOTS?为什么可以连接到未声明为 Q_SLOTS 的函数? 【发布时间】:2018-02-16 08:11:21 【问题描述】:

我“不小心”将信号连接到QWidget::setToolTip()

bool ok = connect(source, &Source::textSignal, widget, &QWidget::setToolTip);
Q_ASSERT(ok);

... 它奏效了。不仅连接成功,函数也被正确调用了。

自己试试吧: main.cpp

#include <QApplication>
#include <QLineEdit>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    QLineEdit le;
    bool ok = QObject::connect(&le, &QLineEdit::textChanged, &le, &QWidget::setToolTip);
    Q_ASSERT(ok);
    le.show();
    return a.exec();


setToolTip() 未声明为 slot

来自 qwidget.h:

    // [...]
public Q_SLOTS: // start of Q_SLOTS
    void setWindowTitle(const QString &);
#ifndef QT_NO_STYLE_STYLESHEET
    void setStyleSheet(const QString& styleSheet);
#endif
public: // from my understanding, this should end the Q_SLOTS region
#ifndef QT_NO_STYLE_STYLESHEET
    QString styleSheet() const;
#endif
    QString windowTitle() const;
    // [...]
    bool isWindowModified() const;
#ifndef QT_NO_TOOLTIP
    void setToolTip(const QString &); // no Q_SLOTS!?
    QString toolTip() const;
    void setToolTipDuration(int msec);
    int toolTipDuration() const;
#endif

所以我想知道:这是因为toolTip 被声明为Q_PROPERTY

    Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip)

文档没有提到这一点。

【问题讨论】:

一个相应的问题是:当你从一个不是信号的函数连接时会发生什么?答案是它在执行过程中编译并生成警告:“Qobject::connect signal not found in ...”。 @HansOlsson ... 并且 QObject::connect() 返回 false。这是我在尝试通过函数指针连接到常规函数时所期望的。 【参考方案1】:

我在woboq.com ('Connecting to any function' and preceding)找到了答案:

[...]

class Test : public QObject
 Q_OBJECT
public:
    Test() 
        connect(this, &Test::someSignal, this, &Test::someSlot);
    
signals:
    void someSignal(const QString &);
public:
    void someSlot(const QVariant &);
;

连接到任何功能

正如您在前面的示例中可能看到的那样,插槽只是被声明为公共而不是插槽。 Qt确实会直接调用slot的函数指针,不再需要moc自省。 (它仍然需要它的信号)

但我们还可以做的是连接到任何函数或函子:

static void someFunction() 
    qDebug() << "pressed";

// ... somewhere else
    QObject::connect(button, &QPushButton::clicked, someFunction);

当您将其与 boost 或 tr1::bind 相关联时,它会变得非常强大。

=> 函数指针无需声明为 public slots: 即可调用。

【讨论】:

请注意,这只适用于 Qt5。【参考方案2】:

有不同的连接方式(阅读 QObject 文档),有些需要函数名,有些需要元方法,有些需要指向成员的指针 em> 和一些函子。您只是在使用接受 指向成员的指针的那个。

QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)

QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection)

QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction 信号,const QObject *receiver, PointerToMemberFunction 方法,Qt::ConnectionType 类型 = Qt::AutoConnection)

QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction 信号, Functor 函子)

QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction 信号,const QObject *context,Functor 函子,Qt::ConnectionType 类型 = Qt::AutoConnection)

【讨论】:

我只是猜测 moc 会抱怨未声明函数指针 slot... moc 只处理头文件,不处理 c++ 文件

以上是关于为啥可以连接到未声明为 Q_SLOTS 的函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不声明 32 个插槽的情况下将 32 个按钮的 press() 信号连接到单个函数?

未捕获的错误:连接到数据库时调用未定义的函数 mysqli_connect() [重复]

为啥我的 android 设备无法连接到 charles 代理,但在我连接到 Fiddler 代理时可以工作?

flashfxp为啥不能连接到服务器

为啥 Node.js 无法连接到套接字时不会抛出错误?

Android Wifip2p:为啥连接到组所有者后组信息为空