QThread und QInputDialog

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Christian_K_AT
User
Beiträge: 1
Registriert: Mittwoch 20. August 2014, 10:45

Hallo!

Ich arbeite gerade an einem Programm für automatisierte Kalibrationsprozeduren. Dafür habe ich etliche python-files in denen sequentiell diverse Geräte per visa angesprochen werden und Werte eingelesen werden. Ich habe dazu ein GUI erstellt, welches, unter anderem, ein QTextEdit enthält auf dem der stdout-stream ausgegeben wird. Mit einem Button führe ich die Kalibrations-files mit execfile("bsp.py") aus. Für die Ausgabe am QTextEdit habe ich mich an das Beispiel von stackoverflow gehalten. Dort wird mit QThread gearbeitet. Ich hab bei mir die Ausführung von meinen Kalibrations-files in einen eigenen Thread gepackt.

Mein Problem ist jetzt folgendes: In diesen Kalibrations-files möchte ich mit QInputDialog bzw. QMessageBox auf User-Kommandos warten. Aber das Aufrufen von QInputDialog bzw. QMessageBox führt zu einem Application Error mit dem Thread:
The instruction at "0x67102405" referenced memory at "0x000000010". The memory coud not be "written".
Der Fehler tritt auch nicht immer auf, sondern manchmal nach dem 10ten mal aufrufen oder manchmal gleich beim ersten Mal.

Hier ist ein Programm, was dem eigentlichen Programm nachempfunden ist, bei dem der Fehler auch auftritt.

Code: Alles auswählen

import sys
from Queue import Queue
from PyQt4.Qt import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *


class test(QMainWindow):
    def __init__(self,*args):
        QMainWindow.__init__(self,*args)

        self.btn1 = QPushButton('TEST',self)
        self.btn1.setGeometry(QRect(10,10,80,30))
        self.btn1.clicked.connect(self.start_thread)

        self.Text = QTextEdit(self)
        self.Text.setGeometry(0,80,220,50)


    def Output(self, text):
        cursor = self.Text.textCursor()
        cursor.movePosition(QTextCursor.End)
        cursor.insertText(text)
        self.Text.setTextCursor(cursor)
        self.Text.ensureCursorVisible()

    @pyqtSlot(str)
    def append_text(self,text):
        self.Text.moveCursor(QTextCursor.End)
        self.Text.insertPlainText( text )

    @pyqtSlot()
    def start_thread(self):
        self.thread = QThread()
        self.writeObject = ex(self)
        self.writeObject.moveToThread(self.thread)
        self.thread.started.connect(self.writeObject.run)
        self.thread.start()

class ex(QObject):
    def __init__(self,mainW,parent=None):
        QObject.__init__(self,parent)
        self.mainW = mainW

    @pyqtSlot()
    def run(self):
        execfile("module2.py")

class Receiver(QObject):
    mysignal = pyqtSignal(str)

    def __init__(self,queue,*args,**kwargs):
        QObject.__init__(self,*args,**kwargs)
        self.queue = queue

    @pyqtSlot()
    def run(self):
        while True:
            text = self.queue.get()
            self.mysignal.emit(text)

class WriteStream(object):
    def __init__(self,queue):
        self.queue = queue

    def write(self,text):
        self.queue.put(text)



class App(QApplication):
    def __init__(self, *args):
        QApplication.__init__(self,*args)
        self.main = test()
        self.main.setGeometry(QRect(100,100,220,130))
        self.main.show()


queue = Queue()
sys.stdout = WriteStream(queue)

app = App(sys.argv)
thread = QThread()
my_receiver = Receiver(queue)
my_receiver.mysignal.connect(app.main.append_text)
my_receiver.moveToThread(thread)
thread.started.connect(my_receiver.run)
thread.start()

app.exec_()
In dem file "module2.py" wird einfach nur ein QInputDialog aufgerufen.

Code: Alles auswählen

#.......#
x, ok = QInputDialog.getText(self.mainW,'MEssage','Enter:')
if ok:
    print (x)
#.......#
Nachdem ich noch nicht lange mit python arbeite, weiß ich auch nicht, ob die Art wie ich den stdout auf das QTextEdit umleite eine gute Wahl ist und mit Threads kenn ich mich eigentlich auch nicht wirklich aus. Hab mir sehr viel von diversen Beispielen aus dem Internet zusammengebaut. Vielleicht könnte man da ja auch noch was verbessern.

Ich hoffe Ihr könnt mir weiter helfen, bin scho ziemlich verzweifelt, weil ich nirgendwo etwas dazu finde.

Vielen Dank schon im Voraus :D .
Benutzeravatar
Madmartigan
User
Beiträge: 200
Registriert: Donnerstag 18. Juli 2013, 07:59
Wohnort: Berlin

Bevor du Instanzen eines QWidgets erzeugen kannst, musst du eine Instanz von QApplication erzeugen. Das passiert zwar für dein MainWindow, ist aber nicht zwingend erreichbar für den QDialog im separaten Thread.

Es ist prinzipiell, vorsichtig formuliert, keine gute Idee, aus einem Non-UI Thread auf Objekte der UI zuzugreifen. Deine UserInterface respektive auch der QDialog sind Teil des MainThreads/UIThreads. Wenn du neue Threads startest dann kannst du Signale nutzen um sicher zwischen den Thread zu kommunizieren. D.h. wenn du Interventionen des Nutzers in den separaten Threads brauchst, dann emittiere ein passendes Signal, reagiere im MainThread darauf und sende das Ergebnis zurück an den, natürlich wartenden, Thread.
Antworten