[PyQt] Events nachladen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
INFACT
User
Beiträge: 385
Registriert: Freitag 5. Dezember 2008, 16:08

Donnerstag 26. März 2009, 20:21

Sehr geehrtes Python Forum.

Ich versuche ein paintEvent nachzuladen, weil das Bild, zu einem Zeitpunkt verändert wurde.
Ich habe jetzt folgenden code der nicht funktioniert :wink::

Code: Alles auswählen

from PyQt4 import QtCore, QtGui
import time
import thread
import sys

class Win(QtGui.QWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, parent)
        self.Grafik = QtGui.QImage("python-logo.png")
        self.Ziel = QtCore.QRect(10, 10, 130, 130)
        self.Quelle = QtCore.QRect(0, 0,
                                   self.Grafik.width(),
                                   self.Grafik.height())

    def paintEvent(self, event):
        def ev():
            while 1:
                Painter = QtGui.QPainter(self)
                Painter.drawImage(self.Ziel, self.Grafik, self.Quelle)
                time.sleep(1)
        thread.start_new_thread(ev,())
    

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    picwin = Win()
    picwin.show()
    app.exec_()
Bin für Vorschläge offen.

Danke für Antworten!

Hier noch das Bild
http://img.xrmb2.net/images/506162.png


MfG Robin
[b][i]ein kleines game für die die lust haben http://konaminut.mybrute.com[/i][/b]
;-)
jerch
User
Beiträge: 1628
Registriert: Mittwoch 4. März 2009, 14:19

Freitag 27. März 2009, 13:02

Ich fasse mal kurz zusammen, was Du da machst:
Für jedes Paintevent startest Du einen neuen Thread. Jeder dieser Threads versucht, im Sekundentakt den Gui-MainThread zu manipulieren.
Fällt Dir da selbst was auf?

Paintevents löst die Gui z.B. für jede Größenänderung des Fensters aus (und zwar pixelweise), hier stößt Du schnell an das max. Threadlimit. Und Gui-Elemente ausserhalb des MainThreads anzufassen ist ohne Locks ein no go. Wobei ich nicht glaube, das Du im Sinn hattest, von abertausenden Threads auf die Gui zuzugreifen.

Wenn Du ein Bild ändern willst, falls sich die Ressource geändert hat, geht das ohne Threads, z.B. mit QTimer() Ressource überprüfen und bei Änderung Laden und ein update() des Widgets auslösen, wobei in der Methode paintEvent() die geänderte Ressource gezeichnet wird.
INFACT
User
Beiträge: 385
Registriert: Freitag 5. Dezember 2008, 16:08

Freitag 27. März 2009, 17:44

ahaa! :idea: :wink:
Ich habe das jetzt mit einem thread und update gemacht:

Code: Alles auswählen

from PyQt4 import QtCore, QtGui
import time
import thread
import sys

class Win(QtGui.QWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, parent)
        self.Grafik = QtGui.QImage("python-logo.png")
        self.Ziel = QtCore.QRect(10, 10, 130, 130)
        self.Quelle = QtCore.QRect(0, 0,
                                   self.Grafik.width(),
                                   self.Grafik.height())
        thread.start_new_thread(self.__event__,())

    def __event__(self):
        while 1:
            self.update()

    def paintEvent(self, event):
        self.Grafik = QtGui.QImage("python-logo.png")
        Painter = QtGui.QPainter(self)
        Painter.drawImage(self.Ziel, self.Grafik, self.Quelle)
   

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    picwin = Win()
    picwin.show()
    app.exec_()
[b][i]ein kleines game für die die lust haben http://konaminut.mybrute.com[/i][/b]
;-)
jerch
User
Beiträge: 1628
Registriert: Mittwoch 4. März 2009, 14:19

Freitag 27. März 2009, 18:26

Das Aufrufen von Widget-Funktionen von einem anderen Thread als dem Gui-MainThread ist nicht thread safe (self.update() in __event__()). Mit update() manipulierst Du den Eventloop der Gui, im worst case macht der Mainthread aber gerade dasselbe und dann passiert von nix bis Programmabsturz alles mögliche.

Wenn Du unbedingt Threads nehmen willst, brauchst Du hier entweder einen Locking-Mechanismus (z.B. QMutex), einen Callback zur Gui oder einen Signalmechanismus (QThread bringt den für Qt gleich mit). Siehe auch http://www.qtforum.org/article/26801/qt ... dgets.html
Ich glaube halt, das Du mit Threads hier mit Kanonen auf Spatzen schießt und mit QTimer gut bedient wärst.

Zwei Dinge noch zur Methode __event__(). Welchen Zweck verfolgst Du mit den Doppelunterstrichen? Die sind eigentlich nicht zum Selbstimplementieren gedacht sondern für Python-interne Dinge, die im Usernamensraum existieren (siehe PEP 8). Desweiteren dürfte Dein Loop dem Prozessor ordentlich einheizen ;)
Benutzeravatar
name
User
Beiträge: 254
Registriert: Dienstag 5. September 2006, 16:35
Wohnort: Wien
Kontaktdaten:

Freitag 27. März 2009, 18:28

wozu das thread? und ich glaub so ohne locking wird das nicht gehen. was spricht gegen QtCore.QTimer?
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
jerch
User
Beiträge: 1628
Registriert: Mittwoch 4. März 2009, 14:19

Freitag 27. März 2009, 20:11

Suchst Du nicht eher sowas?

Code: Alles auswählen

import sys, os
from PyQt4 import QtGui, QtCore

class MyWidget(QtGui.QWidget):
    def __init__(self,  parent=None):
        QtGui.QWidget.__init__(self,  parent)
        self.pixfile = 'bild.png'
        self.pix = QtGui.QPixmap(self.pixfile)
        self.pix.mtime = os.path.getmtime(self.pixfile)
        self.timer = QtCore.QTimer(self)
        self.connect(self.timer, QtCore.SIGNAL('timeout()'),
                     self.checkPixmap)
        self.timer.start(2000)
    
    def paintEvent(self, event):
        p = QtGui.QPainter(self)
        p.drawPixmap(QtCore.QRect(0, 0, self.pix.width(), self.pix.height()),
                     self.pix)
    
    def checkPixmap(self):
        last_change = os.path.getmtime(self.pixfile)
        if self.pix.mtime < last_change:
            self.pix.mtime = last_change
            self.pix.load(self.pixfile)
            self.update()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    w = MyWidget()
    w.show()
    sys.exit(app.exec_())
Der Dateizugriff für die mtime und das Laden müßte allerdings noch ein Exceptionhandling bekommen (falls die Datei zwischendurch nicht vorhanden sein sollte etc.)
lunar

Samstag 28. März 2009, 15:58

Mit QFileSystemWatcher kann man das auch gänzlich ohne Polling lösen.
jerch
User
Beiträge: 1628
Registriert: Mittwoch 4. März 2009, 14:19

Samstag 28. März 2009, 17:33

Danke für den Tipp, lunar. Wobei ich die file-descriptor-Beschränkung bei stärkerem Gebrauch ziemlich nervig finden würde.
Antworten