linking a NSTimer to a NSProgressIndicator - cocoa

I need to make an NSTimer that will tell another class to fire in 10 seconds, and I would also like to use it to animate a determinate NSProgressIndicator. I also need to know how to change my indeterminate progress indicator to determinate. I was able to find a Apple doc on this, however a more in-depth explanation would help.

From indeterminate to determinate NSProgressIndicator You can change in IB. Select Your progressIndicator and go to Attributes inspector and uncheck Indeterminate checkbox like this:
Or it can be done programatically:
[progressIndicatorOutlet setIndeterminate:NO];
Note: progressIndicatorOutlet is Your NSProgressIndicator outlet, so don't forget to IBOutlet it.
Determinate NSProgressIndicator animation:
It's very simple just set and change value like this:
[progressIndicatorOutlet setDoubleValue:10];
Note: progressIndicatorOutlet is Your NSProgressIndicator outlet, so don't forget to IBOutlet it.
NSTimer:
Simple timer example:
//Place this where You want to call class after 10 sec. (for example: when button pressed)
//It will call class with name callAfter10sec after 10 sec. Place in there what You need to do.
[NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(callAfter10sec:)
userInfo:nil
repeats:YES];
Don't forget to add class which I mentioned in comments like this:
-(void)callAfter10sec:(NSTimer *)time {
// Do what You want here
}

Hope it helps.
Using the following way we can achieve what is expected
NSInteger progressValue;
NSTimer *timerObject;
progressValue = progressMaxValue;
timerObject = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(incrementProgressBar) userInfo:nil repeats:YES];
[timerObject fire];
[self.progressBar setMinValue:progressMinValue];
[self.progressBar setMaxValue:progressMaxValue];
[self.progressBar setDoubleValue:progressValue];
- (void)incrementProgressBar {
// Increment the progress bar value by 1
[self.progressBar incrementBy:1.0];
progressValue--;
[self.progressBar setDoubleValue:progressValue];
}

Related

Can I get an Checkbox to visually change its state before sending its action?

I have an OS X app with two checkboxes (NSButton). If the first(primary) is unchecked, it disables and unchecks the second one.
Here is the code for that functionality,
#IBAction func peopleCheckboxAction(sender: AnyObject) {
if(self.peopleCheckbox.state == NSOffState){
self.peopleCommentsCheckbox.enabled = false
self.peopleCommentsCheckbox.state = NSOffState
}else{
self.peopleCommentsCheckbox.enabled = true}
}
But here's the thing: that code gets executed before the first checkbox's state is changed, and it create a two-step action that feels almost like the first box is being unresponsive, or perhaps the user has clicked the wrong button, since the second control changes first. It's only a beat off, but I'd like to fix it.
Is there a simple way to reverse the way these two things are executed, or to ensure that they're happening nearly simultaneously?
Try this:
[self.peopleCheckBox sendActionOn:NSLeftMouseDownMask];
(The default behavior is the action is sent on mouse up.)
You could see what kind of effect you get with bindings - which would mean doing away with the action method altogether.
You'd normally set it all up in Interface Builder (IB), but copying and pasting the code below will quickly let you see if this approach is responsive enough for your needs. If it is, you should probably make the effort to set it all up in IB, leaving you with just the peopleState property in code.
#import "AppDelegate.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSButton *peopleCheckBox;
#property (weak) IBOutlet NSButton *commentCheckBox;
#property NSNumber *peopleState;
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Each time you click on the peopleState checkbox,
// the value of the property <peopleState> will change.
[self.peopleCheckBox bind:#"value"
toObject:self
withKeyPath:#"peopleState"
options:nil];
// Each time the value of the property <peopleState> changes,
// the 'enabled' status of the commentCheckBox is updated
// peopleState == NSOffState -> commentCheckBox disabled.
[self.commentCheckBox bind:#"enabled"
toObject:self
withKeyPath:#"peopleState"
options:nil];
}
#end

Removing the text from the automated back button on a navigation controller

I'm sure this was covered before but I can't find exactly what I'm after. I'm using a custom image for the back button on my navigation controller and need to remove the text, is there a simple way of doing this? Thanks.
Try to set the back button as follows:
self.navigationItem.leftBarButtonItem =
[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"back-arrow.png"]
style:UIBarButtonItemStyleBordered
target:self
action:#selector(backButtonPressed:)];
self.navigationItem.leftBarButtonItem.title = #"";

