Getting the GUI to update more frequently

Discussion in 'Mac Programming' started by jctj, Mar 8, 2010.

  1. jctj macrumors newbie

    Joined:
    Feb 24, 2010
    #1
    I use a NSTableView and a NSLevelIndicator in my user interface.

    When either of them change value, I correctly send the "reloadData" or "setNeedsDisplay" command. With the NSLevelIndicator, this is after setting the value with setIntValue: and with the NSTableView I have already updated the data that gets used in the numberOfRowsInTableView: and tableview:eek:bjectValueForTableColumn:row: methods. I know they work because they work just fine when the processing is done.

    My problem is getting the GUI to respond to the updating commands sooner than it is. Is there a way to tell my method that is generating all the data to 'take a breather' and let the GUI do its update? I have searched through a lot of documentation, and I can't find anything that deals with this.

    In short, the GUI actually updates only after the method ends its calculations (by which time it has gotten something on the order of 50 - 100 reloadData or setNeedsDisplay messages) rather then each time the "setNeedsDisplay" or "reloadData" method is called.

    In debugging, the Controller is getting the "updateTheTable" method call from the model (the program stops at the break point set there), and is sending the "reloadData" message to the NSTableView in the Viewer, but nothing happens in the viewer until the main method stops and the viewer goes back to idly waiting for me to do something. I need to get the intermediate results displayed rather than the final results.

    While this may be a bit vague, I am hoping someone recognizes my problem without me trying to post the entire program or me making a mock miniature program that accurately duplicates the problem.

    Thanks in advance
     
  2. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #2
    You could try calling display: instead of setNeedsDisplay:, which should force a refresh, but this is probably wasteful and will not solve your problem.

    What you really want is probably to spin your processing off to a separate thread and periodically call for UI updates on the main thread, which then should not block.
     
  3. Catfish_Man macrumors 68030

    Catfish_Man

    Joined:
    Sep 13, 2001
    Location:
    Portland, OR
    #3
    Or do the work in chunks. Something like (totally untested)

    Code:
    - (void) doWorkChunk {
         /*
          do a few % of the work 
         */
         [view setNeedsDisplay:YES];
         [self performSelector:@selector(doWorkChunk) afterDelay:0]; //do another chunk of work on the next runloop iteration
    }
    
     
  4. binkmail macrumors member

    Joined:
    Jan 5, 2010
    #4
    Or do your load work in a separate thread. (be sure to call setNeedsDisplay: from your main thread, though). Because AFAIK your windows/controls will not update until the RunLoop regains control of your application (ie. you are done doing your work) hence the behavior as described by you is normal.
     
  5. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #5
    Or you could use NSTimer to break the operation up along the main run loop. Set up a work queue that checks for work every 5 milliseconds or so and do a few operations before returning. Somewhat less of a hassle than threading.
     
  6. jctj thread starter macrumors newbie

    Joined:
    Feb 24, 2010
    #6
    By way of feedback:

    @HiRez: display: worked great for the NSLevelIndicator, but did not work for the NSTableView (I know you said it wouldn't work, but I had to try...). Strange that the NSTableView did not do its update when sent the display: message.

    @Catfish: Great idea, but won't work for details buried in the rest of the program, that were not mentioned in the OP. I'll keep that trick in mind for future problems.

    @All: I'll be looking into threads next, as that is something I want to learn more about anyway. I will also check out using the NSTimer in case this makes for an easier/faster solution while I work on learning threads.
     
  7. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #7
    It is fairly easy to just fire up a thread with +detachNewThreadSelector:toTarget:withObject: (NSThread class method), run through the process and then just exit, killing the thread. You can communicate with the main run loop with NSObject's -performSelectorOnMainThread:withObject:waitUntilDone: to make your display update, and use a simple boolean flag to signal a cancel, if you need that function as well.

    The most important thing you need to remember is to create an autorelease pool for the thread and, if you are using a lot of autoreleased objects in the thread, to drain and recreate it from time to time.
     

Share This Page