Cocoa performClick on button waiting for next external event - objective-c

I have NSAlert instance which i run as modal for user confirmation on cancelling some operation. When user doesn't respond and the operations gets completed , i need to close this modal window. So, for this i'm calling performClick on default button in alert. But i observe that the perform click doesnt get executed instantly but waits for some external event such as mouse move event. Why is this happening? Apart from posting fake event, what are the other solutions?

Here is what you need to do.
Assumption:
1. IBAction is connect to NSButton Which will display the Alert View after clicking upon it.
2. It will perform Click operation by itself on the Second button of the Alert View.
Hope the below code will help you....
- (IBAction)showAlert:(id)sender
{
//display the alert
self.myAlert = [NSAlert alertWithMessageText:#"Sample Test" defaultButton:#"OK" alternateButton:#"DO Nothing" otherButton:#"CANCEL" informativeTextWithFormat:#"TEST",nil];
[self.myAlert beginSheetModalForWindow:[self window]
modalDelegate:self
didEndSelector:#selector(errorAlertDidEnd:returnCode:contextInfo:)
contextInfo:nil];
NSArray *buttonArray = [self.myAlert buttons];
NSLog(#"Button Arrays %#",buttonArray);
//Close by itself without a mouse click by the user
//Assuming the Default Button as the Second one "Do Nothing
NSButton *myBtn = [buttonArray objectAtIndex:2];
[myBtn performClick:self.myAlert];
}
- (void)errorAlertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
NSLog(#"TEST");
}

To know which button is clicked you can modify the mTo know which button is clicked you can modify the method errorAltertDidEnd
- (void)errorAlertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
if(returnCode == NSAlertAlternateReturn)
{
NSLog(#"TEST Alternate %ld",returnCode);
}
if(returnCode == NSAlertDefaultReturn)
{
NSLog(#"TEST Default %ld",returnCode);
}
if(returnCode == NSAlertOtherReturn)
{
NSLog(#"Test Other %ld",returnCode);
}
}
Could you please elaborate on this "But the click event(generated from performClick) itself waits for some external event(example: mouse move) –"

Related

Transient NSPopover swallows first click on parent window control

I have a transient NSPopover and when it's open and I click a button in the parent window the popover is dismissed instead and the click "swallowed". Only the second click on the button triggers the action properly.
Is there a way to pass the first click through to the control directly and dismiss the popover in one step?
NSPopover does seem to swallow the event for the targeted position view. Other views are fine. My solution is to get the delegate to forward the last mouse down event to the target view if hit testing reveals it was the clicked view. Unfortunatety NSApp -currentEvent is nil when the delegate gets messaged - not sure why. So I added an event monitor to the app delegate like so:
- (void)addEventMonitor
{
if (self.eventMonitor) {
return;
}
self.eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:(NSLeftMouseDownMask) handler:^(NSEvent *incomingEvent) {
NSEvent *result = incomingEvent;
self.monitoredEvent = result;
return result;
}];
}
When the delegate closes it checks to see it the last monitored event was in the target:
- (void)popoverDidClose:(NSNotification *)notification
{
// [NSApp currentEvent] is nil here
NSEvent *event = [(BPApplicationDelegate *)[NSApp delegate] monitoredEvent];
if (event && (event.type & NSLeftMouseDown)) {
NSPoint pt = [self.targetView.superview convertPoint:event.locationInWindow fromView:nil];
if ([self.TargetView hitTest:pt]) {
[NSApp postEvent:event atStart:NO];
}
}
}

How to end a button process and proceed with a button process using multiple button UIAlertView

As the title says,
I am having trouble using if statements for multiple UIAlertViews. I want my program to press a button but before initiating what the button will do a confirmation box will pop up saying would you like to proceed with a YES or NO. NO should cancel the initiation and YES should just proceed.
Please help!!
Set delegate to alertView as well as tag
yourAlertView.delegate = self;
yourAlertView.tag = 108;
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag==108)
{
switch (buttonIndex) {
case 0:
break;
case 1:
//Your actions
break;
default:
break;
}
}
}
You can differentiate alertView with tags. Cancel button index is always 0

Open alert box (NASlert) with a delegate and block all other windows?

Is there a way to open a NSAlert window, set a delegate for didEnd callback and while the alert is shown, all other windows should be "disabled" (can the window itself but not push any button or change any text)?
In your NSAlert code add
NSModalSession session = [NSApp beginModalSessionForWindow:theWindow];
[NSApp runModalSession:session];
// NSAlert stuff here ...
In your didEnd callback add
[NSApp endModalSession:session];
For more information about modal windows read NSApplication's "Managing the Event Loop" section.
Update:
Here is a sample code from Apple's doc showing how to run modal without callbacks.
NSModalSession session = [NSApp beginModalSessionForWindow:theWindow];
for (;;) {
if ([NSApp runModalSession:session] != NSRunContinuesResponse)
break;
[self doSomeWork];
}
[NSApp endModalSession:session];

Cocoa AppKit - Dismissing a modal window (i.e. popup or contextual menu) and pressing the button currently hovered above

Basically I want to create the effect of that provided in the system's menu bar. A user presses on one of the menu headings, and as he moves across the different headings, the menus open up automatically.
The snag is that if I open a pop-up menu for a button, the user has to click again to dismiss it. The entire runloop is on hold as I believe the pop-up menu is modal. How do I go about being able to send a [somePopUpMenu cancelTracking] when the user moves to the next button?
Here's code I'm currently trying out in my NSWindow subclass. The point is that once the mouse exits a button, the mouse is automatically clicked (leftdown/leftup) on the next button, the timer is invalidated and the popup menu is cancelled.
Assuming a popup menu is open and the mouse exists, the leftdown/leftup events are fired (I know this works as I log them in NSLog's for mouseDown and mouseUp), the timer is invalidated, but the pop up menu is still showing, and the other button "clicked" on by the fake events doesn't show anything. Also, the whole thing gets into a loop and there's frantic mouseDown/mouseUp being sent for some reason.
Worth noting the the popup menu is created in another object, though the hookToMenu has a proper reference to it (I confirmed via debug/stepping through).
Dunno if I'm borking the event tracking timer or doing it the wrong way. I did try it via a window controller as well but got the same results.
Any help on this would be appreciated.
-(void)stopTimer
{
[timer invalidate];
[hookToMenu cancelTracking]; //hookToMenu is NSMenu*
}
-startFireDateTimer
{
NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
timer = [[NSTimer alloc] initWithFireDate:nil interval:0 target:self selector:#selector(targetMethod) userInfo:nil repeats:YES];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSEventTrackingRunLoopMode];
[timer release];
}
-(void)targetMethod
{
NSEvent *newEvent;
newEvent=[NSApp nextEventMatchingMask:NSMouseExitedMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:NO];
if ([newEvent type]==NSMouseExited)
{
NSPoint mouseLoc;
mouseLoc=[newEvent locationInWindow];
int type=NSLeftMouseDown;
int type2=NSLeftMouseUp;
int windowNumber=[self windowNumber];
id fakeMouseUpEvent=[NSEvent mouseEventWithType:type
location:mouseLoc
modifierFlags:nil
timestamp:[NSDate timeIntervalSinceReferenceDate]
windowNumber:windowNumber
context:nil
eventNumber:nil
clickCount:1
pressure:1];
id fakeMouseUpEvent2=[NSEvent mouseEventWithType:type2
location:mouseLoc
modifierFlags:nil
timestamp:[NSDate timeIntervalSinceReferenceDate]
windowNumber:windowNumber
context:nil
eventNumber:nil
clickCount:1
pressure:1];
[NSApp sendEvent:fakeMouseUpEvent];
[NSApp sendEvent:fakeMouseUpEvent2];
[self stopTimer];
}
}
-(void)mouseDown:(NSEvent *)theEvent
{
[self startFireDateTimer];
NSLog(#"WINDOW: mouse down in window!");
[super mouseDown:theEvent];
}
-(void)mouseUp:(NSEvent *)theEvent
{
NSLog(#"WINDOW: mouse up in window!");
[super mouseUp:theEvent];
}
How do I go about being able to send a [somePopUpMenu cancelTracking] when the user moves to the next button?
Do exactly that. NSMenu responds to a cancelTracking message since Mac OS X 10.5.

prevent UIAlertView from dismissing

As a form of validation, is there any way to prevent an alert view from dismissing when pressing an "OK" button?
Scenario: I have 2 text fields in the alertview for username/password. If both are empty and the user presses "OK", I do not want the alert to be dismissed.
iOS 5 introduces a new property to UIAlertView to handle exactly this problem.
alert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
Apple documentation on UIAlertView.
Add the new UIAlertViewDelegate method to handle the enabling/disabling of the button.
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
Apple documentation on UIAlertViewDelegate.
You’re doing it the wrong way, you should enable and disable the submit button according to the input. First you have to get access to the button. This is easy, just create the alert without buttons, create a standalone button and add it to the dialog:
[alert addButtonWithTitle:#"OK"];
UIButton *submitButton = [[alert subviews] lastObject];
[submitButton setEnabled:…];
And then you have to set a delegate for those textfields and enable or disable the button when the fields change:
- (BOOL) textField: (UITextField*) textField
shouldChangeCharactersInRange: (NSRange) range
replacementString: (NSString*) string
{
int textLength = [textField.text length];
int replacementLength = [string length];
BOOL hasCharacters = (replacementLength > 0) || (textLength > 1);
[self setButtonsAreEnabled:hasCharacters];
}
// Disable the ‘Return’ key on keyboard.
- (BOOL) textFieldShouldReturn: (UITextField*) textField
{
return NO;
}
Of course you should wrap all this into a separate class so that you don’t mess up your calling code.
I don't believe you actually need to pass in any button names. Just take out your OK button string and leave it as "nil".