Make JavaFX Button visually appear to be clicked on right click - swing

I converted some old Java Swing code to JavaFX. The JavaFX code had explicit doClick() for the right mouse button calls:
myButton.addMouseListener(new MouseAdapter() {
#Override
public final void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
// ...
}
else if (SwingUtilities.isRightMouseButton(e)) {
// ...
myButton.doClick();
}
}
});
Left clicks make the button visually appear to be clicked in Java Swing. However right clicks do not visually do this without adding myButton.doClick()
I am seeing the same visual behavior in JavaFX and I want right clicks to visually make the button look clicked. Below is my JavaFX code:
myButton.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(final MouseEvent event) {
if (event.getButton() == MouseButton.PRIMARY) {
// ...
}
else if (event.getButton() == MouseButton.SECONDARY) {
// ...
}
}
});
What do I have to add to make right clicks visually click myButton?

That visual appearance of button click is usually referred as "armed" pseudo state. So you can turn on/off the armed pseudo state of the button when doing right button pressed&released.
Something like..
myButton.setOnMousePressed(e->{
if(e.getButton()== MouseButton.SECONDARY){
myButton.pseudoClassStateChanged(PseudoClass.getPseudoClass("armed"), true);
}
});
myButton.setOnMouseReleased(e->{
if(e.getButton()== MouseButton.SECONDARY){
myButton.pseudoClassStateChanged(PseudoClass.getPseudoClass("armed"), false);
}
});

Updating the :armed pseudo class is not enough if you want the Button's action to be fired by a right click. You actually need to arm the Button. In other words, you need to make the armed property change to true. Also, updating the armed property will update the pseudo class for you.
As the armed property is read-only, you can't set it directly; you need to call arm() and disarm(). You may also need to manually call fire() (expanded on below). Here's an example:
Button button = new Button("Click Me!");
button.setOnAction(event -> System.out.println("Button clicked!"));
button.setOnMousePressed(event -> {
if (event.getButton() == MouseButton.SECONDARY) {
button.arm();
}
});
button.setOnMouseReleased(event -> {
if (button.isArmed()) {
button.disarm();
button.fire();
}
});
However, you don't appear to need the onMouseReleased handler at all—at least in JavaFX 11 and 12, using the default Button's skin/behavior. The Button's behavior class will fire the action if said Button is armed at the time the mouse is released (and no keys are down). Note that the default behavior class does a more complex check regarding which MouseButton was used (i.e. it does more then just check event.getButton() == MouseButton.PRIMARY). You can see the implementation for yourself here.
All that said, if you only want the visuals to change then you should use the approach shown in Sai's answer.

Related

Angular 6+ HostListener on numeric input side arrows selector?

I am facing an issue where I have a directive sitting on an input type=number, those with side arrows for selecting numbers up and down.
I am using HostListener but I can't find a way to target the specific event when the user clicks on the side arrows.
So far I have tried:
#HostListener(change'): does not work at all
#HostListener('ngModelChange'): cause an infinite loop when the user uses the keyboard after
#HostListener('click'): It's the only one the works but the event does not contain the input value as it is a generic click event.
#HostListener('input'): Only works when the users input a number using the keyboard
Does anyone know the official way of getting this event?
#HostListener('input', ['$event'])
onEvent(event) {
this._propagateTouch();
this._propagateChange(event.target.value);
// console.log('input');
}
#HostListener('click', ['$event'])
onChange(event) {
this._propagateTouch();
this._propagateChange(event);
console.log('arrow change');
}
#HostListener('keydown', ['$event'])
handleKeyboardEvent(event) {
this._propagateTouch();
this._propagateChange(event.target.value);
}
Angular executes provided /configured method for HostListener when the element emits the configured event. There are two events change and input available for input
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number
For input when user click on side up or down arrow event get fired for #HostListener("input", ["$event"]). Demo
#HostListener("input", ["$event"])
public onInput(event: any): void {
console.log("input:"+ event);
alert(event);
}
#HostListener("input", ["$event.target"])
public onInput(event: any): void {
console.log("input:"+ event);
alert(event);
}

InputPane does not work correctly

