56 votes

Les signaux Qt peuvent-ils renvoyer une valeur?

Coup de pouce.Les signaux permet différentes stratégies d'utiliser les valeurs de retour des fentes pour former la valeur de retour du signal. E. g. l'ajout d'eux, formant un vector hors d'eux, ou le retour de la dernière.

La commune de la sagesse (exprimée dans la documentation de Qt [EDIT: ainsi que des réponses à cette question ]), c'est que pas une telle chose est possible avec Qt signaux.

Cependant, lorsque je lance le moc sur la définition de classe suivante:

class Object : public QObject {
    Q_OBJECT
public:
    explicit Object( QObject * parent=0 )
        : QObject( parent ) {}

public Q_SLOTS:
    void voidSlot();
    int intSlot();

Q_SIGNALS:
    void voidSignal();
    int intSignal();
};

Non seulement n'est pas moc se plaindre du signal avec la non-vide type de retour, il semble activement la mise en œuvre de telle manière à permettre un retour de la valeur à transmettre:

// SIGNAL 1
int Object::intSignal()
{
    int _t0;
    void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)) };
    QMetaObject::activate(this, &staticMetaObject, 1, _a);
    return _t0;
}

Donc: d'après les docs, cette chose n'est pas possible. Alors qu'est-ce que moc fais ici?

Les fentes peuvent avoir des valeurs de retour, de sorte que peut-on brancher une machine à sous avec une valeur de retour d'un signal avec une valeur de retour maintenant? Cela peut être possible, après tout? Si oui, est-il utile?

EDIT: je ne demande pas de solutions, donc merci de ne pas fournir tout.

EDIT: Il n'est évidemment pas utile en Qt::QueuedConnection mode (ce n'est pas le QPrintPreviewWidget API, bien que, et encore il existe et qu'il est utile). Mais qu' Qt::DirectConnection et Qt::BlockingQueuedConnection (ou Qt::AutoConnection, quand il décide d' Qt::DirectConnection).

42voto

jordan Points 595

OK. J'ai donc fait un peu plus d'enquête. Semble que ce soit possible. J'ai été en mesure d'émettre un signal, et de recevoir la valeur de l'emplacement du signal est connecté. Mais, le problème était qu'il ne retourne la dernière valeur de retour de la part des multiples connecté fentes:

Voici une définition simple d'une classe (main.cpp):

#include <QObject>
#include <QDebug>

class TestClass : public QObject
{
    Q_OBJECT
public:
    TestClass();

Q_SIGNALS:
    QString testSignal();

public Q_SLOTS:
    QString testSlot1() {
        return QLatin1String("testSlot1");
    }
    QString testSlot2() {
        return QLatin1String("testSlot2");
    }
};

TestClass::TestClass() {
    connect(this, SIGNAL(testSignal()), this, SLOT(testSlot1()));
    connect(this, SIGNAL(testSignal()), this, SLOT(testSlot2()));

    QString a = emit testSignal();
    qDebug() << a;
}

int main() {
    TestClass a;
}

#include "main.moc"

Lorsque la principale est exécuté, il construit l'une des classes de test. Le constructeur fils de deux fentes à la testSignal signal, puis émet le signal. Il saisit la valeur de retour de la fente(s) invoquée.

Malheureusement, vous obtenez seulement la dernière valeur de retour. Si vous évaluez le code ci-dessus, vous obtiendrez: "testSlot2", la dernière valeur de retour de la fentes du signal.

Voici pourquoi. Qt Signaux sont d'une syntaxe de sirop d'interface pour le modèle de signalisation. Machines à sous sont les bénéficiaires d'un signal. Dans une connexion directe signal-slot relation, on pourrait penser qu'elle similaire à (pseudo-code):

foreach slot in connectedSlotsForSignal(signal):
    value = invoke slot with parameters from signal
return value

Évidemment, le moc n'est un peu plus pour aider dans ce processus (rudimentaire vérification de type, etc), mais cela permet de peindre l'image.

9voto

vines Points 3649

Non, ils ne sont pas possibles.

Boost :: les signaux sont assez différents de ceux de Qt. Les premiers fournissent simplement un mécanisme avancé pour les rappels, quand les derniers implémentent réellement un idiome de signalisation. Lorsque vous travaillez dans un environnement multithread, les signaux de Qt (multithreads) dépendent des pompes de messages avec des files d'attente; ils sont donc appelés de manière asynchrone à un moment donné (inconnu du thread de l'émetteur).

1voto

jordan Points 595

La fonction qt_metacall de Qt renvoie un code d'état entier. Pour cette raison, je pense que cela rend une valeur de retour réelle impossible (sauf si vous manipulez le système de méta-objets et les fichiers moc après la précompilation).

Vous disposez cependant de paramètres de fonctionnement normaux. Il devrait être possible de modifier votre code de manière à utiliser les paramètres "out" qui agissent comme votre "retour".

 void ClassObj::method(return_type * return_)
{
    ...

    if(return_) *return_ = ...;
}

// somewhere else in the code...

return_type ret;
emit this->method(&ret);
 

1voto

user2014561 Points 547

Vous pouvez obtenir une valeur de retour de Qt signal avec le code suivant:

Mon exemple montre comment utiliser un Qt signal pour lire le texte d'un QLineEdit . J'étends juste ce que @jordan a proposé:

Il devrait être possible de modifier votre code de manière à utiliser les paramètres "out" qui agissent comme votre "retour".

 #include <QtCore>
#include <QtGui>

class SignalsRet : public QObject
{
    Q_OBJECT

public:
    SignalsRet()
    {
        connect(this, SIGNAL(Get(QString*)), SLOT(GetCurrentThread(QString*)), Qt::DirectConnection);
        connect(this, SIGNAL(GetFromAnotherThread(QString*)), SLOT(ReadObject(QString*)), Qt::BlockingQueuedConnection);
        edit.setText("This is a test");
    }

public slots:
    QString call()
    {
        QString text;
        emit Get(&text);
        return text;
    }

signals:
    void Get(QString *value);
    void GetFromAnotherThread(QString *value);

private slots:
    void GetCurrentThread(QString *value)
    {
        QThread *thread = QThread::currentThread();
        QThread *mainthread = this->thread();
        if(thread == mainthread) //Signal called from the same thread that SignalsRet class was living
            ReadObject(value);
        else //Signal called from another thread
            emit GetFromAnotherThread(value);
    }

    void ReadObject(QString *value)
    {
        QString text = edit.text();
        *value = text;
    }

private:
    QLineEdit edit;

};
 

Pour l'utiliser, il suffit de demander call(); .

-1voto

Vous pouvez essayer cette solution de contournement avec les éléments suivants: 1. Tous vos emplacements connectés doivent sauvegarder leur résultat dans un emplacement (conteneur) accessible depuis l'objet de signalisation 2. Le dernier emplacement connecté doit-il utiliser certaines méthodes (sélectionnez max ou dernière valeur) pour traiter les valeurs collectées et exposer le un seul 3. l'objet émetteur peut essayer d'accéder à ce résultat

juste comme une idée

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X