2

I 'accidentally' connected a signal to QWidget::setToolTip():

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

... and it worked. Not only did the connection succeed, the function was also invoked correctly.

Try it yourself:
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() is not declared as a slot.

from 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

So I wondered: Is this because toolTip is declared as Q_PROPERTY?

    Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip)

The documentation doesn't mention that.

Martin Hennings
  • 16,418
  • 9
  • 48
  • 68
  • A corresponding question is: what happens when you connect from a function that is not a SIGNAL? The answer is that it compiles and generates a warning during execution: "Qobject::connect signal not found in ...". – Hans Olsson Feb 16 '18 at 11:08
  • @HansOlsson ... and QObject::connect() returns false. This is what I would have expected when trying to connect to a regular function via function pointer. – Martin Hennings Feb 16 '18 at 14:56

2 Answers2

6

I found an answer at 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 &);
};

Connecting to any function

As you might have seen in the previous example, the slot was just declared as public and not as slot. Qt will indeed call directly the function pointer of the slot, and will not need moc introspection anymore. (It still needs it for the signal)

But what we can also do is connecting to any function or functor:

static void someFunction() {
    qDebug() << "pressed";
}
// ... somewhere else
    QObject::connect(button, &QPushButton::clicked, someFunction);

This can become very powerful when you associate that with boost or tr1::bind.

=> A function pointer doesn't need to be declared as public slots: to be invokable.

Martin Hennings
  • 16,418
  • 9
  • 48
  • 68
1

There is different way to connect (read QObject documentation), some need a function name, some a meta method, some a pointer to member and some a functor. You are just using the one that accepts a pointer to member.

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 signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)

QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)

QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69