QThread Problem

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

Hey,
hab das Problem, wenn ich diesen Thread starte, welcher immer BIlder empfängt und diese in einem neuen Dialog darstellen soll. Jedoch bekomm ich immer den Error: "QObject::killTimers: timers cannot be stopped from another thread"

Code: Alles auswählen

from PyQt4 import QtGui, QtCore, Qt
import socket, sys

class show_pics(QtCore.QThread):
    status = True
    #lock = QtCore.QReadWriteLock()
    
    
    def __init__(self):
        import tempfile
        self.screen = QtGui.QDialog()
        self.screen_view = QtGui.QGraphicsView(self.screen)
        self.screen.setWindowTitle(QtGui.QApplication.translate("Dialog", "Screen", None, QtGui.QApplication.UnicodeUTF8))
        self.scene = QtGui.QGraphicsScene(self.screen)
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.bind(("", 50001))
        server.listen(1)
        self.sock, self.ip = server.accept()
        QtCore.QThread.__init__(self)
        self.screen.show()
        self.screen_view.show()


    def run(self):
        while True:
            #if screen_cap.status == False:
            #    break
            size = int(self.sock.recv(1024))
            print size
            file = self.sock.recv(size)
            f = open("zwischen.jpg", "wb")
            f.write(file)
            f.close()
            pic = QtGui.QPixmap("zwischen.jpg")
            size = pic.rect()
            size = pic.rect()
            self.screen.resize(size.width(), size.height())
            self.screen_view.setGeometry(size)
            self.scene.clear()
            self.scene.addPixmap(pic)
            self.screen_view.setScene(self.scene)
        
 
            
            
   
            
app = QtGui.QApplication(sys.argv)     
g = show_pics()
g.start()
sys.exit(app.exec_())
Kann mir jemand sagen, was ich machen muss damit da alles rund läuft? ^^
Ach und nochmal ne Frage, ist es möglich dass Pixmap das Bild aus einem Tempfile laden kann? Wenn ich einfach QtGui.QPixmap(tmp), in der das Bild gespeichert war, genommen habe, gings nicht. Oder gibt es eine Möglichkeit das Empfangege direkt in eine Pixmap umzuwandeln?
Danke schonmal ;)

gruß
Zuletzt geändert von waki am Donnerstag 13. Januar 2011, 13:29, insgesamt 1-mal geändert.
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Hi,

ansich solltest du dein GUI von dem Hintergrundgewusel trennen. Heißt: Zwei Klassen eine für das GUI die andere startet den Server empfängt Daten etc. Desweiteren musst du dann mit Signalen und Slots arbeiten damit du sauber mit dem GUI arbeiten kannst.

Dazu mal ein Beispiel vom lunar welches mir geholfen hat Klick
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

Jo, ist klar. Nur bekomm ich dass mit den Signalen und Slots nicht ganz so auf die Reihe. Also das ganze clicked ist ja kein Problem, aber jetzt gerade bei meinem Beispiel. Ich wüsste nicht wie ich da die beiden Klassen verbinden könnte, außer über sehr umständliche Wege. Und bei dem Code-Snippet steig ich auch nicht ganz durch, wahrscheinlich weil ich ein ziemlicher Anfänger mit dieser GUI bin ^^ Würd mich über paar hilfreiche Links und Beispiele freuen ;)
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

waki hat geschrieben:Würd mich über paar hilfreiche Links und Beispiele freuen ;)
Da hatte erst kürzlich jemand ein ähnliches Problem:
http://www.python-forum.de/viewtopic.ph ... 25#p188125
Hier wird eine Textdatei in einem separaten Thread zeilenweise ausgelesen und dann per Signal / Slot zeilenweise an die GUI gesendet und verarbeitet. Dein Vorhaben ist eigentlich das selbe, du liest Bilder von einer Netzwerkverbindung und musst sie dann an die GUI senden. Du kannst ja einmal mit Text starten und wenn dies geht auf Bilder wechseln...
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Solltest aber aufpassen da ich in meinem Problem PySide und nicht PyQt4 benutze...
Es sollte reichen wenn du das

Code: Alles auswählen

from PySide import QtCore, QtGui
Durch

Code: Alles auswählen

from PyQt4 import QtCore, QtGui
ersetzt
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

Noch eine Frage: GIbt es eine Möglichkeit diesen Teil ohne wzischenspeichern zu realisieren? also dass ich das Bild direkt in eine QPixmap umwandeln kann?

Code: Alles auswählen

f = open("zwischen.jpg", "wb")
f.write(file)
f.close()
pic = QtGui.QPixmap("zwischen.jpg")
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

