In a C++/winrt app I am able to handle a click in a stackpanel and respond by changing the background of the panel. But if I call the same method from the KeyDown event handler for the main page the appearance of the panel does not change. Both calls to the panel's background change are happening on one of the SHCore.dll threads, and I wonder why they are not on the "Main Thread." Using the dispatcher as follows still leaves me on the SHCore thread:
Window::Current().Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, [this, theKey,&handled]
{
handled = PressLetterKey(theKey);
});
As there is no visible effect from triggering the change within the keydown handler I begin to wonder if this is a thread issue. Yet the thread does appear to the same one in both the functional and the non-functional cases, and both the clickhandler and the keydown handler are calling the same method on the stackpanel - Could the thread here be the problem, or is there some other reason why the panel does not show its change in appearance when triggered by a keydown?
The triggering doesn't have to be a keydown, of course - I'm really just asking if the stackpanel's appearance can be toggled programmatically...for instance if one wanted to blink a button.
OK, once again I've just made a dumb error, but what can be salvaged here is an answer to the threading question. Yes, the SHCore thread is the UIThread, at least here. The "Main Thread" is something else. Any click event or keydown event arrives on the UI thread ready for action, there's no need to call dispatcher. In my case, I was triggering changes in one of a large series of stack panels and - the one I thought I was triggering was actually not the correct one; the triggered item was simply offscreen... so there you have it!
Related
I have the follwing declaration:
<Button Tapped="Handler1" DoubleTapped="Handler2" />
Each time I double tap the button the Handler1 gets fired. Handler 2 never gets fired.
Thanks.
You can't do in this way because it will always fire the first event of tap. You can manage the double tap with the single tap event using a boolean or a counter to manage the following tap events.
I do not know why the DoubleTapped handler does not get called. It should. Maybe IsDoubleTapEnabled is set to false? This could not just happen by explicitly setting the property in XAML, but also e.g. by inheriting the value from a style.
But even when DoubleTapped works, the Tapped event will always fire once. The control is no fortune teller: When the first tap happens, it does not know that a second tap will soon follow, so it fires the Tapped event. If you do not want this, you need to implement your own behaviour and either ignore or delay Tapped events.
MSDN:
If a user interaction also fires DoubleTapped, Tapped will fire first to represent the first tap, but the second tap won't fire an additional Tapped. If you want different logic for Tapped versus DoubleTapped, your Tapped handler may need to use app-specific variables and a timer in order to avoid running on interactions that are eventually interpreted as a DoubleTap action.
But using double taps is generally discouraged by the UX guidelines. I would not use them with buttons, because buttons usually do not work that way and you are breaking user expectations.
I have a transparent NSWindow that follows the user's screen everywhere he goes (the NSWindowstays in front of every app, no matter what, even fullscreen apps).
In that NSWindow i have a mouseDown event that shows a popup. Let's say i'm on safari in fullscreen mode and i have my Window in front of it, i click on safari and i click again on my Window: nothing happens, the mouseDown doesn't occur. I have to click again so the mouseDown event is triggered.
How can i force my NSWindow to be always active so i don't have to click it 2x to trigger the mouseDown when i click on a background app and click in my window again?
Thank you!
I'm not sure if this is exactly what you want (it's not quite a window wide setting), but, from the documentation:
By default, a mouse-down event in a window that isn’t the key window
simply brings the window forward and makes it key; the event isn’t
sent to the NSView object over which the mouse click occurs. The
NSView can claim an initial mouse-down event, however, by overriding
acceptsFirstMouse: to return YES.
The argument of this method is the
mouse-down event that occurred in the non-key window, which the view
object can examine to determine whether it wants to receive the mouse
event and potentially become first responder. You want the default
behavior of this method in, for example, a control that affects the
selected object in a window.
However, in certain cases it’s
appropriate to override this behavior, such as for controls that
should receive mouseDown: messages even when the window is inactive.
Examples of controls that support this click-through behavior are the
title-bar buttons of a window.
Or you could try fiddling with
- (void)sendEvent:(NSEvent *)theEvent
and see if you can handle events in a custom way.
If you add a borderless NSButton instance to your window's view and set your image as the button's image (and as its alternate image, to make it more beautiful), it will work out of the box: Just connect the button's action method to your app delegate (or the object where you want to process the click action). A click on the image (i.e. the button) will then trigger the button's action method, no matter which window is active.
This worked for me, hope that will be helpful, This will keep your window always on Top of all applications
[self.window makeKeyAndOrderFront:nil];
[self.window setLevel:NSStatusWindowLevel];
I think what you really should do is use an NSPanel (a floating palette -- a special kind of NSWindow) that will do exactly what you want in a way that's consistent with the OS rather than trying to fight intended behavior.
Here's the NSPanel documentation:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nspanel_Class/Reference/Reference.html
And here's some helpful and pithy information:
http://cocoadev.com/wiki/NSPanel
By default, an NSPanel will disappear when the application is inactive, but you can turn this off.
I apologize for not laying it out more fully ... pressed for time.
Edit:
Note that you can probably get your window to behave as desired simply:
"The NSView can claim an initial mouse-down event, however, by overriding acceptsFirstMouse: to return YES."
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/HandlingMouseEvents.html
You'll need to do this with any NSView subclass to skip the "activation click".
I would like to simulate a mouse click on a Cocoa application without actually clicking the mouse, and* not have to figure out which view should respond to the click, given the current mouse location.
I would like the Cocoa framework to handle figuring out which view should respond, so I don't think that a method call on an NSView object is what I'm looking for. That is, I think I need a method call that will end up calling this method.
I currently have this working by clicking the mouse at a particular global location, using CGEventCreateMouseEvent and CGEventPost. However, this technique actually clicks the mouse. So this works, but I'm not completely happy with the behavior. For example, if I hold down a key on the keyboard while the CGEventPost is called, that key is wrapped into the event. Also, if I move another process's window over the window that I'd like to simulate the click, then the CGEventPost method will click the mouse in that window. That is, it's acting globally, across processes. I'd like a technique that works on a single window. Something on the NSWindow object maybe?
I read that "Mouse events are dispatched by an NSWindow object to the NSView object over which the event occurred" in the Cocoa documentation.
OK. So I'd like to know the method that is called to do the dispatching. Call this method on the window, and then let the framework figure out which NSView to call, given the current mouse location.
Any help would be greatly appreciated. I'm just starting to learn the Cocoa framework, so I apologize if any of the terminology/verbage here isn't quite right.
It's hard to know exactly how much fidelity you're looking for with what happens for an actual click. For example, do you want the click to activate the app? Do you want the click to bring a window to the top? To make it key or main? If the location is in the title bar, do you want it to potentially close, minimize, zoom, or move the window?
As John Caswell noted, if you pass an appropriately-constructed NSEvent to -[NSApplication sendEvent:] that will closely simulate the processing of a real event. In most cases, NSApplication will forward the event to the event's window and its -[NSWindow sendEvent:] method. If you want to avoid any chance of NSApplication doing something else, you could dispatch directly to the window's -sendEvent: method. But that may defeat some desirable behavior, depending on exactly what you desire.
What happens if the clicked window's or view's response is to run an internal event-tracking loop? It's going to be synchronous; that is, the code that calls -sendEvent: is not going to get control back until after that loop has completed and it might not complete if you aren't able to deliver subsequent events. In fact, such a loop is going to look for subsequent events via -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:], so if your synthetic events are not in the queue, they won't be seen. Therefore, an even better simulation of the handling of real events would probably require that you post events (mouse-down, mouse drags, mouse-up) to the queue using -[NSApplication postEvent:atStart:].
I think your first task is to really think deeply about what you're trying to accomplish, all the potential pitfalls and corner cases, and decide how you want to handle those.
With respect to the CGEvent... stuff, you can post an event to a specific process using CGEventPostToPSN() and that won't click on other app's windows, even if they are in front of the target window. However, it may still click on a different window within the target app.
OK. So I'd like to know the method that is called to do the dispatching. Call this method on the window, and then let the framework figure out which NSView to call, given the current mouse location.
NSView *target = [[theWindow contentView] hitTest:thePoint];
I'm not entirely clear on your problem so I don't know if all you want to do is then call mouseDown: on the target. But if you did, that would be almost exactly the same thing that happens for a real mouse click.
This is the message used in delivering live clicks. It walks the view hierarchy, automatically dealing with overlap, hidden messages, etc., and letting each step in the chain of views interfere if it wants. If a view wants to prevent child views from getting clicks, it does that by eating hitTest:, which means it'll affect your code the exact same way it affects a real click. If the click would be delivered, this method always tells you where it would be delivered.
However, it doesn't necessarily handle all the reasons a click might not be delivered (acceptsFirstMouse, modal dialogs, etc.). Also, you have to know the window, and the point (in the appropriate coordinate system), but it sounds like that's what you're starting with.
You can simulate mouse click by calling mouseDown: like this:
[self mouseDown: nil];
And to get mouse location in screen:
-(void)mouseDown:(NSEvent *)theEvent {
NSPoint mouseLocation = [NSEvent mouseLocation];
NSLog(#"x: %f", mouseLocation.x);
NSLog(#"y: %f", mouseLocation.y);
}
I am looking for an NSButton raising the click event on mouseup, even if the mouse down has been made outside the button.
Do you have any idea to get this behavior?
Thanks!
Moving the mouse outside a control before releasing the button allows the user to cancel the action.
I would think the only way to do that would be to intercept all events and handle all click tracking and movement tracking yourself.
However, it would result in a very unexpected interface behavior, so you should consider carefully why you need to do that.
Issue1:
I want to show an alert window or message box before the Main Window of the Application is launched. When im using the NSRunAlertPanel() it is not showing the alert window.It is directly launching the Application's Main Window.
Issue2:
I want to create an Modal (login dialog) and message boxes in an thread spanned from the main thread.
Its urgent
So, Kindly reply soon...
Thank You Pradeep.
Issue2: I want to create an Modal (login dialog) and message boxes in an thread spanned from the main thread.
In Cocoa, nearly all UI code must run on the main thread. There are a few limited, well-defined exceptions (e.g., the opt-in threaded drawing introduced in Snow Leopard), but the general rule is to not run UI code on another thread.
Besides, you don't need a thread anyway. It's not like the modal dialog is going to be computationally intensive.
Send NSApp a runModalForWindow: message, passing the dialog. This will run the dialog on the main thread, blocking the rest of your UI. If you don't want to block the UI (and you generally shouldn't), just make it key and order it front, like usual.
What you can do is:
uncheck the "Visible at launch" option for your main window in Interface Builder.
start your application as usual
decide whether or not to show the modal dialog
invoke "orderFront:" message of the main window.