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);
}
}
Related
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.
I've been working on javafx and i want to remove default windows and create a window with my style
It's quite easy to create a window in javafx. To create your own window you need to modify the style of your stage which can be done using initStyle() method.
public class Test extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(createParent(), Color.TRANSPARENT);
primaryStage.initStyle(StageStyle.TRANSPARENT);
// primaryStage.initStyle(StageStyle.UNDECORATED);
// primaryStage.initStyle(StageStyle.DECORATED);
primaryStage.setTitle("My Own Window");
primaryStage.setScene(scene);
primaryStage.show();
}
private Parent createParent() {
Pane rootPane = new Pane();
rootPane.setPrefSize(1000,400);
Button btn = new Button("RandomButton");
btn.setOnAction(e -> Platform.exit());
rootPane.getChildren().add(btn);
return rootPane;
}
}
I have a JavaFx application that loads a transparent stage with some text on it.
I want any click on the application to be completely ignored and the background application (if any) to receive that click.
My code at this stage is as follows:
public void start(final Stage primaryStage) {
primaryStage.setAlwaysOnTop(true);
final StackPane layout = new StackPane();
final Text mainText = new Text();
layout.getChildren().add(mainText);
mainText.setText("|||||||||||||||||||||||||||");
final Scene mainScene = new Scene(layout);
mainScene.setFill(null);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(mainScene);
primaryStage.show();
layout.setMouseTransparent(true);
mainText.setMouseTransparent(true);
}
I was not able to achieve the requirement. setMouseTransparent() just prevented the text from triggering events, it still captured the mouse clicks.
Is it possible to achieve this in JavaFx ? Even if it is a per-OS solution.
A way of doing this action in Windows is through user32.dll and Java Native Access (JNA). We used GetWindowLong to get the current configuration of the window and SetWindowLong to update the bit field that is controlling the ability of the window be transparent to the mouse.
Following is a working example that demonstrates this functionality:
#Override
public void start(final Stage primaryStage) {
primaryStage.setAlwaysOnTop(true);
final StackPane layout = new StackPane();
final Text mainText = new Text();
layout.getChildren().add(mainText);
mainText.setText("|||||||||||||||||||||||||||");
final Scene mainScene = new Scene(layout);
mainScene.setFill(null);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(mainScene);
primaryStage.setTitle(sTitle);
primaryStage.show();
sUser32.EnumWindows(
(hWnd, data) -> {
final byte[] windowText = new byte[512];
sUser32.GetWindowTextA(hWnd, windowText, 512);
final String wText = Native.toString(windowText);
if (!wText.isEmpty() && wText.equals(sTitle)) {
final int initialStyle = com.sun.jna.platform.win32.User32.INSTANCE.GetWindowLong(hWnd, WinUser.GWL_EXSTYLE);
com.sun.jna.platform.win32.User32.INSTANCE.SetWindowLong(hWnd, WinUser.GWL_EXSTYLE, initialStyle | WinUser.WS_EX_TRANSPARENT );
return false;
}
return true;
}, null);
}
I'm working with JavaFx and Scenebuilder and want create a local app for myself called "Taskplanner" in eclipse.
I created a new Stage and set it with a Scene (see Main.java). But not sure how to set a new Scene in the old stage (see Controller.java). Didnt also not find out if it is possible pass the signInButtonClicked()-Methode the "Stage primaryStage" over Scene Builder
Can anybody help ?
Controller.java:
#FXML
Button btnSignIn;
#FXML
public void signInButtonClicked() throws Exception
{
//Here I want call the new Scene(SignInGUI.fxml) in my old Stage
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../view/SignInGUI.fxml"));
}
Main.java:
#Override
public void start(Stage primaryStage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("../view/LoginGUI.fxml"));
primaryStage.setTitle("Taskplanner");
primaryStage.setScene(new Scene(root,500,500));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
You can get a reference to the Scene and Window from your button reference. From there, it's up to you to decide how to you want to show the new view.
Here's how you get those references:
Scene scene = btnSignIn.getScene();
Window window = scene.getWindow();
Stage stage = (Stage) window;
You can change the view by changing the root of your Scene:
FXMLLoader loader = ... // create and load() view
btnSignIn.getScene().setRoot(loader.getRoot());
Or you can change the entire Scene:
FXMLLoader loader = ... // create and load() view
Stage stage = (Stage) btnSignIn.getScene().getWindow();
Scene scene = new Scene(loader.getRoot());
stage.setScene(scene);
I'm writing a program in netbeans with javaFX
The view has several buttons in it with some bad buttons(like bombs is minesweeper), I'm trying to freeze the program when a bad button is pushed but i don't find how to do it
thanks!
There are various solutions to your problem. 2 among them are simply ignoring the action event or disabling the buttons like this:
public class ButtonAction extends Application {
final BooleanProperty buttonActionProperty = new SimpleBooleanProperty();
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
FlowPane root = new FlowPane();
CheckBox checkBox = new CheckBox( "Enabled");
checkBox.setSelected(true);
// solution 1: check if action is allowed and process it or not
buttonActionProperty.bind( checkBox.selectedProperty());
Button button = new Button( "Click Me");
button.setOnAction(e -> {
if( buttonActionProperty.get()) {
System.out.println( "Allowed, processing action");
} else {
System.out.println( "Not allowed, no action");
}
});
// solution 2: remove comments to activate the code
// button.disableProperty().bind(buttonActionProperty.not());
root.getChildren().addAll(checkBox, button);
primaryStage.setScene(new Scene(root, 600, 200));
primaryStage.show();
}
}
Add a ROOT typed event filter that consumes all kind of events (mouse, keyboard etc.)
btnThatHasHiddenMine.setOnAction(( ActionEvent event ) ->
{
System.out.println("Ohh no! You just stepped over the mine!");
getGameboardPane().addEventFilter( EventType.ROOT, Event::consume );
});
Add the filter to your GameboardPane only, since we don't want to freeze other part of the app.