2012-04-06 12 views
1

Die Frage bezieht sich auf die Schnittstelle einer vorhandenen C, Pthread-basierten Anwendung mit QT GUI. Es scheint eine einfache Aufgabe zu tun, aber während ich gesucht habe (sowohl im Internet und durch Test & Fehler), fand ich keine akzeptable Lösung.Senden von Daten und Ereignissen von Pthread an eine QT QApplication mit QLabel und QImage

Jetzt verwendet die Anwendung eine bereits vorhandene C-Bibliothek, auf die ich keinen Zugriff habe, um ihren Code zu ändern.

Grundsätzlich implementiert die vorhandene Bibliothek eine Schleife, die in periodischer Weise einige Funktionen (mit einigen Daten) aufruft. Es sind nur die Funktionen (Funktionszeiger), die ich definieren kann.

In einer vollständigen Anwendung der vorbestehenden Bibliothek Schleife ruft die Funktionen (auch bekannt als "Init", "Prozess" und "UNINIT") in der folgenden Weise:

init(f); 
process(f); 
process(f); 
... 
process(f); 
... 
process(f); 
uninit(f); 

Das "f" a ist Struktur, die es ermöglicht, relevante Daten von Anruf zu Anruf zu halten, und "init" - und "uninint" -Funktionen dienen zum Einrichten und Löschen von Daten, die von f zugewiesen werden.

Nun macht die process() - Funktion einige Berechnungen und das Endergebnis ist eine Matrix, die ich als Bild innerhalb einer QT-GUI anzeigen möchte (so einfach wie es geht).

Die QT-GUI hat jedoch eine eigene, blockierende Ereignisschleife, aka myApp.exec().

Um dies zu erreichen, habe ich einen neuen Thread (Pthread) in meiner "init" -Funktion erstellt, der zuerst "f" -Felder mit relevanten Daten füllt und dann die myApp.exec() -Schleife eingibt. Die myApp ist eine einfache QApplication, die ein QLabel enthält, das eine aus einem QImage erstellte QPixmap anzeigt, mit der ich seine "bits()" -Daten mit den berechneten Daten filetieren kann (wobei einige Abbildungen hier irrelevant sind).

Danach führt die "process" -Funktion ihre sukzessiven Berechnungen durch, aktualisiert die "bits" -Daten von QImage (der "bits" -Zeiger ist durch die f-Struktur bekannt) und sollte dann die GUI zwingen, sich selbst zu aktualisieren.

Hier einige Code-Schnipsel sind:

init(f){ 
... 
pthread_create(&(f->qt_tid),NULL,&qtimgdisplay_main_thread,f); 
... 
} 

process(f){ 
... 
do_computation(); 
do_ update(f->bits); 
f->myLabel->repaint(); 
... 
} 

static void *qtimgdisplay_main_thread(void *arg){ 
    FStructure *f = (FStructure *)arg; 

    char arg0[] = "programName"; 
    char arg1[] = "arg"; 
    char arg2[] = "another arg"; 
    char* argv[] = { &arg0[0], &arg1[0], &arg2[0], NULL }; 
    int argc = (int)(sizeof(argv)/sizeof(argv[0])) - 1; 

    f->myApp = new QApplication(argc, &argv[0]); 

    //we create a image 
    QImage image(f->winwidth,f->winheight,QImage::Format_RGB32); 

    f->bits=image.bits(); //pointer to the underlying data image 

    f->myLabel=new QLabel(); 
    f->myLabel->setPixmap(QPixmap::fromImage(image)); 
    f->myLabel->show(); 

    f->myApp->exec(); 

    return NULL; 
} 

Obwohl etwas arbeiten (execpts einige zufällige Zugriffsfehler), das Problem mit dieser Lösung ist, dass es (richtig) angezeigt:

QPixmap: Es ist nicht sicher zu Pixmaps außerhalb der GUI-Thread

zu verwenden, die vollkommen wahr ist, da QWidgets sind nicht einspringend.

Also, dann habe ich versucht, eine Repaint() Nachricht an myApp, in einer asynchronen Art und Weise (ich muss noch vorstellen, wie ein Signal von meinem Prozess() an die QLabel myLabel), durch Ersetzen, innen " Prozess ":

f->myLabel->repaint(); 

mit:

f->myApp->postEvent(f->myLabel,new QPaintEvent(f->myLabel->rect())); 

das katastrophale Ergebnis ist, dass die QT-Oberfläche selbst nicht aktualisiert; mehr, Konsole angezeigt:

QPainter :: beginnen: Widget Malerei kann nur als Ergebnis einer paintEventO

beginnen Schließlich habe ich versucht, die gleiche Zeile oben mit etwas „intelligenter“ zu ersetzen (die ich hier gefunden: nämlich http://www.qtforum.org/article/18253/qpaintevent-problem-in-qt4.html):

QPaintEvent *pe = new QPaintEvent(f->myLabel->rect()); 
    f->myLabel->setAttribute(Qt::WA_WState_InPaintEvent, true); 
    f->myApp->sendEvent(s->myLabel,f->myLabel->rect()); 
    f->myLabel->setAttribute(Qt::WA_WState_InPaintEvent, false); 

Das fantastische Ergebnis ist, dass es nicht einmal kompilieren:

Fehler: keine passende Funktion für Aufruf von 'QApplication :: sendevent (QLabel * &, QRect)'

Ich bin verloren. Könnte jemand bitte helfen?

Dies sind einige mögliche Lösungen, die ich in Betracht gezogen:

1) ein QThread Gewinde anstelle eines Pthread Faden qtimgdisplay_main_thread machen, obwohl ich nicht sicher bin, das eine Hilfe sein wird;

2) versuche, einige Signale von meinem "Prozess" an die f-> myApp oder f-> myLabel zu senden, aber ich habe keine Ahnung, wie das zu tun ist, da "Prozess" auf einem Nicht-QThread läuft (und Es gibt keine Möglichkeit, auf den übergeordneten Thread zuzugreifen)

3) Erstellen und Löschen einer neuen QApplication mit allen zugehörigen QLabel und QImage innerhalb von "process", aber das ist unter normalen Umständen einfach überwältigend und idiotisch.

Ich danke Ihnen für das Lesen all dies zu lesen. Bitte versuchen Sie mir, falls möglich, einen Hinweis durch Code (keine andere Dokumentation) zu geben.

Edit: Es scheint, dass, wenn ich benutze:

f->myLabel->update(); 

statt:

f->myLabel->repaint(); 

in meinem "Prozess".

Kann jemand bestätigen, dass dies die richtige Lösung ist?

Antwort

0

meine eigene Frage zu beantworten: für alle, die in demselben Thema interessiert sein könnten, finden Sie diese Antwort: https://stackoverflow.com/a/10882705/1284631 für eine sehr schöne Lösung von https://stackoverflow.com/users/1329652/kuba-ober (unter Verwendung des QCoreApplication::postEvent-Methode) zur Verfügung gestellt und meine eigene Lösung, die Aufschreiben kocht und Instantiieren einer von einem speziellen Zweck QObject-abgeleiteten Methode befohlenen signalemittierenden Klasse zum Verbinden mit QT (dh einer Klasse, deren Methoden genauso wie andere C++ - Methoden aufgerufen werden, aber die einzige nützliche Sache ist, Signale an die QT zu senden QObjects).

Verwandte Themen