[PyQt] QThread and qRegisterMetaType

Hans-Peter Jansen hpj at urpla.net
Sun Oct 17 19:21:15 BST 2010


On Sunday 17 October 2010, 19:04:16 Janwillem van Dijk wrote:
> I want the output of a function that runs in a thread to be shown in
> a QPlainTextEdit on the main window. Now this crashes with a message
> that I sould use qRegisterMetaType. There are dozens of entries on
> the web on this but I could not find any that tells how to. At least
> not how to in python.
>
> My handicap is that I have not too much experience with
> oo-programming and none at all with c++. Thus suggestions like "call
> qRegisterMetaType() to register the data type before you establish
> the connection." are of no help and I have no idea what to make of
> things like "qRegisterMetaType<VolumeType>( "VolumeType" );"

This isn't possible is PyQt anyway, but these are signs of you doing 
something fundamentally wrong here.

> Please can someone tell me what to do with the small example below to
> get it working.

Please read the text: "Reentrancy and Thread-Safety" in Qt's 
documentation and use the back and forth links to explore this topic to 
some extend. 98% of what is said there is applicable to PyQt, too.

The example, that your code refers to did it right by using signals and 
slots to communicate between the main thread and the worker thread. You 
are not allowed to access widgets directly. 

BTW, your example isn't runnable since your ui file is missing.

> #!/usr/bin/python
> """
> Small test application for threaded output to a QPlainTextEdit.
> The main window consists of three buttons and the QPlainTextEdit
> - pressButtonInsert clicked is connected to slotInsert: append text
> to the edit widget
> - pressButtonThread clicked is connected to slotInsertThreaded:
>      append text to edit widget from within a separate thread
> - pressButtonClear clicked is connected to slotClear: clear the edit
> widget """
> import sys, time
> from PyQt4 import QtCore, QtGui
> from qPlainTextEditGui import Ui_Form #the main form containing the 4
> widgets
> class MyForm(QtGui.QMainWindow):
>      def __init__(self, parent=None):
>          QtGui.QWidget.__init__(self, parent)
>          self.ui = Ui_Form()
>          self.ui.setupUi(self)
>      def slotClear(self):
>          print('ButtonClear triggered')
>          self.ui.plainTextEdit.clear()
>      def slotInsert(self):
>          print('ButtonInsert triggered')
>          append_to_edit(self.ui.plainTextEdit)
>      def slotInsertThreaded(self):
>          print('ButtonTreaded triggered')
>          self.work = work_thread(self.ui.plainTextEdit)
   				   ^^^^^^^^^^^^^^^^^^^^^
				   Bad idea starts here

>          self.work.start()
>
> class work_thread(QtCore.QThread):
>      """
>      After
> http://joplaete.wordpress.com/2010/07/21/threading-with-pyqt4/ """
>      def __init__(self, edit, parent=None):
>          QtCore.QThread.__init__(self, parent)
>          self.edit = edit
>      def run(self):
>          append_to_edit(self.edit)
>
> def append_to_edit(edit):
>      for i in range(5):
>          edit.appendPlainText('line %d' % i)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	   *Bang*

>          time.sleep(0.5)
           ^^^^
           bad style, better use QThread.msleep()

>
> if __name__ == "__main__":
>      app = QtGui.QApplication(sys.argv)
>      myapp = MyForm()
>      myapp.show()
>      sys.exit(app.exec_())
>
> Now it works fine when pressButtonInsert is triggered but returns
> this when pressButtonThread is triggered:
> QObject::connect: Cannot queue arguments of type 'QTextBlock'
> (Make sure 'QTextBlock' is registered using qRegisterMetaType().)
> QObject::connect: Cannot queue arguments of type 'QTextCursor'
> (Make sure 'QTextCursor' is registered using qRegisterMetaType().)
>
> Many thanks for helping me out,
> Janwillem

Good luck,
Pete


More information about the PyQt mailing list