Seite 1 von 1

QTimer sendet kein timeout()-Signal

Verfasst: Freitag 21. Januar 2011, 13:12
von twessels
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

Re: QTimer sendet kein timeout()-Signal

Verfasst: Freitag 21. Januar 2011, 13:39
von Hyperion
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"

Re: QTimer sendet kein timeout()-Signal

Verfasst: Freitag 21. Januar 2011, 14:06
von twessels
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!

Re: QTimer sendet kein timeout()-Signal

Verfasst: Freitag 21. Januar 2011, 14:21
von 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.

Re: QTimer sendet kein timeout()-Signal

Verfasst: Freitag 21. Januar 2011, 15:00
von Hyperion
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_()

Re: QTimer sendet kein timeout()-Signal

Verfasst: Freitag 21. Januar 2011, 15:25
von twessels
Super!
Funktioniert Bestens! Danke