Seite 1 von 1
GUI Interaktion blockt Funktionen
Verfasst: 23. Juni 2009 16:05
von MisterJ
Hallo,
Ich habe eine Basisklasse und einen Thread, der sich in einer Schleife Daten holt und diese wieder an die Basisklasse zur Verarbeitung weiterleitet.
Sobald ich aber das Fenster des GUI verschiebe, wird die Verarbeitung unterbrochen. Ich dachte zunächst, dass es daran liegt, dass ich im Thread zum weiteren Verarbeiten der Daten ein Event auslöse und dass dann die GUI-Interaktion diese Events in den Hintergrund schiebt, um das Fenster zu aktualisieren (Größe, Position). Deshalb habe ich es auch mit Signals and Slots versucht, leider ohne Erfolg. Die Verarbeitung wird immer noch unterbrochen. Daher denke ich, dass dieses Problem auch ohne den Thread auftauchen würde.
Die Frage ist also, ob es einen Weg gibt, dass während der GUI-Interaktion trotzdem die Verarbeitung der Daten sichergestellt ist.
Danke im Voraus
Johannes
Verfasst: 23. Juni 2009 16:39
von Superheftig
benutzt du in dem thread exec(), also den qt eventloop oder hast du nen eigenen loop gemacht.
Falls du exec und signal und slots benutzt musst du nach dem erstellen des thread objekt dieses noch in den Thread verschieben.
Code: Alles auswählen
MyThread* thread = new MyThread();
thread.moToThread(thread);
thread.start();
Verfasst: 23. Juni 2009 16:51
von MisterJ
Ich bin nicht sicher, ob ich verstehe, was du meinst. Ich starte den Thread mit MyThread->start(), die run-Funktion habe ich überschrieben.
Was genau macht den das moToThread()?
Verfasst: 23. Juni 2009 19:51
von solarix
MisterJ hat geschrieben:
Was genau macht den das moToThread()?
moveToThread() bewirkt mal grundsätzlich das da:
http://doc.trolltech.com/4.3/qobject.html#moveToThread .. ein wichtige Folge davon ist, dass SIGNALs des Threads (der Thread-Klasse.. nicht die SIGNALs der dort verwalteten Objekte) auch wirklich in dessen Eventloop verarbeitet werden (und nicht im Eventloop der GUI).
siehe
http://www.qtforum.de/forum/viewtopic.php?t=9127
Die Frage ist also, ob es einen Weg gibt, dass während der GUI-Interaktion trotzdem die Verarbeitung der Daten sichergestellt ist.
Unbedingt! Aber weil Threading nicht einfach und Raten schlecht ist, wäre ein Demoprojekt super..
Verfasst: 25. Juni 2009 08:48
von Sonar
Ich habe ein ähnliches Problem, allerdings verwende ich auch noch die Qt 3.3.5. Und zwar kommuniziere ich mit meiner Applikation mit einem Gerät. Dafür nutze ich eine abgeleitete Klasse von QSocket.
Das ganze funktioniert eigentlich ohne Probleme, wenn ich nun aber das Windows-Applikationsfenster verschiebe, bekomme ich während des Verschiebens keine Antworten von dem Gerät.
Durch die Verfolgung über Breakpoints konnte ich feststellen, dass die Funktion writeBlock() der QSocket-Klasse auch beim Verschieben des Fensters ausgeführt wird, aber das Signal readyRead() kommt erst nachdem das Fenster wieder losgelassen wurde. Somit bekomme ich in der ganzen Zeit keine Antworten auf meine Anfragen an das Gerät.
Hat da jemand ne Idee wie man das umgehen kann oder was an meinem Quellcode falsch sein könnte.
P.S.: Ich vermute mittlerweile, dass Windows selbst die eingehenden Datenpakete nicht sofort an die Anwendung in dem zu verschiebenden Fenster weiterleitet, sondern erst wenn das Fenster wieder losgelassen wurde.
Verfasst: 26. Juni 2009 14:48
von MisterJ
Entschuldige bitte, dass es so lange gedauert hat.
Ich habe mal ein Minimalbeispiel erstellt:
Code: Alles auswählen
class Threadtest_3 : public QMainWindow
{
Q_OBJECT
public:
Basisklasse_(QWidget *parent = 0, Qt::WFlags flags = 0);
~Basisklasse();
Thread * m_pThread;
int m_iCounter;
private:
Ui::BasisklasseClass ui;
bool b_stop;
private slots:
void on_bt_stop_clicked();
void on_bt_start_clicked();
public slots:
void increaseCounter();
};
Basisklasse.cpp
Code: Alles auswählen
Basisklasse::Basisklasse(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
b_stop = false;
m_pThread = new Thread(this);
QObject::connect(m_pThread, SIGNAL(increase()), this, SLOT(increaseCounter()));
m_iCounter = 0;
}
Basisklasse::~Basisklasse()
{
}
void Basisklasse::on_bt_start_clicked()
{
m_pThread->m_bStopThread = false;
m_pThread->start();
}
void Basisklasse::on_bt_stop_clicked()
{
m_pThread->m_bStopThread = true;
}
void Basisklasse::increaseCounter()
{
//++m_iCounter;
ui.label_counterBC->setNum(m_iCounter);
QFile * data;
data = new QFile("testdatei.txt");
if (data->open(QFile::WriteOnly | QFile::Append))
{
QTextStream out(data);
out << "Result: " << m_iCounter << "\n";
data->close();
}
}
Thread.cpp
Code: Alles auswählen
void Strang::run(void){
while(!m_bStopThread)
{
++m_pParent->m_iCounter;
emit increase();
sleep(1);
}
}
Tread.h
Code: Alles auswählen
class Thread:
public QThread
{
Q_OBJECT
public:
Thread(QObject * parent);
~Thread(void);
void run(void);
private:
Basisklasse * m_pParent;
signals:
void increase();
};
Wenn ich das so implementiere, und das Fenster während der Ausführung bewege, schreibt es mir keine Zahlen in die Datei. Wenn ich das Fenster aber loslasse, dann gibt er die Zahl aus, die kommen würde, wenn er währenddessen weitergezählt hätte (was er somit ja nun auch getan hat). Wieso kann das Programm also weiterzählen, den Zähler aber nicht in eine Datei schreiben und wie kann ich das ändern?
Vielen Dank im Voraus
Edit: Wenn ich nach der Erzeugung des Threads diesen mit moveToThread(m_pThread) in den eigenen Thread verschiebe (habe ich das so richtig verstanden?), dann schreibt er n-Mal (Anzahl der durch Verschieben des Fensters übersprungenen Sekunden) die Zahl, die nach dem Loslassen erscheinen würde, wenn Counter normal erhöht wurde. Daraus würde ich schließen, dass der Thread immer schön "normal" und im Hintergrund den Counter erhöht, das emittierende Signal auch abschickt und die Basisklasse dann aber den Befehl zum schreiben des "aktuellen" Counters auf einen Stack wirft, dessen Priorität geringer ist als die Interaktion des Users mit der GUI und deshalb erst nach dem Loslassen den Counter in die Datei schreibt. Die GUI-Interaktion blockiert also somit die Basisklasse. Was kann man dagegen tun?
Verfasst: 26. Juni 2009 18:31
von solarix
Das Beispiel kann leider nicht zum Spielen verwendet werden (UI-Daten fehlen).. optimal wäre daher, ein komplettes Projekt als attachement..
Aber zum eigentlichen Problem: Du siehst ja nun, dass der Thread _nicht_ blockiert wird. Daher:
Die GUI-Interaktion blockiert also somit die Basisklasse. Was kann man dagegen tun?
Naja.. die Basisklasse _ist_ ja die GUI. Falls irgendwelche Funktionen also losgelöst arbeiten müssen, sind diese halt losgelöst zu implementieren: Mach eine eigene Log-Klasse, welche die Daten niederschreiben, dann hast du ein Problem weniger
