2010-11-24 7 views
3

Ich versuche, das Ergebnis anzeigen und erhalten ein Meldungsfeld von außerhalb einer QObject-Klasse. Ich scheine in der Lage sein den Dialog wie folgt zu generieren:Anzeigen und erhalten das Ergebnis einer QMessageBox von außerhalb eines QObject

#include <iostream> 

#include <QApplication> 
#include <QtConcurrentRun> 
#include <QMessageBox> 

class DialogHandler : public QObject 
{ 
Q_OBJECT 

signals: 
    void MySignal(); 

public: 
    DialogHandler() 
    { 
    connect(this, SIGNAL(MySignal()), this, SLOT(MySlot())); 
    } 

    void EmitSignal() 
    { 
    emit MySignal(); 
    } 

public slots: 
    void MySlot() 
    { 
    QMessageBox* dialog = new QMessageBox; 
    dialog->setText("Test Text"); 
    dialog->exec(); 
    int result = dialog->result(); 
    if(result) 
    { 
     std::cout << "ok" << std::endl; 
    } 
    else 
    { 
     std::cout << "invalid" << std::endl; 
    } 
    } 
}; 

#include "main.moc" // For CMake's automoc 

void MyFunction(DialogHandler* dialogHandler) 
{ 
    dialogHandler->EmitSignal(); 
} 

int main(int argc, char *argv[]) 
{ 
    QApplication app(argc, argv); 

    DialogHandler* dialogHandler = new DialogHandler; 

    MyFunction(dialogHandler); 

    return app.exec(); 
} 

Um das Ergebnis zurück in MyFunction zu bekommen, scheint es zu funktionieren einfach zu tun, ein Objekt übergeben, mit dem Ergebnis so füllen:

#include <iostream> 

#include <QApplication> 
#include <QtConcurrentRun> 
#include <QMessageBox> 

class DialogHandler : public QObject 
{ 
Q_OBJECT 

signals: 
    void MySignal(int* returnValue); 

public: 
    DialogHandler() 
    { 
    connect(this, SIGNAL(MySignal(int*)), this, SLOT(MySlot(int*)), Qt::BlockingQueuedConnection); 
    } 

    void EmitSignal(int* returnValue) 
    { 
    emit MySignal(returnValue); 
    } 

public slots: 
    void MySlot(int* returnValue) 
    { 
    std::cout << "input: " << *returnValue << std::endl; 
    QMessageBox* dialog = new QMessageBox; 
    dialog->addButton(QMessageBox::Yes); 
    dialog->addButton(QMessageBox::No); 
    dialog->setText("Test Text"); 
    dialog->exec(); 
    int result = dialog->result(); 
    if(result == QMessageBox::Yes) 
    { 
     *returnValue = 1; 
    } 
    else 
    { 
     *returnValue = 0; 
    } 
    } 
}; 

#include "main.moc" // For CMake's automoc 

void MyFunction(DialogHandler* dialogHandler) 
{ 
    int returnValue = -1; 
    dialogHandler->EmitSignal(&returnValue); 

    std::cout << "returnValue: " << returnValue << std::endl; 
} 

int main(int argc, char *argv[]) 
{ 
    QApplication app(argc, argv); 

    DialogHandler* dialogHandler = new DialogHandler; 

    QtConcurrent::run(MyFunction, dialogHandler); 

    std::cout << "End" << std::endl; 
    return app.exec(); 
} 

Scheint das vernünftig? Gibt es einen besseren Weg, es zu tun?

+0

Sie verwenden also mehrere Threads? Sie könnten eine von QObject abgeleitete Klasse in MyClass erstellen, die nichts anderes tut, als die msgbox in einem Slot anzuzeigen, oder Sie könnten das Objekt im anderen Thread mit Ihrem Widget verbinden und dort die Messagebox anzeigen. –

+0

Ah, richtig, ich habe angegeben, dass ich nicht in einer QObject-Klasse bin, aber Sie haben eindeutig Recht, dass dies daran liegt, dass diese Klasse nicht im selben Thread ist. Ich weiß immer noch nicht, wie man das Signal und den Steckplatz verbindet, weil ich hier bin: Formular :: MyClass :: MyFunction() { ... macht die Funktion ... ... ein Fehler passiert. .. ProduceMessageBox() } Da MyClass kein QObject ist, kann es keine Signale aussenden. Wie kann ich also eine Funktion von Form aufrufen? –

Antwort

1

Dies ist nicht möglich, wie Sie es haben, aber mit ein wenig Arbeit könnte es getan werden. Eine Option wäre natürlich, Ihre Klasse in ein QObject zu konvertieren, an dem Sie Signale senden könnten. Es hilft jedoch nicht für die Verzögerung während der Ausführung. Wenn dies erforderlich ist, können Sie eine Nachrichtenklasse verwenden, die im Hauptthread der Benutzeroberfläche enthalten ist, aber von anderen Threads aus aufgerufen werden kann. Die von anderen Threads aufgerufene Funktion müsste sperren, einen Semaphor erzeugen und ein Ereignis an sich selbst senden, wobei der Semaphor und die Nachricht angezeigt werden. Dann würden Sie in customEvent (das im UI-Thread enthalten wäre) das Meldungsfeld erstellen, es ausführen und das Semaphor auslösen, nachdem das Meldungsfeld gelöscht wurde.

Natürlich wird es etwas komplizierter, wenn Sie Informationen auch andersherum senden müssen. Dann brauchst du ein komplettes Subsystem für dein Programm, anstatt nur eine Basisklasse, wie ich sie hier beschreibe.

+0

Ich denke, ich habe den "one way" Fall (siehe meine Bearbeitung in der Frage). Ist es das, was du meintest? Es macht keine explizite Sperre, aber es scheint zu funktionieren. Haben Sie ein Beispiel, wie Sie Informationen zurücksenden können? –

+0

Ich habe Ihren Code nicht vollständig validiert, aber der Ansatz könnte funktionieren. Sie müssen sicherstellen, dass Ihr DialogHandler im UI-Thread instanziiert ist (wie im Beispiel main). Das Zurücksenden von Informationen könnte über ein benutzerdefiniertes Ereignis zurück zum Ursprungsobjekt erfolgen, obwohl ich keine besonderen Beispiele zur Hand habe. –

+0

Ich dachte, das funktionierte, aber es scheint nur das erste Mal durch eine Schleife zu funktionieren, und dann scheint das Programm nur zu stocken (Prozessor ist bei 0%, aber es läuft nie die zweite Iteration)? http://codepad.org/KoyJBU6C - Hier würde ich erwarten, dass das Meldungsfenster dreimal hintereinander angezeigt wird. Allerdings wird es nur einmal gezeigt, dann macht es diesen "Stall", den ich erwähnt habe. Irgendwelche Gedanken darüber, warum das passieren könnte? –

Verwandte Themen