I'm currently developing an Universal Application, but here is a problem. I have a Frame with the TextBox for User Phone Number.
So, I want to change the height of my LayoutRoot (GRID) so it can fits in the free space.
I'm using InputPane.GetForCurrentView().Showing and InputPane.GetForCurrentView().Hiding for that purposes.
Here is my code.
public UserRegistrationAuthorization_PhoneNumber()
{
this.InitializeComponent();
LayoutRootInitialHeight = LayoutRoot.ActualHeight;
InputPane.GetForCurrentView().Showing += UserRegistrationAuthorization_PhoneNumber_Showing;
InputPane.GetForCurrentView().Hiding += UserRegistrationAuthorization_PhoneNumber_Hiding;
}
private void UserRegistrationAuthorization_PhoneNumber_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
LayoutRoot.Height = LayoutRoot.ActualHeight - args.OccludedRect.Height;
LayoutRoot.VerticalAlignment = VerticalAlignment.Top;
args.EnsuredFocusedElementInView = true;
}
private void UserRegistrationAuthorization_PhoneNumber_Hiding(InputPane sender, InputPaneVisibilityEventArgs args)
{
// TODO: Get rid of that shit
LayoutRoot.Height = LayoutRootInitialHeight;
args.EnsuredFocusedElementInView = false;
}
When I click outside the TextBox keyboard hides and leaves after that a black hole on the screen. 2
But, the most interesting is that when I press that physical Back Button on my Lumia, keyboard hides normally and my LayoutRoot gets the Frame's initial height.
Is it a bug or I'm doing something wrong?
It happens because by the time you saving your LayoutRootInitialHeight in the constructor, LayoutRoot actually isn't loaded and it's ActualHeight == 0. Then you setting LayoutRoot.Height to 0, so it becomes not visible. So you should probably save your LayoutRootInitialHeight in LayoutRoot's Loaded event handler.
I would also suggest you not to change LayoutRoot's height at all. It causes your whole visual tree to be rendered from scratch and it's bad practise in general. Instead, modify RenderTransform of all necessary elements so they get moved to appropriate positions. RenderTransform is the right way to handle movements and animations on the screen, and you can achieve some nice visual effects with Next button moving up same as keyboard.
Roughly your code can look like this:
<Button Content="Next" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center">
<Button.RenderTransform>
<CompositeTransform x:Name="NextButtonTransform" TranslateY="0"/>
</Button.RenderTransform>
</Button>
...
private void UserRegistrationAuthorization_PhoneNumber_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
NextButtonTransform.TranslateY = -300;
EnsuredFocusedElementInView = true;
}
private void UserRegistrationAuthorization_PhoneNumber_Hiding(InputPane sender, InputPaneVisibilityEventArgs args)
{
NextButtonTransform.TranslateY = 0;
args.EnsuredFocusedElementInView = false;
}
And more complicated way is to run some storyboard which makes your Next button move up and down in same speed with keyboard, always appearing on top of it. Although, since InputPane.GetForCurrentView().Showing gets fired after keyboard already shown fully, you should hook up all animations to TextBox.GotFocus and TextBox.LostFocus events. On mobile, keyboard is always shown when text box has focus, so it will work nicely.

How do I remove focus from a button, so that pushing the spacebar or Enter doesn't trigger the button?

When you click or tap a button, it gives it focus, so that when you push the spacebar or Enter, it triggers the button again. I don't want that to happen.
I tried this: button1.Focus(Windows.UI.Xaml.FocusState.Unfocused);
But the unwanted behavior still happens (pushing the spacebar or Enter triggers the button again). I also tried setting focus to another button using the Programmatic and Keyboard FocusStates but that doesn't fix it either.
Any help, especially an explanation of why this is happening, would be greatly appreciated.
You can set the TabStop property to False, but be aware that doing this disallows user from using the button by keyboard.
<Button Content="Click Me By Pointer!" IsTabStop="False"/>
Update
As msdn states:
You can't remove focus from a control by calling this method with FocusState.Unfocused as the parameter. This value is not allowed and causes an exception. To remove focus from a control, set focus to a different control.
So another way to achieve this, is setting focus to previously focused element when the button is about to get focus by pointer. Unfortunatly the GettingFocus event is not working for the Button class (maybe because final version is not released yet?) so we should use GotFocus event, it's ugly it but works.
bool moveFocus = false;
public MainPage() {
this.InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
if (moveFocus) {
UIElement focusedElement = FocusManager.FindNextFocusableElement(FocusNavigationDirection.Right);
if (focusedElement is Control) {
((Control)focusedElement).Focus(FocusState.Programmatic);
}
}
}
private void Button_GotFocus(object sender, RoutedEventArgs e) {
Button button = (Button)sender;
moveFocus = (button.FocusState == FocusState.Pointer);
}
Note that I passed FocusNavigationDirection.Right to FocusManager.FindNextFocusableElement to get an element in right, I should have used FocusNavigationDirection.Previous instead to get previous element but it returns null for unknown reason.

