This question already has an answer here:
JavaFX 2 custom popup pane
(1 answer)
Closed 7 years ago.
I want to create a popup window in a JavaFX application. Give me some ideas.
When I click on Check button it opens the popup window.
How to do it?
You can either create a new Stage, add your controls into it or if you require the POPUP as Dialog box, then you may consider using DialogsFX or ControlsFX(Requires JavaFX8)
For creating a new Stage, you can use the following snippet
#Override
public void start(final Stage primaryStage) {
Button btn = new Button();
btn.setText("Open Dialog");
btn.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
final Stage dialog = new Stage();
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.initOwner(primaryStage);
VBox dialogVbox = new VBox(20);
dialogVbox.getChildren().add(new Text("This is a Dialog"));
Scene dialogScene = new Scene(dialogVbox, 300, 200);
dialog.setScene(dialogScene);
dialog.show();
}
});
}
If you don't want it to be modal (block other windows), use:
dialog.initModality(Modality.NONE);
The Popup class might be better than the Stage class, depending on what you want. Stage is either modal (you can't click on anything else in your app) or it vanishes if you click elsewhere in your app (because it's a separate window). Popup stays on top but is not modal.
See this Popup Window example.
Take a look at jfxmessagebox (http://en.sourceforge.jp/projects/jfxmessagebox/) if you are looking for very simple dialog popups.
Have you looked into ControlsFx Popover control.
import org.controlsfx.control.PopOver;
import org.controlsfx.control.PopOver.ArrowLocation;
private PopOver item;
final Scene scene = addItemButton.getScene();
final Point2D windowCoord = new Point2D(scene.getWindow()
.getX(), scene.getWindow().getY());
final Point2D sceneCoord = new Point2D(scene.getX(), scene.
getY());
final Point2D nodeCoord = addItemButton.localToScene(0.0,
0.0);
final double clickX = Math.round(windowCoord.getX()
+ sceneCoord.getY() + nodeCoord.getX());
final double clickY = Math.round(windowCoord.getY()
+ sceneCoord.getY() + nodeCoord.getY());
item.setContentNode(addItemScreen);
item.setArrowLocation(ArrowLocation.BOTTOM_LEFT);
item.setCornerRadius(4);
item.setDetachedTitle("Add New Item");
item.show(addItemButton.getParent(), clickX, clickY);
This is only an example but a PopOver sounds like it could accomplish what you want. Check out the documentation for more info.
Important note: ControlsFX will only work on JavaFX 8.0 b118 or later.
Related
I have a full screen main application stage and want to make a TextInputDialog appear on top, with a modal style (i.e. the dialog must be dismissed before giving other input to the stage).
If I set the owner to the stage, and the style to UTILITY, then it works.
But if I want to remove decoration (by setting the style to UNDECORATED) then the dialog doesn't appear at all! I can only get it to appear by not setting the parent.
If I don't set the parent, the dialog appears on top of the stage but if I click anywhere else on the application it disappears behind the full screen stage.
How do I create an undecorated dialog that has modal-like behaviour over a full-screen stage?
// This works, but is decorated
TextInputDialog dialog = new TextInputDialog();
dialog.initOwner(stage);
dialog.initStyle(StageStyle.UTILITY);
dialog.showAndWait();
// This doesn't show at all (probably appears underneath the stage?)
TextInputDialog dialog = new TextInputDialog();
dialog.initOwner(stage);
dialog.initStyle(StageStyle.UNDECORATED);
dialog.showAndWait();
// This still allows clicking in the stage while dialog shown. Also causes
// "exit" of fullscreen by showing task bar when dialog is shown
TextInputDialog dialog = new TextInputDialog();
dialog.initStyle(StageStyle.UNDECORATED);
dialog.showAndWait();
I've made a complete example, which appears to be something you've tried, but isn't working. In my case it works great though. The window shows full screen, and the dialog comes up in the center without window decorations.
public class DialogCheck extends Application{
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("text field");
BorderPane root = new BorderPane();
Button b = new Button("dialog");
root.setCenter(b);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setFullScreen(true);
primaryStage.show();
b.setOnAction((evt)->{
TextInputDialog dialog = new TextInputDialog();
dialog.initOwner(primaryStage);
dialog.initStyle(StageStyle.UNDECORATED);
dialog.showAndWait();
});
}
}
Note that this is with java 11 & openjfx 11 on osx.
For some added debugging:
dialog.setOnShown( sevt ->{
System.out.println("showing: " + dialog.isShowing() + ", " + dialog.getX());
TextField field = dialog.getEditor();
field.requestFocus();
System.out.println(field.isFocused());
});
Also note the difference between using 'showAndWait' vs 'show'.
Dialog.showAndWait output:
showing: false, NaN.
false
Dialog.show output:
showing: true, 621.0
true
The title may be a bit vague, so allow me to define it a little better. I have a working piece of code (down below): a simple main menu for a game I am working on. Everything works well, except for the Start button.
What I want to be able to do is click the Start button, and have a new scene appear on the same stage (window). I do not want to see a new window open. I have talked with someone more experienced in Java, and they told me to create separate classes for the MenuFX and the GameFX. If that is the case, I would need to call some start or launch method on the GameFX class from the MenuFX class, correct? Is this the best approach, or would I want to keep all FX-related code in one class? Also, I should keep the same stage for all FX work, no?
This post shed some light on things, but I am not well-versed in some of the terms discussed- for instance, I still do not understand the concept of Root.
Also, this post talks about a similar application, but I am not using FXML or SceneBuilder... I do not know if any of it is relatable.
MenuFX.java - I have removed some of the working code, simply for brevity. You can see that all I need help with is tying the Start button to some functionality that makes a new empty scene.
/*
* This is simply working on the title screen.
*/
// Asssume all imports are correct
import java.everythingNeeded
public class MenuFX extends Application {
#Override
public void start (Stage primaryStage) {
// Make the window a set size...
primaryStage.setResizable(false);
// Create menu vbox and set the background image
VBox menuVBox = new VBox(30);
menuVBox.setBackground(new Background(new BackgroundImage(new
Image("image/bambooBG.jpg"), null, null, null, new BackgroundSize(45,
45, true, true, true, true))));
// Create start button
Button startButton = new Button("Start Game");
// TODO Some things...
// Need assistance here
// Create help button
Button helpButton = new Button("Help");
helpButton.setOnAction(e -> THINGS);
// Create music toggle button
ToggleButton musicButton = new ToggleButton("Music On/Off");
musicButton.setOnAction(e -> THINGS);
// Create credits button
Button creditsButton = new Button("Credits");
creditsButton.setOnAction(THINGS);
// Create exit button and set it to close the program when clicked
Button endButton = new Button("Exit Game");
endButton.setOnAction(e -> Platform.exit());
// Add all nodes to the vbox pane and center it all
// Must be in order from top to bottom
menuVBox.getChildren().addAll(startButton, helpButton, musicButton, creditsButton, endButton);
menuVBox.setAlignment(Pos.CENTER);
// New scene, place pane in it
Scene scene = new Scene(menuVBox, 630, 730);
// Place scene in stage
primaryStage.setTitle("-tiles-");
primaryStage.setScene(scene);
primaryStage.show();
}
// Needed to run JavaFX w/o the use of the command line
public static void main(String[] args) {
launch(args);
}
}
Restating: I want to click the Start button and have the currently open window change to an empty scene.
Here is a pastebin of the MenuFX class in its entirety:
http://pastebin.com/n6XbQfhc
Thank you for any help,
Bagger
The basic idea here is you would do something like:
public class GameFX {
private final BorderPane rootPane ; // or any other kind of pane, or Group...
public GameFX() {
rootPane = new BorderPane();
// build UI, register event handlers, etc etc
}
public Pane getRootPane() {
return rootPane ;
}
// other methods you may need to access, etc...
}
Now back in the MenuFX class you would do
Button startButton = new Button("Start Game");
startButton.setOnAction(e -> {
GameFX game = new GameFX();
primaryStage.getScene().setRoot(game.getRootPane());
});
How to make a button stacked behind a Label clickable?
Button
Button btn = new Button();
//TODO: button's main function, like onPressed, onReleased etc. here...
Custom label
CustomLabel sp = new CustomLabel("Some texts here"));
//TODO: custom label's main function, like a translucent background etc here...
//main purpose of this is to overlay the button
Main Pane
StackPane mainPane = new StackPane();
mainPane.getChildren.addAll(btn, sp);
With this, the area which the custom label overlays becomes unclickable.
Is there anyway to make the button still clickable even though overlay-ed, for example?
Or is there another way to do it? Something like setting label to not visible on click?
EDIT : To answer Itamar Green 's question..
By using the example as shown in this link: Mouse Events get Ignored on the Underlying Layer , it still does not seems to work. The button stacked under the layer is still not clickable.
sp.setPickOnBounds(false);
You can set the mouseTransparent property of the element(s) drawn on top to true. Note that this way all descendants of the node are ignored for mouse events:
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Say 'Hello World'");
btn.setOnAction((ActionEvent event) -> {
System.out.println("Hello World!");
});
Region region = new Region();
region.setStyle("-fx-background-color: #0000ff88;");
region.setMouseTransparent(true);
StackPane root = new StackPane(btn, region);
Scene scene = new Scene(root, 100, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
Comment out
region.setMouseTransparent(true);
and the button will no longer react to mouse events in any way...
thanks for your help. I think I have solved my own question.
All I did was set a clickable event for my label.
Label sp = new Label("some texts here")
sp.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
//copy over the button's event.
}
});
Not sure if there is any better way of doing this...
in addition with the correct answer. you can enable or disable " mouse transparent " property via fxml with scenebuilder
I have a Java Swing application. For one of javax.swing.JFrame, I use JFXPanel to embed JavaFX content. In JFXPanel, there is ListView (JFrame => JFXPanel => ListView). Double click on ListView's item, will open new JavaFX browser Window, to load HTML content of it's URL.
Assuming 3 windows:
Window-A: Main application window (Swing).
Window-B: JFrame with JFXPanel (contain's ListView).
Window-C: JavaFX browser window
Once Window-C is open, it always stay on top of any other Windows (Window-A, Window-B, & even Netbean IDE Window). When click on Window-A / Window-B, the Window is actived but always stay behind Window-C. The only way to have complete view on Window-A / Window-B, is to move Window-C away so not to overlap with them.
I tried setting these for Window-C, but with no effect:
stage.initOwner(((Node)event.getSource()).getScene().getWindow());
stage.initModality(Modality.NONE);
The intended behaviour is, whenever Window-A / Window-B / Window-C is clicked, it should stay on top, all the other windows should go behind it.
Any idea how to make this work? Is it a mistake to invoke pure JavaFX Window (Window-C) from Swing application?
Below is my code snippet:
public class StockNews extends JFrame {
private final JFXPanel jfxPanel = new JFXPanel();
Scene scene;
VBox vbox;
java.util.List<FeedItem> messages;
ListView<FeedItem> newsListView;
ObservableList<FeedItem> messages_o;
public StockNews(java.util.List<FeedItem> messages) {
super();
this.messages = messages;
initComponents();
}
private void initComponents() {
Platform.runLater(new Runnable() {
#Override
public void run() {
vbox = new VBox();
scene = new Scene(vbox, 500, 500);
jfxPanel.setScene(scene);
messages_o = FXCollections.observableArrayList (messages);
newsListView = new ListView<>(messages_o);
newsListView.setCellFactory(new Callback<ListView<FeedItem>,
ListCell<FeedItem>>() {
#Override
public ListCell<FeedItem> call(ListView<FeedItem> list) {
// draw single cell
return new DisplaySingleNews();
}
}
);
// Double-clicked ListView's item, will open new JavaFX browser Window, loading HTML content of it's URL
newsListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.getClickCount() > 1) {
FeedItem msg = newsListView.getSelectionModel().getSelectedItem();
URL link = msg.getLink();
Stage stage = new Stage(StageStyle.UTILITY);
// This window always stay on top, even not active. below 2 lines have no effect
stage.initOwner(((Node)event.getSource()).getScene().getWindow());
stage.initModality(Modality.NONE);
WebView browser = new WebView();
stage.setScene(new Scene(browser));
stage.show();
WebEngine webEngine = browser.getEngine();
webEngine.load(link.toString());
}
}
});
vbox.getChildren().addAll(newsListView);
}
});
this.add(jfxPanel, BorderLayout.CENTER);
this.setVisible(true);
}
}
I am trying to implement a custom tooltip using the javafx.stage.Popup. The sample demo code is:
public class PopupDemo extends Application {
private Popup tooltip;
private final SepiaTone sepiaTone = new SepiaTone();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("PopupDemo");
Label content = new Label();
content.setStyle("-fx-background-color:#FCFBBD; -fx-padding: 5; -fx-border-color: #BFBD3B");
tooltip = new Popup();
tooltip.getContent().add(content);
VBox vbox = new VBox(10);
for (int i = 0; i < 5; i++) {
final Label lbl = new Label("item " + i);
lbl.setStyle("-fx-border-color:darkgray; -fx-background-color:lightgray");
lbl.setMaxSize(80, 60);
lbl.setMinSize(80, 60);
lbl.setAlignment(Pos.CENTER);
lbl.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(final MouseEvent e) {
lbl.setEffect(sepiaTone);
lbl.setStyle("-fx-cursor: hand");
Label content = (Label) tooltip.getContent().get(0);
content.setText(lbl.getText());
tooltip.show(lbl, e.getScreenX(), e.getScreenY());
}
});
lbl.setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
lbl.setEffect(null);
lbl.setStyle("-fx-cursor: default");
tooltip.hide();
}
});
vbox.getChildren().add(lbl);
}
StackPane root = new StackPane();
root.setPadding(new Insets(20));
root.getChildren().add(vbox);
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}
}
When I move the mouse over the labels the popup shows up and it is working great. But in some cases the two mouse event handlers OnMouseEntered and OnMouseExited are being called continuously one after another. One can reproduce this by running provided example, maximising a window and hovering labels continuously.
Is there a way to avoid this? I'm using JavaFX 2.0.1. Thanks.
It's a classic problem: you put mouse at a point, node receives MouseEntered — tooltip appears under the mouse and covers the node triggering MouseExited.
To avoid that you can change tooltip.show(lbl, e.getScreenX(), e.getScreenY()) call to
tooltip.show(lbl, e.getScreenX() + 1, e.getScreenY() + 1);
This is not really an answer, so much as pointers to things you might try or investigate further.
You could look at the implementation of Tooltip Skin and Behavior to see how it handles some of these cases.
The easiest way to implement a custom popup is just to use a Tooltip, style it the way you need using css and use the Tooltip's setGraphic method to add any custom Node content you want.
If you prefer to use your own implementation, I think you need to keep track of whether the popup has been displayed or not, so you don't try to show it if it is already showing, etc. You may also need invoke the hiding of the popup by having a mouse exit handler installed on the popup itself. You also might want a click to dismiss function for the popup by implementing a mouse click handler on the popup. You should also consider whether you should do a straight subclass of Popup or PopupControl, though using Popup as you have is likely more straightforward.