How to have a button focused when pressing 'Tab' button in javaFX? - css

This is the Image link of my fxml file...
In the above shown window of a simple form in javaFx when I press tab button it will go to ok button and next tab will shift to cancel button. However the focus as shown on the textfield is not transferred to the buttons.But when the mouse cursor is moved on them the hover effect works perfectly.
How to make these buttons focused/hovered with different colors when pressing the tab button (not by moving the mouse cursor on them)?
Thanks in anticipation.

You can set the colors for the buttons in a stylesheeet.
public class YourApp extends Application {
#Override
public void start(Stage primaryStage) {
TextField txt = new TextField("test");
Button btnOk = new Button("OK");
btnOk.setId("buttonOk");
Button btnCancel = new Button("Cancel");
btnCancel.setId("buttonCancel");
VBox box = new VBox(txt, btnOk, btnCancel);
Scene scene = new Scene(box);
scene.getStylesheets().add(getClass().getResource("yourApp.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
yourApp.css:
#buttonCancel:hover,
#buttonCancel:focused {
-fx-background-color: blue;
}
#buttonOk:hover,
#buttonOk:focused{
-fx-background-color: green;
}

Related

Javafx Popup can't get focus if other application gains focus

I use a JavaFX Popup in my application to change the Shipping Address of a customer. That often requires copy pasting the Address from the web browser. If I click on the Popup after the application lost focus it will not regain focus. I first need to click the parent window behind the popup and then click the Popup again to be able to interact with it.
Is there any way to solve that problem, besides using an undecorated stage instead of a Popup?
EDIT:
Here I made a minimal example:
public class HelloApplication extends Application {
#Override
public void start(Stage stage) throws IOException {
Scene scene = new Scene(new VBox(), 600, 600);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
Popup popup = new Popup();
Button btn = new Button("This is a very nice button!");
btn.setOnAction(actionEvent -> System.out.println("button clicked"));
TextField textField = new TextField();
textField.setOnMouseClicked(mouseEvent -> System.out.println("textField clicked"));
VBox popupVBox = new VBox(btn, textField);
popupVBox.setStyle("-fx-background-color: white");
popupVBox.setPadding(new Insets(10));
popup.getContent().add(popupVBox);
popup.show(scene.getWindow());
}
public static void main(String[] args) {
launch();
}
}
If you click outside of the application (for example the web browser, to copy some value) then you can not enter Text into the TextField anymore. The button action listener and even the TextField mouse Listener still work and output "button clicked" and "textField clicked" but the blue halo around them does not apppear and you can not enter (or paste) text into the TextField. After you click somewhere on the main Stage of the application it works again.
I tried adding textField.requestFocus();
to the mouse Listener of the textfield but that does not do anything.
EDIT 2 after the comment from kleopatra:
I tried adding the following code:
popupVBox.setOnMouseEntered(mouseEvent -> {
popup.getOwnerWindow().requestFocus();
parentVBox.toFront(); //This is created above and passed to the new Scene instead of diectly passing new VBox() as in the code snippet posted above
});
With that code added, popup and its children seem to have focus if the mouse is hoverd over it after an other application had focus, i.e. if clicked with the mouse the blue border appears around the button and textField, and if there is any text in the textField I can move the cursor with the mouse and select the text with the mouse, buy any keyboard inputs are ignored. Actually they are executed in the other application which had focus before. If I ctrl+c in Intellij and try to ctrl+v into the textfield it will be pasted to the Intellij editor. Also the arrow keys move the cursor in the intellij window instead of the textField.
The only way to be able to type anything in the TextField is to click the parent window first.
Also
textField.setOnMouseClicked(mouseEvent -> {
textField.requestFocus();
});
does not do anything
not an answer, just to clarify the comment (will delete if seen by OP :)
public class PopupFocus extends Application {
#Override
public void start(Stage stage) throws IOException {
Scene scene = new Scene(new VBox(), 300, 300);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.setX(10);
stage.show();
Popup popup = new Popup();
Button btn = new Button("This is a very nice button!");
btn.setOnAction(actionEvent -> System.out.println("button clicked"));
TextField textField = new TextField();
textField.setOnMouseClicked(mouseEvent -> {
System.out.println("textField clicked");
stage.toFront();
});
VBox popupVBox = new VBox(btn, textField);
popupVBox.setStyle("-fx-background-color: white");
popupVBox.setPadding(new Insets(10));
popup.getContent().add(popupVBox);
// original
popup.show(scene.getWindow());
}
public static void main(String[] args) {
launch();
}
}

JavaFX popup blocks first mousePress on the background

I have a popup on button press
When I press a button the popup shows up.
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
root.setPrefWidth(200);
root.setPrefHeight(200);
Button btn = new Button("Press");
root.getChildren().add(btn);
root.setOnMouseDragged(e-> System.out.println("draaaag"));
root.setOnMousePressed(e-> System.out.println("PRESSED"));
root.setOnMouseReleased(e-> System.out.println("RELEASED !!!!!!!!!!!!!!!"));
Scene scene = new Scene(root);
Popup popup = new Popup();
popup.getContent().add(new Label("POPUP"));
popup.setAutoHide(true);
popup.setAutoFix(true);
btn.setOnMouseClicked(ev -> {
popup.show(primaryStage);
});
primaryStage.setScene(scene);
primaryStage.show();
}
}
background have mouseDrag, mousePress and mouseRelease events.
When I open the popup and click the on the root, the popup hides as expected, but the root area notifies only mouseRelease and drag actions first, than all other actions act.
IWant to listen on mousePress on root even if the popup is showing...
I got the answer.
the event is consumed on auto hide
so
popup.setConsumeAutoHidingEvent(false)
It does the job.
Popup are managed as different window higher than the one you insert. Therefore you have to insert onMouseRelease event also to popup:
popup.getContent().get(0).setOnMouseReleased(e -> System.out.println("Popup clicked!"));
you can also add a styled Label with a different background to highlight the popup:
Label label = new Label("POPUP");
label.setStyle("-fx-background-color: grey;");
popup.getContent().add(label);
label.setOnMouseReleased(e -> System.out.println("Popup clicked!"));

