JavaFX wait until value is set - java

I am struggling with the following problem:
I have something like a popup in my javafx application, that should block the application, until the user made some input. It is NOT a seperate stage, where i can call showAndWait() and then return the input of the stage. The popup is realized as a pane, that is placed over the other components. And now i do something like this:
PopupPane pp = new PopupPane()
stackPane.add(new PopupPane()); //show pane
//... waiting until user terminates popup
return pp.getInput(); //returns input when user terminates popup
So i want pp.getInput() to wait, until the user presses the OK/CANCEL/APPLY/... button in my popup. How can i realize something like showAndWait() in this situation?

One possible way to do this would be to utilize an additional pane that can be disabled while the "popup" is being displayed.
For example, say the root layout pane of your Scene is a StackPane. You could wrap all the rest of your interface in another Pane that you'll disable or enable as needed.
When the "popup" needs to be displayed, add it to your StackPane and disable the "content" pane. When the popup closes, just remove it from your StackPane and re-enable the "content" pane.
Here's a quick and admittedly unattractive example of the concept:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class SimulatedPopupExample extends Application {
private static StackPane root;
private static BorderPane content;
public static void main(String[] args) {
launch(args);
}
private static void showPopup() {
// Disable the main layout pain
content.setDisable(true);
VBox popup = new VBox();
popup.setPadding(new Insets(10));
popup.setAlignment(Pos.CENTER);
popup.setStyle("-fx-border-color: black; -fx-background-color: -fx-base;");
popup.setMaxSize(200, 200);
popup.getChildren().add(
new Button("Close Popup") {{
setOnAction(event -> {
// Re-enable the pane
content.setDisable(false);
// Remove popup from root layout
root.getChildren().remove(popup);
});
}}
);
// Add popup to root layout
root.getChildren().add(popup);
}
#Override
public void start(Stage primaryStage) {
// Simple Interface
root = new StackPane();
content = new BorderPane(
new Button("Show \"Popup\"") {{
setOnAction(e -> showPopup());
}},
new Button("Top Button"),
new Button("Right Button"),
new Button("Bottom Button"),
new Button("Left Button")
);
root.getChildren().add(content);
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setWidth(500);
primaryStage.setHeight(400);
primaryStage.setTitle("SimulatedPopupExample Sample");
primaryStage.show();
}
}
The Result:

Here is a Custom Dialog that can not be closed or accepted until the user enter data in the TextField
private void showInputTextDialog(){
Label lblAmt = new Label("Enter Amount");
Button btnOK = new Button("OK");
TextField txtAmt = new TextField();
AnchorPane customDialog = new AnchorPane();
customDialog.setStyle("-fx-border-color:red;-fx-border-width:10px; -fx-background-color: lightblue;");
customDialog.getChildren().addAll(lblAmt,btnOK,txtAmt);
lblAmt.setLayoutX(30);
lblAmt.setLayoutY(30);
txtAmt.setLayoutX(164);
txtAmt.setLayoutY(25);
txtAmt.setMaxWidth(116);
btnOK.setLayoutX(190);
btnOK.setLayoutY(100);
btnOK.setStyle("-fx-font-size: 18px;-fx-font-weight: bold;");
lblAmt.setStyle("-fx-font-size: 18px;-fx-font-weight: bold;");
txtAmt.setStyle("-fx-font-size: 18px;-fx-font-weight: bold;");
Scene secondScene = new Scene(customDialog, 300, 180);
EventHandler<ActionEvent> filter = event -> {
if(txtAmt.getText().isEmpty()) {
event.consume();
}
};
// New window (Stage)
Stage newWindow = new Stage();
//newWindow.initStyle(StageStyle.UNDECORATED);
newWindow.initModality(Modality.APPLICATION_MODAL);
newWindow.setResizable(false);
//newWindow.setTitle("Custom Dialog");
newWindow.setScene(secondScene);
btnOK.addEventHandler(ActionEvent.ACTION,filter);
btnOK.setOnAction(evt -> {
String str = txtAmt.getText();
System.out.println("################ str "+str);
if(txtAmt.getText().trim().equals("")) {
evt.consume();
txtAmt.clear();
txtAmt.requestFocus();
}else{
txAMT = Double.valueOf(str);
newWindow.close();
}
});
newWindow.setOnCloseRequest(event -> {
if(txtAmt.getText().isEmpty()) {
event.consume();
}
});
txtAmt.requestFocus();
newWindow.showAndWait();
}

Related

Updating GUI instead of new scene

