On Sat, 25 Feb 2006, Andreas Pakulat wrote: > On 25.02.06 09:55:18, Tina Isaksen wrote: > > > So I guess I've fallen in the trap of old-time thinking again... > > This time it's actually not python-specific "wrong-thinking" ;-);-) This > would've happend to you in C++, Java and any other threaded-language > with a threaded-toolkit like Qt.
I'm not sure I'd put it that way, but I know what Andreas is saying. Basically, in the doUpdateSources() method, Qt doesn't update any of the widgets until you return from the method. Actually, it could take the opportunity to refresh them, but I suspect that the updates are queued until it regains control (in the event loop). Here's the code again: def doUpdateSources(self): self.sourcesMessage.setEnabled(1) self.sourcesMessage.setText("Updating your sources, please wait...") os.chdir("/etc/apt/") self.mainTextWindow.setEnabled(1) self.mainTextWindow.setText(commands.getoutput("apt-get update")) self.mainTextWindow.append("Done!") self.mainTextWindow.scrollToBottom() self.pbSaveMain.setEnabled(0) self.mainTextWindow.setReadOnly(1) You will notice that the GUI will appear to freeze if the "apt-get update" operation takes a long time. With PyQt and Qt 3, you can drag other windows over your main window and "wipe away" the GUI because it isn't being updated. > You now have 2 Options: > > 1) Call QApplication::processEvents (IIRC that was the name of the > function) after setting the text. This makes Qt process any pending > events (like the redraw of the label) and then returning to your > code-part, AFAIK. Yes, this works quite well. However, it still doesn't solve the problem of long delays if "apt-get" takes a long time to finish. There's a way to fix this that _shouldn't_ be too hard (see option 3). > 2) put the "work" into a separate Thread (i.e. the hole > commands.getoutput which takes time) and communicate between the > mainTextWindow and the new Thread via Event's. But befor doing so (and > that is why I'm so brief here) you need to read some basics about > threading, so you don't shoot yourself in the foot with it (for example > never trigger drawing-operations outside the gui-thread). I don't have > any book title or tutorial or some such at hand to recommend, sorry. Many people regard threading as a fairly advanced technique, although Python's own threading module makes it look almost trivial. However, it can introduce even more ways to shoot yourself in the foot. Another option is: 3) Run "apt-get update" in another process, using either QProcess or a Python standard library module. QProcess will execute a command with arguments, and lets you read the output and errors as they become available. There are ways of monitoring the command's status and collecting the output. One of the easiest ways to use QProcess in this way is to do something like the following. (Note: this is untested.) def doUpdateSources(self): self.sourcesMessage.setEnabled(1) self.sourcesMessage.setText("Updating your sources, please wait...") os.chdir("/etc/apt/") self.mainTextWindow.setEnabled(1) process = QProcess("apt-get") process.addArgument("update") process.start() while process.canReadLineStdout(): self.mainTextWindow.append(process.readLineStdout()) qApp.processEvents() self.mainTextWindow.append("Done!") self.mainTextWindow.scrollToBottom() self.pbSaveMain.setEnabled(0) self.mainTextWindow.setReadOnly(1) Note that you need to import qApp and QProcess from the qt module. This doesn't cover things like error reporting, what happens when the process is killed, etc. Anyway, I'll put a more complete example on the Wiki because I encountered a few more problems with this approach, and I want to show some code that's as clear as possible. > > So what I want it to do is to display the 'please wait' in the > > sourceMessage *before* doing the 'commands.output', just as this little > > console script does: > > This works, because print does output the text directly, without the > need of a redraw-event processed and thus it works. Yes, this is the difference between a framework with its own event loop and one without. You need to let the event loop run every so often, so that redraws and other events can be processed. David _______________________________________________ PyKDE mailing list PyKDE@mats.imk.fraunhofer.de http://mats.imk.fraunhofer.de/mailman/listinfo/pykde