How to add a JPopupMenu to a JMenuBar?

I have an application with a popup menu. I'd like to use the popup in the usual way (i.e., it should appear when the user right-clicks anywhere in the window), but I'd also like to attach it to the main MenuBar at the top of the window. I'm not sure how to do this.
I'd thought it would as simple as calling
myJMenuBar.add(myPopupMenu)
but this doesn't work.
JMenuBar.add() wants a JMenu parameter, not a JPopupMenu.
Does anyone have any suggestions?
Instead of trying to reuse the JPopupMenu object, the best approach would be to encapsulate the actions that the menus perform, and reuse those. The popup would trigger those actions, as would the menu items.
From the Action JavaDoc:
In addition to the actionPerformed method defined by the ActionListener interface, this interface allows the application to define, in a single place:
One or more text strings that describe the function. These strings can be used, for example, to display the flyover text for a button or to set the text in a menu item.
One or more icons that depict the function. These icons can be used for the images in a menu control, or for composite entries in a more sophisticated user interface.
The enabled/disabled state of the functionality. Instead of having to separately disable the menu item and the toolbar button, the application can disable the function that implements this interface. All components which are registered as listeners for the state change then know to disable event generation for that item and to modify the display accordingly.
and
JPopupMenu, JToolBar and JMenu all provide convenience methods for creating a component and setting the Action on the corresponding component. Refer to each of these classes for more information.
I had the same issue. A right-mouse-click as well as a top menu with exactly the same (complicated) set of menu items. The 'Action' class is something to consider if you are talking about enablement choices, but it's not dealing with visibility and in my case there was also a dynamic list of entries based on a current selection that I wanted to reuse.
So I ended up implementing a 'Bridge' design pattern (I think) for the methods I actually use (add() and addSeparator()):
public static class MenuBridge
{
private JPopupMenu popupMenu;
private JMenu menu;
public MenuBridge(JPopupMenu popupMenu)
{
this.popupMenu = popupMenu;
}
public MenuBridge(JMenu menu)
{
this.menu = menu;
}
public void addSeparator()
{
if(popupMenu!=null) popupMenu.addSeparator();
else menu.addSeparator();
}
public void add(JMenuItem item)
{
if(popupMenu!=null) popupMenu.add(item);
else menu.add(item);
}
}
So then I can write a reusable method that computes the menu items and synchronize my right mouse click with the top-level menu:
public void addTaskMenuItems(DefaultMenu menu, List<MDProcTask> taskList)
{
...
menu.add()/menu.addSeparator()
...
}
addTaskMenuItems(new DefaultMenu(popupMenu),taskList);
...
taskMenu.addMenuListener( new MenuListener() {
public void menuCanceled(MenuEvent menuevent)
{
}
public void menuDeselected(MenuEvent menuevent)
{
}
public void menuSelected(MenuEvent menuevent)
{
taskMenu.removeAll();
addTaskMenuItems( new DefaultMenu(taskMenu),getSelectedTasks());
taskMenu.revalidate();
}});

html body gwt click event

html file has two textbox and one button.
but i need to generate click event when i only click outside of the two textboxes and button
element.how can i do that.
RootPanel.get().addEventListener or something like that?? help.
Typing anywhere in the browser window will trigger alert pop-up:
Event.addNativePreviewHandler(new Event.NativePreviewHandler() {
#Override
public void onPreviewNativeEvent(NativePreviewEvent event) {
NativeEvent ne = event.getNativeEvent();
if (KeyDownEvent.getType().getName().equals(ne.getType())) {
Window.alert("who fired me last?"
+ event.getNativeEvent().getCurrentEventTarget()
+ "\nevent target:" + event.getNativeEvent().getEventTarget());
}
}
});
I don't know, if RootPanel.get().addEventListener works, but you can add another panel, which contains the three elements. To the new panel you can add an listener.