Re: Callbacks, GUI updates and threading
Re: Callbacks, GUI updates and threading
- Subject: Re: Callbacks, GUI updates and threading
- From: Brent Gulanowski <email@hidden>
- Date: Sun, 9 May 2004 21:59:39 -0400
On May 9, 2004, at 7:55 PM, Hamish Allan wrote:
>
Hi Brent, Andreas,
>
>
Thanks for your replies. I'd like to work the single-threaded model if
>
I can (I can increase the number of callbacks if necessary) but I'm
>
still not sure of the following:
>
>
Firstly: from where should I call the decoder? As I mentioned, the
>
window is not visible when loadDataRepresentation: ofType: is called,
>
and even windowDidLoad: is called before the window is visible. So I'd
>
really like to hook into proceedings a little later, i.e., just after
>
the window is visible, to create and run modally a sheet with a
>
progress bar and cancel button.
Well you can usually load all the data into some kind of lump very
quickly, and then do the slow processing in -makeWindowControllers,
right after allocating the window and displaying it. It's not intuitive
but it works fine. You can happily put up a sheet if you want to.
-makeWindowControllers {
YourWindowController *window = [[[YourWindowController alloc]
initWithWindowNibName:@"yourNIB"] autorelease];
[self addWindowController:windowController];
// begin your modal alert sheet on the window
// do your hard work, calling back to update progress indicator
// etc.
}
>
>
Secondly: if my decoder callbacks are to update the progressbar, I
>
presume they have to send [progressBar displayIfNeeded] after changing
>
its value, rather than just [progressBar setNeedsDisplay:YES] ,
>
because the event loop will not be run again until that function
>
returns (hence the rainbow beach ball). But if that is the case, how
>
will the events from my 'cancel' button be handled? It seems to me
>
that I'm definitely going to need a separate worker thread, no? Also,
>
do I need to call performSelectorOnMainThread: displayIfNeeded, or
>
will setNeedsDisplay:YES or even just doubleValue (which should
>
presumably call setNeedsDisplay itself) do? Are (determinate)
>
NSProgressIndicators animated from the main thread?
You want to look up information on running a modal session, which will
let you create your own modal event loop for your sheet. See the
NSApplication methods:
beginModalSessionForWindow:
beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo:
runModalSession:
endModalSession:
From the documentation on modal windows (ADC Home > Documentation >
Cocoa > User Experience > Windows and Panels > How Modal Windows Work):
The second mechanism for operating a modal window or panel, called a
modal session, allows the application to perform a long operation while
it still sends events to the window or panel. Modal sessions are
particularly useful for panels that allow the user to cancel or modify
an operation. To begin a modal session, invoke NSApplications
beginModalSessionForWindow: method, which sets the window up for the
session and returns an identifier used for other session-controlling
methods. (In Objective-C, the identifier is an integer; in Java, the
identifier is an instance of NSModalSession.) At this point, the
application can run in a loop that performs the operation, on each pass
sending runModalSession: to the application object so that pending
events can be dispatched to the modal window. This method returns a
code indicating whether the operation should continue, stop, or abort,
which is typically established by the methods described above for
runModalForWindow:. After the loop concludes, you can remove the window
from the screen and invoke NSApplications endModalSession: method to
restore the normal event loop. The method description for
runModalForWindow: in the NSApplication class specification includes
sample code illustrating a modal session.
>
>
On May 9, 2004, at 16:44, Brent Gulanowski wrote:
>
>
> These responses are just my own personal opinions:
>
>
>
> On May 8, 2004, at 3:51 PM, Hamish Allan wrote:
>
>
>
>> Hi,
>
>>
>
>> This is probably a bit of a newbie question (the cap fits and I'm
>
>> wearing it) but hopefully not a dumb one. I'm writing an audio
>
>> processing app and I've got a basic document framework in place. I'm
>
>> using libmad to decode MP3 data into PCM. Currently I'm doing this
>
>> all at load time, from within loadDataRepresentation: ofType:.
>
>> Therefore the program becomes unresponsive (spinning rainbow ball)
>
>> whilst the decoding happens.
>
>
>
> Have a program in similar situation. Mine could take from 10 seconds
>
> to a minute depending on resources of the computer.
>
>>
>
>> I've implemented a callback in the document's controller which
>
>> currently just NSLogs a number between 0 and 1, and I've arranged
>
>> for it to get called about a hundred times. Which is fine for the
>
>> developer, but the user really wants to see a progress bar. So my
>
>> first question is this: can I cause GUI elements to be updated from
>
>> within my callback? It seems to me intuitively unlikely that any GUI
>
>> updates should occur before loadDataRepresentation returns, but I
>
>> could well be wrong about that.
>
>
>
> A determinate vs indeterminate progress bar will require different
>
> solutions -- you probably want a determinate one. My program combined
>
> an indeterminate on e with a textual update of what was going on,
>
> using a callback to send a string to the window controller which
>
> would periodically update a textview with the "doing X" string. This
>
> is the same as your logging a percentage, in structure. We could both
>
> use a variation, which would involve a determinate progress bar and a
>
> percentage complete estimate being sent to the window controller to
>
> update the progress bar. This usually involves the bar growing at
>
> annoyingly different speeds, but that's the standard situation (e.g.:
>
> in Apple's Package Installer).
>
>>
>
>> Then I think, that progress bar should have a 'cancel' button next
>
>> to it. And ideally, the window containing that progress bar and
>
>> button should actually be a sheet off the document's window. But the
>
>> document's window doesn't appear until loadDataRepresentation:
>
>> ofType: returns. I couldn't spot a documentDidFinishLoading method,
>
>> so how do I manage this?
>
>
>
> If you want a cancel button, you could add a BOOL return value to the
>
> callback for whether to continue processing. This can be determined
>
> by running an event loop modally, which I have not tried. See the
>
> NSApplication methods -runModalForWindow: and -runModalSession:.
>
>>
>
>> I suppose my wider question is this: am I going to need to use
>
>> threads, or will callbacks be enough if the callback's return value
>
>> can cancel the operation and a responsiveness of (decoding time /
>
>> n), where n is currently 100, is enough?
>
>
>
> You don't need a separate thread. It is probably overkill and then
>
> you have to worry about locking and stuff, because you'll have to set
>
> a flag from the main thread and read it from the working thread (or
>
> maybe you can dispatch an event to the worker thread, but then you
>
> have to check that the methods in AppKit you use are thread safe; I'm
>
> speculating wildly here). Anyway you are still faced with the exact
>
> same responsiveness problem: the work thread has to stop what it's
>
> doing and check the status of the flag/event/callback, although I
>
> suppose there is the option of just terminating the thread with
>
> prejudice. I imagine that might have problems if you have a file open
>
> and are in the middle of a read or something, but I really don't know
>
> (it just feels like the number of variables increases unnecessarily).
>
>
>
> Cheers,
>
>
>
> --
>
> Brent Gulanowski email@hidden
>
>
--
Brent Gulanowski email@hidden
[demime 0.98b removed an attachment of type application/pkcs7-signature which had a name of smime.p7s]
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.