[PyQt] QThread problem in linux

mir amicitas amicitas at gmail.com
Tue Mar 24 21:41:35 GMT 2009


(ack sorry I pressed the wrong button and sent it before it was done.
Here is the exciting conculsion . . .)

I think what you probably want to do here is to put your loadModule()
function in a thread instead of the the progress dialog.  That is to
say the program that you want to run in the background is in the
thread.

Then to communicate with the progress dialog, you can have
loadModule() emit events.
To have the dialog communicate with the thread (to cancel for example)
the simplest way is to give them both access to a variable that
defines the cancel state.  Then have your thread check this variable
occasionally.

The harder part is making sure that your thread can properly access
everything else that it needs in your application.  To do this you
will probably want to make use of a QMutexLocker in your thread.


I home some of this is helpful, I am not an expert on multithreaded
programming (though I have build a couple of applications).  Keeping
everything straight is kinda hard.

Novi


Here is a small example:

class LoadModuleThread(QThread):
   def __init__(self, moduleName):
       QThread.__init__(self)

       self.mutex = QtCore.QMutex()

   def run(self):
       with QtCore.QMutexLocker(self.mutex) as locker:
           t = og.Timer()

           for m in self.moduleList:
               if m.name == moduleName:
                   if m.hasDependencies: # load modules on wich the
main module depends before the main module is loaded
                       for moduleDependencie in m.moduleDependencies:
                           for m2 in self.moduleList:
                               if m2.name == moduleDependencie:

self.emit(QtCore.SIGNAL('setProgress'), 2, "Loading Dependencie: " +
moduleDependencie)
                                   m2.load()

               self.emit(QtCore.SIGNAL('setProgress'), 4, "Loading " +
moduleName)
               m.load()

           self.emit(QtCore.SIGNAL('loadingDone'))
           print "Time to load module: " + str(t.getMilliseconds() /
1000.0) + " seconds"


def startLoadingModules(self):
    self.thread = LoadModuleThread(moduleName)

    self.connect(self.thread
                        ,QtCore.SIGNAL('setProgress')
                        ,self.setProgress)
    self.connect(self.thread
                        ,QtCore.SIGNAL('loadingDone')
                        ,self.setProgressDone)

   self.progress = QProgressDialog("Loading " + moduleName, "Abort
Loading", min, max, None);
   self.progress.setWindowModality(Qt.WindowModal)
   self.progress.show()

   self.thread.start()

def setProgress(self, progress, labelText):
   self.progress.setLabelText(labelText)
   self.progress.setValue(progress)

def setProgressDone(self):
  self.progress.quit()


---------------
On Tue, Mar 24, 2009 at 11:38 AM, Stefan Stammberger
<sstammberger at web.de> wrote:
>
> Hi,
>
> I have a small QThread problem here. I'm trying to do a small progress bar in my app while my app is working. I have already tried QApplication.processEvents() which works very well in Windows
> but screws everything up in Linux. When I use it my app receives key events only once in 10 tries, its completely unreliable. Now I have read in a kde mailing list that QApplication.processEvents()
> is a bad thing anyway I have tried putting the progress bar in its own thread. This is my ProgreassBar class code:
>
> class ProgressBarThread(QThread):
>    def __init__(self, min, max, moduleName):
>        QThread.__init__(self)
>        self.progress = QProgressDialog("Loading " + moduleName, "Abort Loading", min, max, None);
>        self.progress.setWindowModality(Qt.WindowModal)
>
>    def setProgress(self, progress, labelText):
>        self.progress.setLabelText(labelText)
>        self.progress.setValue(progress)
>
>    def run(self):
>        self.progress.show()
>        self.exec_()
>
>
> And how I use it:
>
>   def loadModule(self, moduleName):
>        t = og.Timer()
>
>        self.progress = ProgressBarThread(0, 8, moduleName)
>        self.progress.start()
>
>        for m in self.moduleList:
>            if m.name == moduleName:
>                if m.hasDependencies: # load modules on wich the main module depends before the main module is loaded
>                    for moduleDependencie in m.moduleDependencies:
>                        for m2 in self.moduleList:
>                            if m2.name == moduleDependencie:
>                                self.progress.setProgress(2, "Loading Dependencie: " + moduleDependencie)
>                                m2.load()
>                                self.modelSelectionDialog.scanDirForModels(m2.moduleRoot)
>                                self.materialSelectionDialog.scanDirForMaterials(m2.moduleRoot)
>                                self.mainModuledependencieList.append(m2)
>
>                self.progress.setProgress(4, "Loading " + moduleName)
>                m.load()
>                self.progress.setProgress(6, "Scan for models...")
>                self.modelSelectionDialog.scanDirForModels(m.moduleRoot)
>                self.progress.setProgress(8, "Scan for materials")
>                self.materialSelectionDialog.scanDirForMaterials(m.moduleRoot)
>                self.mainModule = m
>                self.moduleExplorer.setCurrentModule(m)
>
>        self.progress.quit()
>        print "Time to load module: " + str(t.getMilliseconds() / 1000.0) + " seconds"
>        del t
>
> When using this I get a few warnings:
>
> QPixmap: It is not safe to use pixmaps outside the GUI thread
> QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread
>
> And the worst:
>
> X Error: RenderBadGlyphSet (invalid GlyphSet parameter) 181
>
> Extension: 155 (RENDER)
>
> Minor opcode: 25 (RenderCompositeGlyphs32)
>
> Resource id: 0x0
>
>
>
> When I get this error no text in my application is drawn at all. The strange thing is,
> when I have a cleanly booted system, it works very well the first time I start the application.
> On the second time I don't get any text. Two screen shots:
> How it looks without text: http://picasaweb.google.de/some.fusion/Lockenwickler?feat=directlink#5316822651416543426
> And how it should look: http://picasaweb.google.de/some.fusion/Lockenwickler?feat=directlink#5316822694766353394
>
> I don't know what I'm doing wrong here, I'm very new to the Threading stuff.
>
> In case anybody wonders what my app is all about, its a game editor for an open source game.
> http://www.youtube.com/watch?v=J-1ekVyv19o and http://www.youtube.com/watch?v=R0ZKMbLtXYY
>
> Sorry for this long email!
>
> Thank you very much!
> Stefan Stammberger
>
>
>
>
> _______________________________________________
> PyQt mailing list    PyQt at riverbankcomputing.com
> http://www.riverbankcomputing.com/mailman/listinfo/pyqt



More information about the PyQt mailing list