Thx
Ich hab jetzt eine anderes Problem, wenn ich "QtCore.Signal(unicode)" eingebe, dann sagt er mir, dass es Signal nicht gibt. Was mach ich falsch? ^^
lunar

Erwartest Du mit dieser Fehlerbeschreibung ernsthaft sinnvolle Antworten?!
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

ok, hatte das mit Signal - Slot eingebaut - ausgeführt:

Code: Alles auswählen

    newPic = QtCore.Signal()
AttributeError: 'module' object has no attribute 'Signal'
€: Hab in der Dokumentation nachgeschaut: QtCore.pyqtSignal() hat dann geklappt. Jedoch empfängt meine GUI das Signal nicht. Hab so definiert:

Code: Alles auswählen

screen.newPic.connect(self.showe)
aber self.showe wird nicht ausgeführt...

Code: Alles auswählen

class View(QtGui.QDialog):
    
    
    def __init__(self):
        QtGui.QDialog.__init__(self)
        self.screen_view = QtGui.QGraphicsView(self)
        self.setWindowTitle(QtGui.QApplication.translate("Dialog", "Picture", None, QtGui.QApplication.UnicodeUTF8))
        self.scene = QtGui.QGraphicsScene(self)
        self.resize(1000, 800)
        
        screen.newPic.connect(self.showe)

    def showe(self):
        pic = QtGui.QPixmap("zwischen.jpg")
        size = pic.rect()
        self.resize(size.width(), size.height())
        self.screen_view.setGeometry(size)
        self.scene.clear()
        self.scene.addPixmap(pic)
        self.screen_view.setScene(self.scene)
        self.screen_view.show()
        
        


class model(QtCore.QThread):
    newPic = QtCore.pyqtSignal()

    
    def __init__(self):
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.bind(("", 50001))
        server.listen(1)
        self.sock, self.ip = server.accept()
        QtCore.QThread.__init__(self)
        
        

    def run(self):
        while True:
            size = int(self.sock.recv(1024))
            self.sock.send("ok")
            file = self.sock.recv(size)
            with open("zwischen.jpg", "wb") as f:
                f.write(file)
            f.close()
            self.newPic.emit()
g = model()
screen = View()
g.start()        
            
        
Zuletzt geändert von waki am Mittwoch 12. Januar 2011, 20:31, insgesamt 1-mal geändert.
lunar

Und was soll diese Zeile bezwecken?!
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

update oben....
lunar

Jetzt überlege mal, in welcher Klasse Du das Signal definiert hast, und welchen Typ das Objekt hat, bei dem Du versuchst, das Signal zu verbinden.
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

weil sonst der QThread ein Problem meldet. Kann leider nicht den Fehlercode schicken, da ich am falschen pc bin...
lunar

Was immer Du mir damit sagen willst, mit meiner Anmerkung hat es jedenfalls nichts zu tun. Da Du diese also offenbar nicht verstanden hast, sage ich es Dir eben direkt: "screen.newPic.connect()" funktioniert deswegen nicht, weil "screen" gar kein "newPic"-Attribut hat. "screen" ist nämlich vom Typ "View", das "newPic"-Signal aber wird in der Klasse "model" definiert. Und wo kein Signal existiert, kann man natürlich auch keins verbinden.

Generell solltest Du beim Programmieren ein bisschen mehr Sorgfalt walten lassen und ein bisschen struktierter vorgehen, dann geschehen solche einfachen Fehler erst gar nicht.
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

Jetzt weiß ich was du meinst. Das ist nur ein Fehler hier, sry, habe es eigentlich so geschrieben:

Code: Alles auswählen

g = View()
screen = model()
screen.start() 
Und es funktioniert so nicht ^^
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Was hat das mit lunars Hinweisen zu tun? Das ändert nichts an dem beschriebenen Problem.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

Dass sich das Signal newPic sehrwohl im Object screen ist...
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

waki hat geschrieben:Dass sich das Signal newPic sehrwohl im Object screen ist...
Du meintest "befindet"?

Du hast drei Zeilen gezeigt, in denen Du Instanzen von Klassen bildest und Methoden aufrufst. Daraus kann ich nicht sehen, was Du ggf. an der Klasse View intern geändert hast!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
waki
User
Beiträge: 133
Registriert: Dienstag 9. März 2010, 16:41

Davor war "screen" eine Instanz der View-Klasse. Dies war jedoch nur ein Fehler hier, in meinem code ist "screen" die model-Klasse. Und in der Model-Klasse befindet sich das Signal newPic. Und dieses soll mit screen.newPic.connect() mit der View-Klasse verbunden werden, jedoch funktioniert dies nicht, da danch nicht die gewünschte Funktion beim auslösen des Signals aufgerufen wird...
Antworten