I currently have
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
String dd = "Hello";
stage.setTitle("Greetings"); //creates title
button_roll = new Button("Roll");
StackPane layout1 = new StackPane();
layout1.getChildren().add(button_roll);
Scene scene1 = new Scene(layout1, 600, 600);
stage.setScene(scene1);
Label mylab = new Label();
mylab.setText(dd);
Scene scene2 = new Scene(mylab, 600, 600);
button_roll.setOnAction(e -> stage.setScene(scene2));
stage.show();
}
My code currently displays "Hello" into the scene as a new scene.
I was wondering if there was a way to just update the scene1 to display the text instead of creating a whole new scene with just the text in it.
Is there terminology for what I want to do, if so what is it?
Any help would be great!
Your problem is you never add the Label to the Scene. Having the root node as StackPane will stack the Label and Button over each other. You need to replace StackPane with VBox, HBox, or a more suitable Node. Comments in the code.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class App extends Application
{
#Override
public void start(Stage stage) throws Exception
{
String helloString = "Hello";//String use in the lable once the button is pressed.
Label lblHello = new Label();//Label that will show helloString once the button is pressed.
Button btnRoll = new Button("Roll");//The button that will trigger the action to change the label from empty string to helloString.
btnRoll.setOnAction((t) -> {//Set the button's action
lblHello.setText(helloString);//set the label's text to helloString.
});
VBox vbLayoutRoot = new VBox(lblHello, btnRoll);//The root layout is a VBox. Add the label and the btn to the root layout.
Scene scene = new Scene(vbLayoutRoot, 600, 600);//Add the root layout to the scene.
stage.setScene(scene);//Set the scene.
stage.setTitle("Greetings"); //creates title
stage.show();//Show the stage.
}
public static void main(String[] args)
{
launch(args);
}
}
I am not familiar with javaFX, but maybe you should try an EventHandler/ActionEvent:
button_roll.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
mylab.setText("Hello");
}
});
You should do like this:-
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
String dd = "Hello";
stage.setTitle("Greetings"); //creates title
Button button_roll = new Button("Roll");
StackPane layout1 = new StackPane();
layout1.getChildren().add(button_roll);
Scene scene1 = new Scene(layout1, 600, 600);
stage.setScene(scene1);
Label mylab = new Label();
mylab.setText(dd);
button_roll.setOnAction(e -> {
layout1.getChildren().clear();
layout1.getChildren().add(mylab);
});
stage.show();
}

Saving input data JavaFX

I am new to programming and am taking a class on OOP. I am trying to come up with a JavaFX application that saves mood input to be able to gather data. As of now the data is having to the console command window, but gets replaced when a new input is added. any Direction would be greatly appreciated.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class comboBoxPTSD extends Application {
Stage window;
Scene scene;
Button button;
ComboBox<String> comboBox;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
window.setTitle("PTSD Tracker App");
button = new Button("Submit");
comboBox = new ComboBox<>();
comboBox.getItems().addAll(
"Happy", "Content", "Good", "Sad", "Angry",
"Hopeless", "Suicidal");
//sets combo boxes text name.
comboBox.setPromptText("How are you doing today?");
comboBox.setEditable(true);
/*
* can set the comboBox to input user input with
*"comboBox.setEditable(true);"
*will override box name.
*want to save input and output...
*
*use variable string.
*/
button.setOnAction(e -> printMood());
//ComboBoxes also generate actions if you need to get value instantly
comboBox.setOnAction( e -> System.out.println("User selected " + comboBox.getValue()) );
VBox layout = new VBox(10);
layout.setPadding(new Insets(20, 20, 20, 20));
layout.getChildren().addAll(comboBox, button);
scene = new Scene(layout, 300, 250);
window.setScene(scene);
window.show();
}
private void printMood(){
System.out.println(comboBox.getValue());
}
}
Application JavaFX
Consol picture

HBox.setAlignments(Pos.CENTER) not working on one of the HBoxes in my JavaFX program.

