|
From: | Frederic Stark |
Subject: | Re: NSProgressIndicator movement inside a loop |
Date: | Tue, 01 Mar 2005 15:47:20 +0100 |
User-agent: | Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031007 |
Frederico Muñoz wrote:
Warning, long and boring mail ahead. I have a doubt about the best way to display a progress bar when theactions that will affect the progress movement are inside a loop.
[...]
I decided to use: [NSThread detachNewThreadSelector:@selector (installPackage:) toTarget:packageManager withObject:self];
When you have a problem and the solution is to fork a thread, you generally end up with two problems.
to overcome this (please disregard the "self" bit, I'm just experimenting for now). I set a autorelease pool in the installPackage method as per the documentation and now it works, I call [sender updateProgress] inside the copy loop and the progress bar is updated in real time. However it was brought to my attention that mixing this call inside a thread might not be very safe and would produce unpredictable results. I tried with [sender performSelectorOnMainThread: @selector(updateProgressWithFile:) withObject: file waitUntilDone: NO]; to be more thread friendly but this doesnt work, since not having it executing in the main thread (to escape the run loop draw timing) was the reason I created the thread in the first place, and this way the problem reapears, the progress bar is only updated after the loop exits. So, this is it. I really welcome any advices regarding any issu in this mail. I must add that dividing the steps into smaller chunks isn't really doable. I need to update it inside the loop that copies the file.
You actually have several solutions, I don't know which ones work with GNUstep, but I would recommend option 5:
1/ Separate your work in little chunks. Okay you said you did not want to do that, but I had to say that.
2/ Under NeXTstep, you could draw from a tight loop and call some sort of DPSFlush() to send the drawing to the window server. This was enough to display, but not enough to answer to events (ie: no buttons in the window), but you could cancel anything with the help of NXUserAborted(). Some form of updateWindows also used to do the same thing. More or less, YMMV.
3/ Like in 2, but you handle an inner run loop yourself. This was classic MacOS programming (IIRC, you can do the same in Win32). It basically consist of rewritting one step of the event loop in updateProgress method. You can look at the implementation of -[NSApp run] to grasp some knwoledge of how to do it. In general, the resulting UI are not very responsive, and you may be carefull of launching your install by a performAfterDelay (so you are not in 20 stack frame of UI code already).
4/ Fork a thread. The good thing is that, after fighting with obscure unreproducable bugs for a few days, you'll end up deciding you don't really care about that user interface (or life in general).
5/ Split the code in two processes (or fork). The command line version would do the install and write information on its standard output. The top-level one just listen to the file descriptor in its run loop and update the window.
Cheers, --fred
[Prev in Thread] | Current Thread | [Next in Thread] |