I did a search and found all sorts of things on this forum about NSProgressIndicator, but alas nothing which helps me specifically. It seems like a popular topic though. Here's my problem. Up until today, my determinate bar indicator was working fine but all of a sudden, it just stopped animating after running smoothly the first time through. Here is my code
-(void) someMethod;
{
// Setup the progress indicator
double progressValue = 0.0;
[self.progressBar setBezeled:YES];
[self.progressBar setDoubleValue:progressValue];
[self.progressBar setMaxValue: (double) maxCount];
for(int i=0, i<=maxCount-1; i++)
{
///Lots of stuff in the loop
// Increment progressIndicator
progressValue +=1;
[self.progressBar setHidden:NO];
[self.progressBar setDoubleValue: progressValue];
NSLog(#"%f",[self.progressBar doubleValue]);
[self.progressBar displayIfNeeded];
}
[self.progressBar setHidden:YES];
}
Please note that I explicitly use setHidden:YES and setHidden:NO because I already couldn't get the displayWhenStopped to work correctly. When I check the actual value of progressBar.doubleValue in the log it does increment as it should to the incremented values. It really seems as if the displayIfNeeded method just stopped working all of a sudden. Like I said, it works correctly the first time through, then after that it displays the bar, increments once or twice, then gets stuck. The rest of the code and loop continue just fine and completes itself.
Does anyone have any ideas or clues?? I suspect it may have something to do with threads which I know nothing about. Any help would be great. Thanks in advance for any help!
Related
I have motor programmed with arduino, the hardware is already setup so i don't want to change the micro controller. I need to give the motor 1 second to move from each point to the other and if its too much stay until "one second" is done and then go the rest of the code.
the bellow code this is part of the whole code. it freezes and not working after about 40 hour. please advise how can i prevent that. I know that the mills() function is the problem but don't know whats the best option to replace or prevent that?
unsigned long firsttime = 0;
unsigned long secondtime = 0;
void loop(){
...
firsttime= millis();
myStepper.step(RNum);
secondtime = 1000-millis()+firsttime;
delay (secondtime);
...
}
Thanks
I will be very short:
I'am drawing lines using drawrect and NSBezierPath.
To draw these lines I am using a for loop.
Now, since the loop takes many seconds,I'm trying to use a NSProgresIndicator to show the progress and to update it within the loop I used dispatch_async & queue.. The ProgressIndicator updates but nothing is being drawn.. If don't use the queue the lines are drawn but the indicator updates at the end of the cycle.
What am I doing wrong ?
The error:
<Error>: CGContextRestoreGState: invalid context 0x0.
This is a serious error.
This application, or a library it uses, is using an invalid context
and is thereby
contributing to an overall degradation of system stability and reliability.
This notice is a courtesy: please fix this problem.
It will become a fatal error in an upcoming update.
// SAMPLE OF CODE
dispatch_queue_t myQueue = dispatch_queue_create("my queue", NULL);
dispatch_async(myQueue, ^
{
for (int i = 1; i <= 200; i++) {
dispatch_async(dispatch_get_main_queue(), ^{
[istance set_progress:i];
//This sets the progress, but bezierPath doesn't work
});
//Bezier already alloc & init
[my_path moveToPoint....]
[my_path lineToPoint....]
[my_path stroke]
}
});
In general you shouldn't be drawing on a background thread or queue.
Please read this document for information about multithreaded drawing. Skip to "Drawing Restrictions"
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html
I'm using a button to activate a timer. In that button's code, it turns on the timer. I'll attach the code, though I doubt it'll make sense out of context.
- (IBAction)btnStartWasClicked:(NSButton *)sender {
if ([btnStartTitle.title isEqualToString:#"Start"])
{
NSLog(#"Debug: Start button was clicked."); //Debug
//Changes the Start button to say Stop
[btnStartTitle setTitle:#"Stop"];
started = TRUE;
[self tick:nil];
NSLog(#"Debug: Timer has started."); //Debug
[btnReset setEnabled:FALSE];
[btnLap setEnabled:TRUE];
if (lapTimerIsPaused == TRUE)
{
lapTimerIsRunning = TRUE;
[self tickAfterLap:nil];
}
}
else
{
NSLog(#"Debug: Stop button was clicked."); //Debug
//Changes the Stop button to say Start
[btnStartTitle setTitle:#"Start"];
started = FALSE;
NSLog(#"Timer has been stopped."); //Debug
[btnReset setEnabled:TRUE];
lapTimerIsRunning = FALSE;
lapTimerIsPaused = TRUE;
[btnLap setEnabled:NO];
}
I currently have a nasty bug I'm not quite sure how to get rid of. If the user double-clicks the start button really quickly, it will either:
A) Do nothing, just change the start button to say stop.
B) Make the timer count twice as fast (if the double-click is REALLY quick.) THIS ONLY HAPPENS WHEN THE START BUTTON IS SET TO SAY STOP, NOT START.
My bug is B. I'm not quite sure how to squash it.
Edit: The lap timer is a different timer than the regular timer, and I don't think the bug I'm having affects it, so ignore the lap timer code.
Any ideas?
I'm writing an application that runs an algorithm, but allows you to 'step through' the algorithm by pressing a button - displaying what's happening at each step.
How do I listen for events while within a method?
eg, look at the code I've got.
static int proceed;
button1Event(GtkWidget *widget)
{
proceed = 0;
int i = 0;
for (i=0; i<15; i++) //this is our example 'algorithm'
{
while (proceed ==0) continue;
printf("the nunmber is %d\n", i);
proceed = 0;
}
}
button2Event(GtkWidget *widget)
{
proceed = 1;
}
This doesn't work because it's required to exit out of the button1 method before it can listen for button2 (or any other events).
I'm thinking something like in that while loop.
while(proceed == 0)
{
listen_for_button_click();
}
What method is that?
The "real" answer here (the one any experienced GTK+ programmer will give you) isn't one you will like perhaps: don't do this, your code is structured the wrong way.
The options include:
recommended: restructure the app to be event-driven instead; probably you need to keep track of your state (either a state machine or just a boolean flag) and ignore whichever button is not currently applicable.
you can run a recursive main loop, as in the other answer with gtk_main_iteration(); however this is quite dangerous because any UI event can happen in that loop, such as windows closing or other totally unrelated stuff. Not workable in most real apps of any size.
move the blocking logic to another thread and communicate via a GAsyncQueue or something along those lines (caution, this is hard-ish to get right and likely to be overkill).
I think you are going wrong here:
while(proceed == 0)
{
listen_for_button_click();
}
You don't want while loops like this; you just want the GTK+ main loop doing your blocking. When you get the button click, in the callback for it, then write whatever the code after this while loop would have been.
You could check for pending events & handle the events in while loop in the clicked callback. Something on these lines:
button1Event(GtkWidget *widget)
{
proceed = 0;
int i = 0;
for (i=0; i<15; i++) //this is our example 'algorithm'
{
while (proceed ==0)
{
/* Check for all pending events */
while(gtk_events_pending())
{
gtk_main_iteration(); /* Handle the events */
}
continue;
}
printf("the nunmber is %d\n", i);
proceed = 0;
}
}
This way when the events related click on the second button is added to the event queue to be handled, the check will see the events as pending and handle them & then proceed. This way your global value changes can be reflected & stepping should be possible.
Hope this helps!
If you want to do it like this, the only way that comes to my mind is to create a separate thread for your algorithm and use some synchronization methods to notify that thread from within button click handlers.
GTK+ (glib, to be more specific) has its own API for threads and synchronization. As far as I know Condition variables are a standard way to implement wait-notify logic.
I have a determinate progress indicator. It is working just like I would expect it to but it does not disappear after it reaches maxValue. I have set the progress indicator to not display when stopped in the main.nib file, I have also entered it into the awakeFromNib{} method.
I put a log at the end of the routine to make sure the [displayWhenStopped] setting was still set to NO and it is.
Here is my code :
-(void)getEvents:(NSURL *)mffFile{
NSMutableArray * eventTypeResults =[[NSMutableArray alloc]init];
EWaveformRecording *ptrToRcdFile = [EWaveformRecording openRecording:mffFile permission:readOnly user:nil convertFileFormat:NO openReadOnlyAnyway:NO];
NSArray *events = [ptrToRcdFile getEvents];
//get the size of events for the progressbar and instantiate a loop counter
NSInteger total = [events count];
int loop = 0;
//set progress bar params
[self->meter_ setUsesThreadedAnimation:YES];
[self->meter_ setControlSize:NSMiniControlSize];
[self->meter_ setMaxValue:(double)total];
for(EEvent* event in events){
loop ++;
if(![eventTypeResults containsObject:event.code]){
NSLog(#"check eventNames in getEvents %#", event.code);
[eventTypeResults addObject: event.code];
}//end if
//display loop increment in progress bar
[self->meter_ setDoubleValue:(1000*(double)loop)/1000];
}//end for
//send the eventTypesResults array to the EventExport class
[evtPtr setEventsAvailableList:eventTypeResults];
}
What I have tried:
with and without [setUsesThreadedAnimation] which I don't totally understand; it does slow down the progress bar which makes it look better but the docs say only indeterminate types should be effected by animation.
I have tried using [start & stop animation]
I have tried [setDisplayWhenStopped:NO] after my loop
Any help is greatly appreciated
MIke
This is what I learned.
I should not be allowing the progress bar to run on a different thread even though it looks like its working because the NSProgressIndicator can no longer respond to the settings in the main thread, so the proper thing to do is to not instantiate that method, however , that was not the solution to my problem; I was doing everything else right, but the main thread could not redraw the progress because it's busy with all the other calls in the UI. The solution was to implement NSRunLoop so that each iteration of the loop interrupts the main thread and redraws the progress meter , then returns control.