Mnemonics - how to set color?

I have multiple buttons in in my javafx appliaction with mnemonics.
When I press "Alt" the mnemonics appear in a dark color but I want them to be white.
What is the right css selector for this?
I tried:
.mnemonic-underline: {
-fx-stroke: white;
}
But after that the underlines are visible all the time.
This should work:
:show-mnemonics > .mnemonic-underline {
-fx-stroke: white;
}
Example program:
public class MnemonicStylingSSCCE extends Application {
#Override
public void start(Stage stage) {
// Init label
final Label mnemonic = new Label("_Mnemonic");
mnemonic.setMnemonicParsing(true);
// Init scene
final Scene scene = new Scene(mnemonic);
scene.getStylesheets().add(MnemonicStylingSSCCE.class.getResource("mnemonic.css").toExternalForm());
stage.setScene(scene);
// Request focus & show
stage.requestFocus();
stage.show();
}
}
Side note - the content of mnemonic.css is CSS shown above (but with the red color instead of white).

How to disable right click on a menu in javafx

In javaFX code, a menu can popup by left click or right click. How to disable right click?
public void start(Stage primaryStage)
{
BorderPane root = new BorderPane();
MenuBar menuBar = new MenuBar();
Menu hello = new Menu("hello");
menuBar.getMenus().addAll(hello);
Menu world = new Menu("world");
menuBar.getMenus().addAll(world);
root.setCenter(menuBar);
MenuItem item = new MenuItem("laugh");
hello.getItems().add(item);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
When I right click the "hello" menu, it will popup menuitem "laugh".
The basic approach is to register a eventFilter on the MenuBar that consumes the events that should not be delivered to the children.
Doing so manually in your application code:
public class DisableRightClickOpenMenu extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
MenuBar menuBar = new MenuBar();
menuBar.addEventFilter(MouseEvent.MOUSE_PRESSED, ev -> {
if (ev.getButton() == MouseButton.SECONDARY) {
ev.consume();
}
});
Menu hello = new Menu("hello");
menuBar.getMenus().addAll(hello);
Menu world = new Menu("world");
menuBar.getMenus().addAll(world);
root.setCenter(menuBar);
MenuItem item = new MenuItem("laugh");
hello.getItems().add(item);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you want this behaviour across all your applications, you can implement a custom menuBarSkin that registers the filter and install the custom skin via a stylesheet.
The skin:
public class ExMenuBarSkin extends MenuBarSkin {
/**
* Instantiates a skin for the given MenuBar. Registers an
* event filter that consumes right mouse press.
*
* #param menuBar
*/
public ExMenuBarSkin(MenuBar menuBar) {
super(menuBar);
menuBar.addEventFilter(MouseEvent.MOUSE_PRESSED, ev -> {
if (ev.getButton() == MouseButton.SECONDARY) {
ev.consume();
}
});
}
}
In your stylesheet (replace with your fully qualified class name):
.menu-bar {
-fx-skin: "de.swingempire.fx.event.ExMenuBarSkin";
}
Its usage (replace the name with your stylesheet file name):
URL uri = getClass().getResource("contextskin.css");
primaryStage.getScene().getStylesheets().add(uri.toExternalForm());
This is usual behavior of menu in many programs. I don't think you can change it. However, you can use some other controls and simulate menu. (Like HBox and Labels).
I agree as far as I know there's no a standard way to do this, but you may want to consider the following workaround.
It is replacing the Menu node with a Menu object composed by an HBox and a Label: an EventHandler is added to the HBox and by checking the mouse button pressed we add/remove on the fly the MenuItem to its parent.
#Override
public void start(final Stage primaryStage) {
final BorderPane root = new BorderPane();
final MenuBar menuBar = new MenuBar();
final Menu menuHello = new Menu();
final Menu menuWorld = new Menu("world");
final MenuItem menuitem = new MenuItem("laugh");
final HBox hbox = new HBox();
menuBar.getMenus().addAll(menuHello, menuWorld);
root.setCenter(menuBar);
hbox.setPrefWidth(30);
hbox.getChildren().add(new Label("hello"));
menuHello.setGraphic(hbox);
menuHello.getItems().add(menuitem);
hbox.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(final MouseEvent e) {
if (e.getButton() == MouseButton.SECONDARY) {
System.out.println("Right click");
menuHello.getItems().remove(menuitem);
} else {
System.out.println("Left click");
if (!menuHello.getItems().contains(menuitem)) {
menuHello.getItems().add(menuitem);
menuHello.show(); // The .show method prevent 'losing' the current click }
}
}
});
final Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
This will produce the following result - preview
Note that I've used an HBox just for habit, there's no a particular reason.
While using a workaround like this, my suggestion would be to fill all the Menus with the same 'pattern', such as the HBox + Label combo in my example, and stylize them via css/code (width/height, background/fill/hover... colors etc.) in order to have them as uniform as possible and avoid creating graphic inconsistencies due to have different nodes types in the same menubar.

JAVAFX binding imageview on button(responsive)

Here i would like to create a responsive button alongwith imageview,but the problem is imageview not binding properly with button and if i clicked on the button or try to resize the window, automatically the image size increeses and lot of irrelevent scaling problems occuring,eventhough i have'nt set an eventhandler for that button.
This is my sample code
public class ImageController extends Application{
private DoubleProperty fontSize = new SimpleDoubleProperty(10);
#Override
public void start(Stage primaryStage) {
FlowPane fp=new FlowPane(); //here i used flowpane to make imagegallery(productview) that will be in responsive in thier position and i tested my problem not with the flowpane
for(int j=0;j<1;j++)
{
try {
Button button = new Button();
button.styleProperty().bind(Bindings.concat("-fx-font-size: ", fontSize.asString(), ";")); //button size binded to the scene
FileInputStream input = new FileInputStream("images/wine.png");
Image image = new Image(input, 100, 100, true,true);
ImageView imageView=new ImageView(image);
imageView.setPreserveRatio(true);
imageView.fitWidthProperty().bind(button.widthProperty()); //image size binded to the button
imageView.fitHeightProperty().bind(button.heightProperty());
button.setGraphic(imageView);
fp.getChildren().add(button);
} catch (FileNotFoundException ex) {
Logger.getLogger(ImageController.class.getName()).log(Level.SEVERE, null, ex);
}
}
Scene scene = new Scene(fp, 500, 500);
fontSize.bind(scene.widthProperty().add(scene.heightProperty()).divide(50));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
you can see my problem dairectly by running my code and resize the window or clicking on button.I need a button alongwith imageview both will resize according to screen resize(responsive)that's all.ThankYou in advance

Resources