Seite 1 von 1
Label friert ein
Verfasst: Samstag 9. Juni 2012, 15:42
von tron46
Hallo,
wir haben mithilfe von pyqt4 eine ui-File erstellt, auf dem sich unter anderem auch ein Label befindet (erstellt mit QLabel)"
Nun haben wir ein Pythonprogramm, in dem wir das ui-File laden, um darauf Daten zu visualisieren.
In besagtem Label wollen wir eine Anzeige für Gradzahlen machen dies machen wir in der Funktion:
wobei self._widget das UI-File ist
Code: Alles auswählen
def setLabel(self, d):
str = "Degree: %s"%d
self._widget.degree_label.setText(str)
die Gradzahl wird etwa alle 0.1 Sekunden neu gesetzt
das Problem:
nach einer gewissen (unregelmäßigen) Zeit (5 - 45 Minuten) friert das Label ein
und die Anzeige verändert sich nicht mehr
woran könnte dies liegen?
Vielen Dank im Voraus =)
Re: Label friert ein
Verfasst: Samstag 9. Juni 2012, 15:52
von EyDu
Hallo,
setzt ihr den Wert des Labels aus einem anderen Thread? Ohne entrspchende Maßnahmen kann es da zu solchen Problemen führen.
Sebastian
Re: Label friert ein
Verfasst: Samstag 9. Juni 2012, 16:40
von tron46
Ja, dass ist ein guter Hinweis die Grad-Änderungen werden mit einem eigenen Thread beobachtet,
der bei Änderungen diese Funktion aufruft.
Wir werden uns daran setzten dieses Problem zu fixen und anschliessend noch Rückmeldung geben ob es funktioniert hat.
Vielen Dank =)
Re: Label friert ein
Verfasst: Samstag 9. Juni 2012, 19:11
von Hyperion
Du musst die Threading Technologien von Qt nutzen.
Hier ein Beispiel dazu.
Re: Label friert ein
Verfasst: Sonntag 10. Juni 2012, 09:18
von tron46
Vielen dank, dass scheint das Problem behoben zu haben
wir machen den Labelupdate jetzt ueber einen QTimer
Code: Alles auswählen
# In der Init-Methode einen QTimer erstellen:
# Der Text, der in das Label geschrieben werden soll:
self.degree_text = "no data"
# Einen Timer erstellen, der automatisch alle 0.1 sekunden das Label updated:
self.timer = QTimer(self)
self.connect(self.timer, SIGNAL('timeout()'), self.update_label)
# den Timer mit der Verzögerung von 100 ms starten
self.timer.start(100)
(...)
# Die Labelbeschriftung setzen
def setLabel(self, d):
self.degree_text = "Degree: %s"%d
# Die Labelbeschriftung in das Label schreiben
def update_label(self):
self._widget.degree_label.setText(self.degree_text)
Vielen Dank fuer die schnelle Hilfe und die Tipps
// Edit:
jetzt ohne global,
sollte man es so machen?
Re: Label friert ein
Verfasst: Sonntag 10. Juni 2012, 13:14
von Hyperion
Noch ein Tipp: Vergesst `global`! Das ist in 99,9% aller Fälle böse.
Re: Label friert ein
Verfasst: Sonntag 10. Juni 2012, 13:33
von lunar
@tron64: Wieso verwendet ihr nicht "QThread", und löst ein Signal aus, um das Label zu aktualisieren? Das ist eleganter und effizienter als Polling mit "QTimer".
Re: Label friert ein
Verfasst: Sonntag 10. Juni 2012, 20:15
von tron46
lunar hat geschrieben:@tron64: Wieso verwendet ihr nicht "QThread", und löst ein Signal aus, um das Label zu aktualisieren? Das ist eleganter und effizienter als Polling mit "QTimer".
Die Degreeänderungen generieren wir nicht selbst, sondern wir bekommen sie übergeben
(eine Funktion wird automatisch aufgerufen wenn sich die Daten ändern)
Ich bin mir nicht sicher wie QThread funktioniert, kann man in QThread einfach ein Signal erstellen
und es immer passend aufrufen oder muss man mit einer Endlosschleife arbeiten
Ich würde die QThread Klasse jetzt so schreiben:
Code: Alles auswählen
class update_thread(QThread):
text = "no data"
def __init__(self, degree_label, parent=None):
QThread.__init__(self, parent)
self.label = degree_label
self._run_semaphore = QSemaphore(1)
def run(self):
while self._run_semaphore.available() > 0:
self.msleep(100)
self.label.setText(self.text)
def setText(self, degree_text):
self.text = degree_text
def stop(self):
self._run_semaphore.acquire(1)
Und dann eben immer setText mit dem richtigen Text aufrufen,
allerdings scheint mir diese Variante nicht effizienter als mit QTimer
ich würde ja das gleiche tun es nur in einer Extra Thread Klasse auslagern
übersehe ich eine Möglichkeit die QThread bietet?
Re: Label friert ein
Verfasst: Sonntag 10. Juni 2012, 20:20
von deets
Zuerstmal ist das glaube ich schlicht genauso falsch wie der urspruengliche timer-lose Ansatz. Wenn musst du in deinem Hintergrund-Thread ein *Signal* schicken an den GUI-Thread. Da sorgt dann Qt dafuer, dass das ohne Probleme passiert.
Der Thread sollte dann auch einfach auf die Semaphore blockierend warten, dann kommst du ohne diesen Verzug von 100ms daher. Stellt sich natuerlich die Frage wie die eigentlich gesetzt wird.
Re: Label friert ein
Verfasst: Sonntag 10. Juni 2012, 20:54
von lunar
@tron46: Es wird also ein Callback aufgerufen, wenn sich die Gradzahl ändert? Diese nicht ganz unwichtige Information hätte im ersten Beitrag stehen sollen…
Ihr braucht in diesem Fall nämlich weder Thread noch Timer. Stattdessen reicht es, einfach im Callback ein Signal auszulösen. Dazu müsst ihr eine Klasse erstellen, die von "QObject" erbt und ein Signal für die Aktualisierung der Gradzahl hat. Als Callback verwendet ihr dann eine Methode dieser Klasse an. In dieser Methode löst ihr das Signal mit dem neuen Wert für die Gradzahl aus. Dieses Signal verbindet ihr mit einer Methode, die den Zahlenwert als Text formatiert und dem Label zuweist.
Das ist eigentlich die einfachste und offensichtlichste Lösung.
Re: Label friert ein
Verfasst: Sonntag 10. Juni 2012, 22:23
von tron46
@lunar tut mir leid ich bin neu in Python und QT
wir verwenden ROS
http://www.ros.org/wiki/
und haben einen Subscriber geschrieben, der wie du richtig erkannt hast einen Callback aufruft,
wenn sich die entsprechenden Daten ändern
habe ich das richtig verstanden, dass es durch die Signale automatisch richtig syncronisiert wird?
Code: Alles auswählen
# die updater Klasse, die die Callback methode hat und ein Signal mit der
# Gradzahl erstellt
class degreeLabelUpdater(QObject):
dataUpdated = pyqtSignal(object)
def _updateWindDirection(self, data):
self.dataUpdated.emit(data.angle)
# in meiner HauptKlasse:
def __init__(self, context):
(...)
# In der Init methode erstelle eine ein Instanz dieser Callback-Klasse
self.degreeLabelUpdater = degreeLabelUpdater()
# verbinde die Callback(_updateWindDirection) Methode so das sie aufgerufen wird, wenn sie die Daten ändern
self._windDirectionSubscriber = rospy.Subscriber('wind', Winddirection, self.degreeLabelUpdater._updateWindDirection)
# dann verbinde ich das Signal aus der Callbackmethode mit der setlabel Methode
self.degreeLabelUpdater.dataUpdated.connect(self._updateDegreeLabel)
#und schließlich die set label methode, die das label setzt
def _updateDegreeLabel(self, degree):
text = "Degree: %s"%degree
self._widget.degree_label.setText(text)
Funktioniert das so oder ist wieder ein Fehler drin?
Vielen Dank für die ausdauernde Hilfe =)
// Edit:
bessere Variabeln Benennung und Anpassung mit Lunar's Hinweisen
Re: Label friert ein
Verfasst: Sonntag 10. Juni 2012, 22:49
von lunar
@tron46: Theoretisch funktioniert das so, praktisch musst Du das schon selbst ausprobieren
Ein paar Anmerkungen zum Quelltext: Nutze die
moderen API für Signale und Slots, um schwierig zu findende Fehler (durch Tippfehler in Signalnamen usw.) zu vermeiden. Statt einen "updater" und einen "subscriber" zu definieren, würde ich persönlich eher eine Klasse "WindObserver" (oder so) definieren, die den "subscriber" verwaltet und das Signal entsprechend auslöst.
Oder – wenn an mehreren Stellen ein "Signal"-Aufsatz für einen Subscriber benötigt wird – einen "QtSubscriber" von "rospy.Subscriber" ableiten, der automatisch einen "callback" verwendet, der dann ein Signal auslöst. Dazu ein
unvollständiges und ungetestetes Beispiel, Klassen und Modulnamen musst Du natürlich entsprechend anpassen.
Achte beim Programmieren auch ein bisschen auf die Namen, die Du so verwendest. "set_label", "subscriber" und "updater" sagen beispielsweise nichts darüber aus, welches Label mit welchem Text gesetzt wird, oder was "updater" eigentlich aktualisiert. Wenn Du Namen verwendest, die etwas über die eigentliche Funktion des Objekts aussagen, also beispielsweise "windSubscriber" oder "updateWindAngle" (statt "set_text"), dann erleichterst Du sowohl Dir selbst als auch Deinen Mitarbeiter die Arbeit ungemein.
Re: Label friert ein
Verfasst: Sonntag 10. Juni 2012, 23:11
von tron46
Vielen Dank für die vielen hilfreichen Tipps und sehr schnellen Antworten
das hat uns sehr geholfen
