I'm making an applet using JavaFX 8 (via a JFXPanel) and was planning on using a Popup to display an area with a TextField in it. This works as expected, until the application loses focus. After that, I'm unable to make the TextField regain focus so you can't type in it any more. I've tried calling requestFocus() on the TextField but that didn't seem to do anything. The problem can be seen in the simple example below:
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Popup;
import javax.swing.*;
public class FXApplet extends JApplet {
protected Scene scene;
protected Group root;
#Override
public final void init() {
SwingUtilities.invokeLater(() -> initSwing());
}
private void initSwing() {
JFXPanel fxPanel = new JFXPanel();
add(fxPanel);
Platform.runLater(() -> {
initFX(fxPanel);
initApplet();
});
}
private void initFX(JFXPanel fxPanel) {
root = new Group();
scene = new Scene(root);
fxPanel.setScene(scene);
}
public void initApplet() {
Popup popup = new Popup();
popup.setAutoHide(false);
popup.getContent().add(new TextField());
popup.show(scene.getWindow());
}
}
Related
after run this and press {play} button java stops and not respond on Mac
so I don't know what is the problem , I tried it in another another device (macOS )and same result.
any one have an idea !
import javafx.application.Application;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.*;
import javax.swing.*;
public class MyFX_event_1 extends Application{
public static void main(String[] args) { Application.launch(args); }
public void start(Stage primaryStage){
// Create a pane and set its properties
HBox pane = new HBox(10);
Button btn1 = new Button("PLAY");
MyHandlerClass handler1 = new MyHandlerClass();
btn1.setOnAction(handler1);
pane.getChildren().addAll(btn1);
// Create a scene and place it in the stage
Scene scene = new Scene(pane, 100, 100);
primaryStage.setTitle("HandleEvent"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
class MyHandlerClass implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent e) {
JOptionPane.showMessageDialog(null , "game will start");}
}
}
I am trying to set the focus on the JTextPane so that when the window opens it can immediately be edited with the keyboard. However, nothing I've done seems to give the JTextPane focus on startup. Is this just an issue with using JavaFX with Swing?
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingNode;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javax.swing.*;
public class TestDialog {
#FXML
private ListView listView;
#FXML
private SwingNode node;
private ObservableList<Integer> obsList;
#FXML
public void initialize(){
JTextPane pane = new JTextPane();
SwingUtilities.invokeLater(() -> pane.requestFocusInWindow());
pane.setText("This issue is not reproducible in JDK 8 early-access build (8u172) which is yet to be released.");
node.setContent(pane);
obsList = FXCollections.observableArrayList();
for(int x = 0; x < 12; x++){
obsList.add(x);
}
listView.setItems(obsList);
node.setFocusTraversable(true);
node.requestFocus();
pane.requestFocus();
pane.grabFocus();
}
#FXML
private void removeItem(ActionEvent event) {
obsList.remove(0);
}
}
It's working now thanks to a solution from BWC_semaJ. Rather than using:
SwingUtilities.invokeLater(() -> pane.requestFocusInWindow());
I should have used:
Platform.runLater(() -> {swingNode.requestFocus();}); //Use this instead
I don't know if this helps but below is the demo program I made based on the sample code and for some reason it works for me:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingNode;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javax.swing.*;
public class Test extends Application {
#FXML
private ListView listView;
#FXML
private SwingNode node;
private ObservableList<Integer> obsList;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage arg0) throws Exception {
initialize(arg0);
}
#FXML
public void initialize(Stage stage){
JTextPane pane = new JTextPane();
// The program runs the same no matter if one of the below two lines are used or if neither are used
//SwingUtilities.invokeLater(() -> pane.requestFocusInWindow());
//Platform.runLater(() -> {node.requestFocus();});
pane.setText("This issue is not reproducible in JDK 8 early-access build (8u172) which is yet to be released.");
node = new SwingNode();
node.setContent(pane);
obsList = FXCollections.observableArrayList();
for(int x = 0; x < 12; x++){
obsList.add(x);
}
listView = new ListView();
listView.setItems(obsList);
node.setFocusTraversable(true);
node.requestFocus();
pane.requestFocus();
pane.grabFocus();
StackPane root = new StackPane();
root.getChildren().add(node);
Scene scene = new Scene(root, 500, 500);
stage.setTitle("Test");
stage.setScene(scene);
stage.show();
}
#FXML
private void removeItem(ActionEvent event) {
obsList.remove(0);
}
}
I am now trying to make focus to FX FileDialog. When i click outside the dialog, dialog is outfocused. Its any way to make when i click outside, the dialog call any metod that make him visible (focused)? TY :)
I just tried any like this.
...focusedProperty().addListener((obs, oldVal, newVal) -> System.out.println(newVal ? "Focused" : "Unfocused"));
and maeby this way...
fileChooser.addEventHandler(WindowEvent.WINDOW_SHOWN, new EventHandler<WindowEvent>(){
#Override
public void handle(WindowEvent window)
{...
There is no way to handle focus using addEventHandler inside javafx.stage.FileChooser,
But you can simply use primaryStage.setAlwaysOnTop(true); to make your FileChooser always visible on top of other windows
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class JavaFXtest5 extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Test");
FileChooser chooser = new FileChooser();
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
primaryStage.setAlwaysOnTop(true);
chooser.showOpenDialog(primaryStage);
primaryStage.setAlwaysOnTop(false);
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello Dialog!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
I've made my own TimePicker that is supposed to work very much like DatePicker. I would like to know the best way to handle an event such as selecting a time and confirming it from the PopupWindow.
I could:
Make my TimePicker's popup node (a separate FXML and controller) define an interface and force the TimePicker parent to implement the methods to handle the selected date. (I'd MUCH like to avoid using interfaces in this manner. It seems like a terribly way to do things.)
Register some kind of custom EventHandler and listener to the popup window? Then, if I click OKAY after selecting a date from the PopupWindow, an event can be fired all the way up to the TimePicker.
Implement some kind of callback-like function. In android, for example, there were options for going to another screen solely to retrieve a result. I'm not sure if JavaFX has that kind of thing. The screens are quite separated from each other.
Just expose a ReadOnlyProperty representing the value. The user of your popup can then just observe the property.
Here's a proof of concept using a DatePicker:
import java.time.LocalDate;
import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Popup;
import javafx.stage.PopupWindow;
import javafx.stage.Stage;
public class DatePickerPopupExample extends Application {
#Override
public void start(Stage primaryStage) {
Label dateLabel = new Label(LocalDate.now().toString());
Button changeButton = new Button("Change");
HBox root = new HBox(5, dateLabel, changeButton);
root.setAlignment(Pos.CENTER);
changeButton.setOnAction(event -> {
DatePickerPopup popup = new DatePickerPopup();
popup.valueProperty().addListener((obs, oldDate, newDate) -> {
dateLabel.setText(newDate.toString());
});
Bounds buttonBds = changeButton.getBoundsInLocal();
Point2D loc = changeButton.localToScreen(buttonBds.getMaxX(), buttonBds.getMinY());
popup.showPopup(primaryStage, loc.getX(), loc.getY());
});
Scene scene = new Scene(root, 250, 150);
primaryStage.setScene(scene);
primaryStage.show();
}
public class DatePickerPopup {
private final ReadOnlyObjectWrapper<LocalDate> value = new ReadOnlyObjectWrapper<>();
private final Popup popup ;
public ReadOnlyObjectProperty<LocalDate> valueProperty() {
return value.getReadOnlyProperty();
}
public final LocalDate getValue() {
return valueProperty().get();
}
public DatePickerPopup(LocalDate date) {
value.set(date);
DatePicker picker = new DatePicker(date);
Button okButton = new Button("OK");
okButton.setOnAction(event -> {
popup.hide();
value.set(picker.getValue());
});
Button cancelButton = new Button("Cancel");
cancelButton.setOnAction(event -> {
popup.hide();
});
BorderPane root = new BorderPane();
root.setCenter(picker);
HBox buttons = new HBox(5, okButton, cancelButton);
buttons.setPadding(new Insets(5));
buttons.setAlignment(Pos.CENTER);
root.setBottom(buttons);
popup = new Popup();
popup.getContent().add(root);
}
public DatePickerPopup() {
this(LocalDate.now());
}
public void showPopup(Stage owner, double x, double y) {
popup.show(owner, x, y);
}
}
public static void main(String[] args) {
launch(args);
}
}
I want to create simple gridPane, which would change its size after clicking a button. I have this code:
public class NewSimScene extends GridPane{
Button testButton;
public NewSimScene(){
setPrefSize(500, 500);
testButton = new Button("TEST");
testButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
Node source = (Node) t.getSource();
NewSimScene pane = (NewSimScene) source.getParent();
pane.setPrefSize(100, 100);
pane.setMaxSize(100, 100);
}
});
getChildren().add(testButton);
}
}
When I'm debugging, I can see that prefHeight and prefWidth values are changed, but there isn't any change in pane appearance. What could be a problem?
I don't know if it's relevant, but I'm running this pane in a separate scene, triggered from MenuBar.
there is no issue in your code, the Grid Pane's getting re-sized. Please have a look at the following code and feel free to comment if you are looking for something else !
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class TableViewSample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
GridPane grid = new NewSimScene();
((Group) scene.getRoot()).getChildren().addAll(grid);
stage.setScene(scene);
stage.show();
}
public class NewSimScene extends GridPane {
Button testButton;
public NewSimScene() {
setPrefSize(500, 500);
setStyle("-fx-background-color: palegreen;");
testButton = new Button("TEST");
testButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
Node source = (Node) t.getSource();
NewSimScene pane = (NewSimScene) source.getParent();
pane.setPrefSize(100, 100);
}
});
getChildren().add(testButton);
}
}
}