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

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();
}
}

Related

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!"));

Can JavaFX ComboBox fire events when selection not changed?

I'm new to JavaFX. Unlike Swing, JavaFX's combo box's action event seems to be fired when the selection actually changed. In Swing, you can add an ActionListener on a JComboBox and it will fire an event whenever you make a selction (by clicking on one of the choices in the combo box), regardless of if the selected value actually changed. Can we achieve the same behavior in JavaFX? Some code below. What I want is to select "Hello" and have it printed, and select "Hello" again and have it printed again.
public class ComboBoxSelection extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
VBox layout = new VBox();
ComboBox<String> comboBox = new ComboBox<>();
comboBox.getItems().addAll("Hello", "World");
comboBox.setOnAction(event -> System.out.println("Selected " + comboBox.getValue()));
layout.getChildren().addAll(comboBox);
Scene scene = new Scene(layout);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I noticed a thread here: ComboBox SAME item selected action listener. This almost gives me what I want, except this fires when the selection cancels (press Esc) as well. Is there any other solution? Thanks in advance.

TextField in PopOver with strange behavior

I have a PopOver with a TextField with a strange behavior, this PopOver it's owned by other TextField because when I type the word 'Fernández' all keys are processed by the internal TextField except when I type a stressed vowel like 'á' that it's collected by the external TextField.
PopOver owned by TextField
But when i show the same PopOver owned by a button works fine and the internal TextField receives the letter 'á'
PopOver owned by Button
I would appreciate any help to solve it.
EDIT: Here you can see an example code to show this.
public class PopOverTest extends Application {
#Override
public void start(Stage primaryStage) {
CustomTextField externo = new CustomTextField();
ImageView imgView = new ImageView(new Image("test/image.png"));
externo.setLeft(imgView);
CustomTextField interno = new CustomTextField();
PopOver popOver = new PopOver();
popOver.setContentNode(interno);
popOver.stArrowLocation(PopOver.ArrowLocation.TOP_LEFT);
imgView.setOnMouseClicked(e -> {
popOver.show(imgView);
});
StackPane root = new StackPane();
root.getChildren().add(externo);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
I found a solution for this.
Changing the external Textfield EventDispatcher and the problem is resolved
EventDispatcher dispatcher = externalTextField.getEventDispatcher();
then on focus of the internal TextField
externalTextField.setEventDispatcher(interntalTextField.getEventDispatcher());
and when lost focus restore the EventDispatcher
externalTextField.setEventDispatcher(dispatcher);
That's all folks!

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

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;
}

How to create a modal window in JavaFX 2.1

I can't figure out how to create a modal window in JavaFX. Basically I have file chooser and I want to ask the user a question when they select a file. I need this information in order to parse the file, so the execution needs to wait for the answer.
I've seen this question but I've not been able to find out how to implement this behavior.
In my opinion this is not good solution, because parent window is all time active.
For example if You want open window as modal after click button...
private void clickShow(ActionEvent event) {
Stage stage = new Stage();
Parent root = FXMLLoader.load(
YourClassController.class.getResource("YourClass.fxml"));
stage.setScene(new Scene(root));
stage.setTitle("My modal window");
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(
((Node)event.getSource()).getScene().getWindow() );
stage.show();
}
Now Your new window is REALY modal - parent is block.
also You can use
Modality.APPLICATION_MODAL
Here is link to a solution I created earlier for modal dialogs in JavaFX 2.1
The solution creates a modal stage on top of the current stage and takes action on the dialog results via event handlers for the dialog controls.
JavaFX 8+
The prior linked solution uses a dated event handler approach to take action after a dialog was dismissed. That approach was valid for pre-JavaFX 2.2 implementations. For JavaFX 8+ there is no need for event handers, instead, use the new Stage showAndWait() method. For example:
Stage dialog = new Stage();
// populate dialog with controls.
...
dialog.initOwner(parentStage);
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.showAndWait();
// process result of dialog operation.
...
Note that, in order for things to work as expected, it is important to initialize the owner of the Stage and to initialize the modality of the Stage to either WINDOW_MODAL or APPLICATION_MODAL.
There are some high quality standard UI dialogs in JavaFX 8 and ControlsFX, if they fit your requirements, I advise using those rather than developing your own. Those in-built JavaFX Dialog and Alert classes also have initOwner and initModality and showAndWait methods, so that you can set the modality for them as you wish (note that, by default, the in-built dialogs are application modal).
You can create application like my sample. This is only single file JavaFX application.
public class JavaFXApplication1 extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Stage stage;
stage = new Stage();
final SwingNode swingNode = new SwingNode();
createSwingContent(swingNode);
StackPane pane = new StackPane();
pane.getChildren().add(swingNode);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle("Swing in JavaFX");
stage.setScene(new Scene(pane, 250, 150));
stage.show();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private void createSwingContent(final SwingNode swingNode) {
SwingUtilities.invokeLater(() -> {
try {
Path currentRelativePath = Paths.get("");
String s = currentRelativePath.toAbsolutePath().toString();
JasperDesign jasperDesign = JRXmlLoader.load(s + "/src/reports/report1.jrxml");
String query = "SELECT * FROM `accounttype`";
JRDesignQuery jrquery = new JRDesignQuery();
jrquery.setText(query);
jasperDesign.setQuery(jrquery);
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
JasperPrint JasperPrint = JasperFillManager.fillReport(jasperReport, null, c);
//JRViewer viewer = new JRViewer(JasperPrint);
swingNode.setContent(new JRViewer(JasperPrint));
} catch (JRException ex) {
Logger.getLogger(AccountTypeController.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

Resources