I am currently working on a javaFX project that has to deal with stacking 3 panes on top of each other. The top one contains 5 radio buttons, the center contains a text that read "Programming is fun", and the bottom pane contains two buttons that have a "<=" symbol and the other contains a "=>" symbol. Essentially, I've finished the program, but I am having issues centering the bottom buttons. I used RadioButtons.setAlignment(Pos.CENTER) for the radio buttons and that worked fine, but, for some reason, it doesn't work when I type BottomButtons.setAlignment(Pos.CENTER). I would appreciate any help.
HBox bottomButtons = new HBox(5);
Button leftb = new Button("<=");
Button rightb = new Button("=>");
bottomButtons.getChildren().addAll(leftb, rightb);
Pane bottomPane = new Pane();
bottomButtons.setAlignment(Pos.CENTER);
bottomPane.getChildren().addAll(bottomButtons);
pane.setBottom(bottomPane);
Here is the full code in case there is something I missed within it.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Unit08_Prog01 extends Application {
public static void main(String[] args) {
launch(args);
}
Text text = new Text(40,40,"Programming is fun");
public BorderPane getPane() {
text.setFont(new Font(20));
HBox radioButtons = new HBox(5);
RadioButton redrb = new RadioButton("Red");
RadioButton yellowrb = new RadioButton("Yellow");
RadioButton whiterb = new RadioButton("White");
RadioButton orangerb = new RadioButton("Orange");
RadioButton greenrb = new RadioButton("Green");
radioButtons.getChildren().addAll(redrb, yellowrb, whiterb, orangerb, greenrb);
radioButtons.setAlignment(Pos.CENTER);
BorderPane pane = new BorderPane();
pane.setTop(radioButtons);
ToggleGroup group = new ToggleGroup();
redrb.setToggleGroup(group);
yellowrb.setToggleGroup(group);
whiterb.setToggleGroup(group);
orangerb.setToggleGroup(group);
greenrb.setToggleGroup(group);
Pane centerPane = new Pane();
centerPane.getChildren().add(text);
pane.setCenter(centerPane);
centerPane.setStyle("-fx-border-color: black");
HBox bottomButtons = new HBox(5);
Button leftb = new Button("<=");
Button rightb = new Button("=>");
bottomButtons.getChildren().addAll(leftb, rightb);
Pane bottomPane = new Pane();
bottomButtons.setPadding(new Insets(0,0,0,225));
bottomPane.getChildren().addAll(bottomButtons);
pane.setBottom(bottomPane);
whiterb.setSelected(true);
redrb.setOnAction(e -> {
if (redrb.isSelected()) {
centerPane.setStyle("-fx-background-color: red");
}
});
yellowrb.setOnAction(e -> {
if (yellowrb.isSelected()) {
centerPane.setStyle("-fx-background-color: yellow");
}
});
whiterb.setOnAction(e -> {
if (whiterb.isSelected()) {
centerPane.setStyle("-fx-background-color: white");
}
});
orangerb.setOnAction(e -> {
if (orangerb.isSelected()) {
centerPane.setStyle("-fx-background-color: orange");
}
});
greenrb.setOnAction(e -> {
if (greenrb.isSelected()) {
centerPane.setStyle("-fx-background-color: green");
}
});
leftb.setOnAction(e -> {
text.setX(text.getX() - 10 );
});
rightb.setOnAction(e -> {
text.setX(text.getX() + 10);
});
return pane;
}
#Override
public void start(Stage primaryStage) throws Exception {
// TODO Auto-generated method stub
Scene scene = new Scene(getPane(),500,200);
primaryStage.setTitle("Unit08_Prog1");
primaryStage.setScene(scene);
primaryStage.show();
}
}
Change the bottomPane from Pane to StackPane and remove the padding. Also set the alignment of bottomButtons to Pos.CENTER.
bottomButtons.setAlignment(Pos.CENTER);
StackPane bottomPane = new StackPane();
//bottomButtons.setPadding(new Insets(0,0,0,225));
Pane will not have a default layout policy. Whereas StackPane has a layout policy and by default it aligns to center.

Switching scenes don't retain maximized screen in JavaFX

