QTimer sendet kein timeout()-Signal

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Hallo liebe Gemeinde,

simpler Code, den ich hier habe. Sehe nur leider den Fehler nicht.

Code: Alles auswählen

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class Chatty(QMainWindow):
	def __init__(self, parent=None):
		super(Chatty, self).__init__(parent)
		
		timer1 = QTimer()
		self.connect(timer1, SIGNAL("timeout"), self.chatter)
		timer1.start(1000)

	def chatter(self):
		print "alive"
	
	
# Execute main function   
if __name__ == "__main__":
	import sys
	
	app = QApplication(sys.argv)
	gui = Chatty()
	gui.show()
	app.exec_()
Bräuchte nur schnell ein Prozess welcher Daten erzeugt, daher Chatty. Er printet nur leider nichts auf die Konsole.
Wäre für schnelle Hilfe dankbar
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Na, ich denke schon, dass das prinzipiell klappt. Allerdings scheint es da Probleme mit der Ausgabe nach Standard-Out zu geben. Hier findest Du ein Beispiel, welches in der GUI Aktualisierungen vornimmt:
https://bitbucket.org/lunar/snippets/sr ... untdown.py

Übrigens gibt es eine neu, pythonischere Syntax für connects:

Code: Alles auswählen

timer1.timeout.connect(self.chatter)
Wenn Du nur auf der Shell Daten benötigst, wozu dann Qt? Wieso nicht so:

Code: Alles auswählen

import time

while True:
    time.sleep(1)
    print "Hallo"
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Danke für die Antwort
Das Programm in C++ geschrieben funktioniert.
Hab auch gedacht, es würde an der Ausgabe nach stdout selber liegen und print durch qDebug() ersetzt. Leider auch ohne Erfolg!
Ich nehme jetzt einfach das Gegenstück von Python zu QTimer
Komisch ist die Sache trotzdem!
lunar

@twessels: "timer1" ist ein lokaler Name in "Chatty.__init__()". Nach dem Ende der Ausführung von "__init__()" wird der Name "timer1" gelöscht, weil der Namensraum der Methode "__init__()" natürlich nicht länger existiert. In dem gezeigten Programm ist dieser Name allerdings die einzige Referenz auf das daran gebundene "QTimer"-Objekt. Die automatische Speicherverwaltung von Python [1] löscht folglich das "QTimer"-Objekt. Somit kann nach dem Ablauf der Sekunde auch kein "timeout()" ausgelöst werden, das "QTimer"-Objekt existiert ja schon nicht mehr.

Die Lösung ist, irgendwie eine über das Ende von "__init__()" hinausgehende Referenz auf dieses Objekt zu halten. Dazu gibt es zwei Wege. Der erste ist, "timer1" an das Exemplar zu binden:

Code: Alles auswählen

self.timer1 = QTimer()
self.timer1.timeout.connect(self.chatter)
self.timer1.start(1000)
Die andere Lösung, welche ich in diesem Falle empfehlen würde, ist Qt dieses Objekt zur Verwaltung zu überlassen, indem man ein gültiges Vater-Objekt setzt:

Code: Alles auswählen

timer1 = QTimer(self)
timer1.timeout.connect(self.chatter)
timer1.start(1000)
Damit übernimmt Qt die Speicherverwaltung für dieses Objekt, was in diesem Fall empfehlenswert ist, da zumindest im gezeigten Beispieltext von Python aus nicht mehr auf das Objekt zugegriffen wird.

Im Allgemeinen ist es immer empfehlenswert, das Vater-Objekt für Qt-Objekte korrekt zu setzen. Das gilt vor allem und insbesondere für Steuerelemente, sprich Exemplare von "QWidget" oder davon abgeleiteten Klassen.

In C++ funktioniert der Quelltext übrigens nur deswegen, weil C++ keine Speicherverwaltung hat und Objekte somit "ewig" leben, wenn sie nicht explizit gelöscht werden. Kurz gesagt, der C++-Quelltext hat ein Speicherleck, und ist dementsprechend auch nicht sonderlich gut.


[1] Genauer gesagt geht es hier nur um die spezielle Implementierung der Speicherverwaltung in CPython. Alternative Python-Implementierungen wie Jython, IronPython und PyPy können sich hier in der Tat anders verhalten. Insgesamt ist das Verhalten für nicht mehr referenzierte Objekte in Python per definitionem undefiniert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Stimmt, den lokalen Namen hatte ich übersehen. Hier mal meine Lösung:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8

import sys
from PyQt4.QtCore import QObject, QTimer
from PyQt4.QtGui import QApplication

class MyTimer(QObject):

    def __init__(self):
        QObject.__init__(self)
        self.timer = QTimer()
        self.timer.timeout.connect(self.chat)    
        self.timer.start(1000)

    def chat(self):
        print "alive"


if __name__ == "__main__":
    app = QApplication(sys.argv)
    timer = MyTimer()
    app.exec_()
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
twessels
User
Beiträge: 22
Registriert: Freitag 21. Januar 2011, 13:05

Super!
Funktioniert Bestens! Danke
Antworten