How to use NSTimer with data from NSURL pass to NSXMLParser display in TableView

How to use NSTimer with data from NSURL pass to NSXMLParser display in TableView
I have application display data from web server by PHP gen' to XML
In my xcode i use NSURL for connect to PHP file (in web server)
and use NSXMLParser to read XML data put value to array
and final display on TableView
I want to see data in TableView live update or update every x time
I think i can use NSTimer but i don't know how i can
where i can put NSTimer to the code in xcode
In short, something like:
// Schedule a timer repeating every 2 seconds
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self.tableView
selector:#selector(reloadData)
userInfo:nil
repeats:YES];
Longer version:
You need to call -doParse from a timer, fetch data, do parsing, and reload the data.
In order not to block main thread, you must NOT call [[NSXMLParser alloc] initWithContentsOfURL:theURL] from main thread.
Instead:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithContentsOfURL:theURL];
...
// finish parsing
dispatch_async(dispatch_get_main_queue(), ^{
[tableView reloadData];
});
});
And call -doParse with a NSTimer from -viewDidLoad :
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:#selector(doParse)
userInfo:nil
repeats:YES];
Further reading:
WWDC 2012 Session 211 - Building Concurrent User Interfaces on iOS.

How to stop the animation on a determinate NSProgressIndicator?

NSProgressIndicator allows stopAnimation: when isIndeterminate == YES, but how does one stop the animation for determinate progress bars?
For context, the progress bar I am trying to do this with is a child of an NSView, which itself is the view property of an NSMenuItem. Sending ridiculously high numbers to setAnimationDelay: does what I want, but only temporarily -- when the parent menu is closed and re-opened, the progress bar is animated again.
(Possibly unnecessary disclaimer: I swear this is a legit use case; I have to be able to visually (i.e.: without using text) display the progress of very-long-running tasks which may pause and re-start as needed by the backend. Answers which boil down to "UI design: ur doin it rong" will be not be accepted unless accompanied by a brilliant alternative suggestion. ;) )
Subclass NSProgressIndicator like this, it also works with Lion:
#interface UnanimatedProgressIndicator : NSProgressIndicator {
#private
BOOL isAnimating;
}
#end
#interface NSProgressIndicator (HeartBeat)
- (void) heartBeat:(id)sender; // Apple internal method for the animation
#end
#implementation UnanimatedProgressIndicator
- (void) startAnimation:(id)sender
{
isAnimating = YES;
[super startAnimation:sender];
}
- (void) stopAnimation:(id)sender
{
isAnimating = NO;
[super stopAnimation:sender];
}
- (void) heartBeat:(id)sender
{
if (isAnimating)
[super heartBeat:sender];
}
#end
Solved the problem using the same approach as described previously, with one small change.
When the menu's delegate receives menuNeedsUpdate:, I send setAnimationDelay: (with the sufficiently huge number as the arg) to each progress bar. This is working reliably now, so I'm happy enough with it.

NSTimer no effect...?

I tried to call [self setNeedsDisplay:YES] in a NSTimer selector in order to trigger the drawRect method.
At first, I put the NSTimer init code in a button func:
-(IBAction)buttonPush:(id)sender
{
myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(myTimerAction:)
userInfo:nil
repeats:YES];
}
-(void)myTimerAction:(NSTimer *) timer
{
[self setNeedsDisplay:YES];
}
The "setNeedsDisplay" is called normally but the code inside the drawRect is never called:
- (void)drawRect:(NSRect)dirtyRect
{
NSLog(#"drawRect");
}
Then I tried to move the NSTimer init code to "- (id)initWithFrame:(NSRect)frame", then everything works just fine.
(the drawRect is called correctly every 1 sec).
What's the difference between the two methods above?
What should I do if I want to trigger the Timer in a button?
Just wondering, in what class does that code reside? I would assume the buttonPush: action is inside a controller, correct?
If so, then you should have:
-(void)myTimerAction:(NSTimer *) timer
{
[[self view] setNeedsDisplay:YES];
}
because setNeedsDisplay: is a method of NSView, not NSViewController.
(BTW probably the reason why it works if you put it inside initWithFrame: is because that one is a NSView initializer: I'm guessing that when you move the code there you are also moving the myTimerAction: method, which then has "self" referring correctly to the view.)
Since it works when you use initWithFrame:, the problem is probably that buttonPush: isn't hooked up correctly. Try setting a breakpoint in buttonPush: an see if it is actually called when you click the button.

Resources