My configuration:
I need to switch between scenes via the same stage
I need to keep a maximized stage that fills the whole screen
My issue:
although I set my stage to be maximized primaryStage.setMaximized(true);it adopts its size to the size of the scenes afterwards.
What I tried until now:
I tried using primaryStage.getScene().setRoot(<the root node of scene>). While it worked to keep the stage maximized, yet after each change of scene the focus on the previously focused gui control is lost (after switch only the first gui control in the scene hierarchy is focused). I really need scenes, so that any gui control that was focused still be will focused after the stage changes its scene.
I need your assistance:
I really need your assistance in keeping the stage maximized during changing scenes.
Here is my example code:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) {
// init buttons
Button btn1 = new Button("switch to next scene >>");
Button btn2 = new Button("<< switch to previous scene");
// first scene
StackPane root1 = new StackPane();
root1.getChildren().add(btn1);
Scene scene1 = new Scene(root1, 300, 250);
// second scene
StackPane root2 = new StackPane();
root2.getChildren().add(btn2);
Scene scene2 = new Scene(root2, 500, 400);
// button actions
btn1.setOnAction((ActionEvent event) -> {
primaryStage.setScene(scene2);
});
btn2.setOnAction((ActionEvent event) -> {
primaryStage.setScene(scene1);
});
primaryStage.setMaximized(true);
primaryStage.setScene(scene1);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
SOLUTION
create scenes depending on the screen size of your monitor
after several attempts I finally figured how to easily solve this problem to keep the maximized screen while retaining the focused node on each Scene. Hope it helps the community:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class NewFXMain extends Application {
#Override
public void start(Stage primaryStage) {
// get screensize of monitor
Rectangle2D screenSize = Screen.getPrimary().getVisualBounds();
// init buttons
Button btn1 = new Button("switch to next scene >>");
Button btn2 = new Button("<< switch to previous scene");
// first rootNode
StackPane root1 = new StackPane();
root1.getChildren().add(btn1);
Scene scene1 = new Scene(root1, screenSize.getWidth(), screenSize.getHeight());
// second rootNode
StackPane root2 = new StackPane();
root2.getChildren().add(btn2);
Scene scene2 = new Scene(root2, screenSize.getWidth(), screenSize.getHeight());
// button actions
btn1.setOnAction((ActionEvent event) -> {
primaryStage.setScene(scene2);
});
btn2.setOnAction((ActionEvent event) -> {
primaryStage.setScene(scene1);
});
primaryStage.setMaximized(true); // keep this since otherwise the titlebar is bit overlapped
primaryStage.setScene(scene1);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I think it's a bug. You can report it at: http://bugreport.java.com.
In the meantime, as a workaround, you probably need to just set the pane for a shared scene, replacing its content rather than replacing the scene.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class NewFXMainFixed extends Application {
#Override
public void start(Stage primaryStage) {
// init buttons
Button btn1 = new Button("switch to next scene >>");
Button btn2 = new Button("<< switch to previous scene");
// first scene
StackPane root1 = new StackPane();
root1.getChildren().add(btn1);
// second scene
StackPane root2 = new StackPane();
root2.getChildren().add(btn2);
// button actions
btn1.setOnAction((ActionEvent event) ->
primaryStage.getScene().setRoot(root2)
);
btn2.setOnAction((ActionEvent event) ->
primaryStage.getScene().setRoot(root1)
);
Scene scene = new Scene(root1);
primaryStage.setMaximized(true);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Is it possible to detect when the mouse cursor is over a hidden stage or scene in JavaFX?

I'm trying to implement a control that exists on a stage that, when moused over will be shown, and then when the mouse leaves it's bounds, hides itself.
I've tried
Stage.getScene().setOnMouseEntered((MouseEvent mEntered) -> {Stage.show();});
Stage.getScene().setOnMouseExited((MouseEvent mExited) -> {Stage.hide();});
I'm not really very surprised it didn't work, but it doesn't help me very much.
Is it possible to detect when the mouse is over the Stage or Scene when it is hidden?
I've read your multiple threads now and didn't get what you really intend to achieve when you put it all together. Maybe if you elaborate on that, another solution may be more appropriate.
Anyway, for your transparent buttons the solution is to use a transparency low enough to let the content below it shine through, but still not totally transparent in order to register mouse events. You wouldn't get mouse events on the application if it were fully transparent.
Here's an example about how you could do it:
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane pane = new Pane();
HBox hbox = new HBox();
hbox.setSpacing(12);
Button button1 = new Button("Button 1");
Button button2 = new Button("OMG Magic!");
Button button3 = new Button("Button 3");
hbox.getChildren().addAll(button1, button2, button3);
pane.getChildren().add( hbox);
final Scene scene = new Scene(pane, Color.TRANSPARENT);
// scene.getRoot().setStyle("-fx-background-color: transparent");
scene.getRoot().setStyle("-fx-background-color: rgba(1,1,1,0.004)");
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(scene);
primaryStage.show();
// initial opacity of button 2
button2.setOpacity(0.0);
// button2: fade-in on mouse scene enter
scene.addEventHandler(MouseEvent.MOUSE_ENTERED, evt -> {
System.out.println("Mouse entered");
FadeTransition fadeTransition = new FadeTransition(Duration.millis(300), button2);
fadeTransition.setFromValue(0.0);
fadeTransition.setToValue(1.0);
fadeTransition.play();
});
// button2: fade-out on mouse scene exit
scene.addEventHandler(MouseEvent.MOUSE_EXITED, evt -> {
System.out.println("Mouse exited");
FadeTransition fadeTransition = new FadeTransition(Duration.millis(300), button2);
fadeTransition.setFromValue(1.0);
fadeTransition.setToValue(0.0);
fadeTransition.play();
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
It shows 3 buttons. When you enter the button 2 or the pane between buttons 1 and button 3 with the mouse, then button 2 will magically appear :-)

Categories