JavaFX command link dialog - javafx

I want to make dialog exactly the same as described in this tutorial http://code.makery.ch/blog/javafx-8-dialogs/.
Dialog is called "Command Link Dialog".
Unfortunately this tutorial is depracated since these dialogs are inside JDK 8u40.
Is there a simple way to make the same dialog using new JDK without ControlsFX?

First create your own button graphic that resembles the CommandLink. In my example I'm using FontAwesomeFX to create the green arrow icon:
GridPane graphicGrid = new GridPane();
graphicGrid.setHgap(5);
graphicGrid.setVgap(5);
// Create an icon using FontAwesomeFX.
Text icon = GlyphsDude.createIcon(FontAwesomeIcon.ARROW_RIGHT);
icon.setFill(Color.GREEN);
Label headerLabel = new Label("Go to the Circus");
headerLabel.setStyle("-fx-font-size: 1.5em;");
Label detailsLabel = new Label("Watch acrobats fly around and clowns, of course.");
graphicGrid.add(icon, 0, 0);
graphicGrid.add(headerLabel, 1, 0);
graphicGrid.add(detailsLabel, 1, 1);
Button button = new Button("", graphicGrid);
Then use the Custom Dialog example from the JavaFX dialogs tutorial to create your own custom dialog and fill it with the buttons you've created. Here's a complete example:
import de.jensd.fx.glyphs.GlyphsDude;
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon;
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MCVE extends Application {
#Override
public void start(Stage stage) {
Dialog dialog = new Dialog();
GridPane content = new GridPane();
content.setHgap(10);
content.setVgap(5);
Text headerIcon = GlyphsDude.createIcon(FontAwesomeIcon.INFO_CIRCLE, "3em");
headerIcon.setFill(Color.BLUE);
Label headerLabel = new Label("Where do you want to go?");
headerLabel.setStyle("-fx-font-size: 1.5em;");
CommandLink zooButton = new CommandLink("Go to the Zoo",
"Here you will see zebras, monkeys, lions, elephants, and maybe also an alligator.");
zooButton.setOnAction(e -> dialog.close());
CommandLink circusButton = new CommandLink("Go to the Circus",
"Watch acrobats fly around and clowns, of course.");
circusButton.setOnAction(e -> dialog.close());
CommandLink homeButton = new CommandLink("Stay Home", "Watch TV or play some board games with your siblings.");
// To enable closing of the dialog. We need to add a hidden close
// button. See this thread:
// http://stackoverflow.com/questions/32048348/javafx-scene-control-dialogr-wont-close-on-pressing-x
dialog.getDialogPane().getButtonTypes().add(ButtonType.CLOSE);
Node closeButton = dialog.getDialogPane().lookupButton(ButtonType.CLOSE);
closeButton.managedProperty().bind(closeButton.visibleProperty());
closeButton.setVisible(false);
content.add(headerIcon, 0, 0);
content.add(headerLabel, 1, 0);
content.add(zooButton, 1, 1);
content.add(circusButton, 1, 2);
content.add(homeButton, 1, 3);
dialog.getDialogPane().setContent(content);
dialog.showAndWait();
}
public static void main(String[] args) {
launch();
}
class CommandLink extends Button {
public CommandLink(String header, String text) {
GridPane graphicGrid = new GridPane();
graphicGrid.setHgap(5);
graphicGrid.setVgap(5);
// Create an icon using FontAwesome.
Text icon = GlyphsDude.createIcon(FontAwesomeIcon.ARROW_RIGHT);
icon.setFill(Color.GREEN);
Label btnHeaderLabel = new Label(header);
btnHeaderLabel.setStyle("-fx-font-size: 1.5em;");
Label detailsLabel = new Label(text);
graphicGrid.add(icon, 0, 0);
graphicGrid.add(btnHeaderLabel, 1, 0);
graphicGrid.add(detailsLabel, 1, 1);
setGraphic(graphicGrid);
}
}
}
And here's the result: A dialog that looks somewhat like the Command Link Dialog. You'll have to play around with styling yourself to make it perfect. There's also the possibility to use the Information Dialog from the official dialogs if you want the original information icon.

Related

the method .add(node) doesn't allow me to use Button. JavaFX [duplicate]

Ok so from my stand point my code is pretty decent enough to get a passing grade but I am having trouble adding a simple refresh/shuffle button. NOT USING the aids of JOptionPane.
Eclipse doesnt seem to recognize that I have created the button which doesnt make sense at all for me because its telling me something about a Node which the Button is in fact a node and it is created. But when I go into another class and add another button with the 3 line example it simply works. But when I move it to my homework program it simply gives me an error on the add method which breaks the whole program!
Says
"The method add(Node) in the type List is not applicable for the arguements (Button)"
Could anyone shed some light of where I could be going wrong in my code? It has to be something along the a node to string conversion or something I just cant seem to figure it out. Willing to take any hints given to me but please DO NOT SOLVE THE PROBLEM FOR ME.
Here is the question from the book basically.
"Write a program that lets the user click the refresh button to display four cards from a deck of 54 cards."
I just need some help on the button thats all. I literally have the rest.
Here is my code so far.
I Have left the imports out as there is just too many.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import java.awt.Button;
import java.io.File;
import java.util.ArrayList;
public class Cards extends Application
{
public void start(Stage primaryStage)
{
ArrayList<String> cards = new ArrayList<>(); //Array list
Shuffle(cards); //Shuffles the Cards
String file1 = new File("cards" + "/" + cards.get(1) + ".png").toURI().toString();
String file2 = new File("cards" + "/" + cards.get(2) + ".png").toURI().toString();
String file3 = new File("cards" + "/" + cards.get(3) + ".png").toURI().toString();
String file4 = new File("cards" + "/" + cards.get(4) + ".png").toURI().toString();
Pane pane = new HBox(20); //Creates the Box for the Images
pane.setPadding(new Insets(5, 5, 5, 5)); //Spreads the Images out
Image image = new Image(file1); //Creates the String Image
Image image2 = new Image(file2);
Image image3 = new Image(file3);
Image image4 = new Image(file4);
pane.getChildren().add(new ImageView(image)); //Adds the First Image
ImageView view1 = new ImageView(image);
view1.setFitHeight(100);
view1.setFitWidth(100);
pane.getChildren().add(new ImageView(image2)); //Adds the Second Image
ImageView view2 = new ImageView(image2);
view2.setFitHeight(100);
view2.setFitWidth(100);
pane.getChildren().add(new ImageView(image3)); //Add the Third Image
ImageView view3 = new ImageView(image3);
view3.setFitHeight(100);
view3.setFitWidth(100);
pane.getChildren().add(new ImageView(image4)); //Add the Fourth Image
ImageView view4 = new ImageView(image4);
view4.setFitHeight(100);
view4.setFitWidth(100);
HBox hbox = new HBox(5); //Creates the Box for the Button
Button shuffle = new Button("Shuffle"); //Creates the Button
hbox.getChildren().add(shuffle); //Should add the button but doesn't
shuffle.addActionListener( e -> //Listener for the button
{
Shuffle(cards);
});
BorderPane pane2 = new BorderPane();/ /Creates the Pane for the Button
pane2.setCenter(pane); //Sets the cards in the Center
pane2.setBottom(hbox); //Sets the Button on the bottom
BorderPane.setAlignment(hbox, Pos.CENTER);
hbox.setAlignment(Pos.BOTTOM_CENTER);//Aligns the Button to BOT_CENTER
Scene scene = new Scene(pane2); //Creates the Scene
primaryStage.setTitle("Cards");
primaryStage.setScene(scene);
primaryStage.show();
}
public void Shuffle(ArrayList<String> cards)
//Allows the cards to Shuffle when called.
{
for (int i = 0; i <= 53; i++) //Sets the Number of Cards in Deck
cards.add(String.valueOf(i+1));
java.util.Collections.shuffle(cards);
}
public static void main(String[] args)
{
launch(args);
}
}
You're using the AWT-button with your import java.awt.Button;, that's why you can use the method public void addActionListener(ActionListener l).
Replace your import to import javafx.scene.control.Button;. Furthermore you could use (analogue to your code) the following lambda:
shuffle.setOnAction( (x) -> //Listener for the button
{
Shuffle(cards);
});
Give it a try :)

How to use modal dialog in this case?

I have a question. I need to make a GridPane with a directory choose that will then lead me to a modal dialog showing photos. I cannot figure how to do the modal dialog that also has to be a GridPane or a HBox...so the question is , how do I get to show a Modal Dialog after selecting the Folder and pressing the "Show" Button... Thanks a lot!
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
public class FotoView extends Application {
#Override
public void start(Stage primaryStage) {
TextField tf = new TextField();
Button b1 = new Button("Search");
Button b2 = new Button("Show");
DirectoryChooser dc = new DirectoryChooser();
GridPane gp = new GridPane();
gp.add(tf, 0 , 0);
gp.add(b1, 1, 0);
gp.add(b2, 0, 1);
b1.setOnAction(e-> dc.showDialog(primaryStage));
primaryStage.setScene(new Scene(gp)) ;
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
} ```
Below is a quick example where a first window has a button that opens up a DirectoryChooser. Once a directory has been selected a second smaller window opens up with the Modality set to APPLICATION_MODAL. In this second window you could add the image(s) that you load and add them to the GridPane.
import java.io.File;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(final String[] args) {
launch(args);
}
#Override
public void start(final Stage aStage) throws Exception {
final HBox root = new HBox();
final Button browseBtn = new Button("Click to open a Directory chooser");
root.getChildren().add(browseBtn);
browseBtn.setOnAction(e -> {
final DirectoryChooser chooser = new DirectoryChooser();
final File dir = chooser.showDialog(aStage);
openNewModalStage(aStage, dir);
});
final Scene scene = new Scene(root, 500, 500);
aStage.setScene(scene);
aStage.show();
}
private void openNewModalStage(final Stage aStage, final File aDirectory) {
final Stage stage = new Stage();
final GridPane grid = new GridPane();
final Scene scene = new Scene(grid);
grid.setStyle("-fx-background-color:black");
grid.setPrefWidth(400);
grid.setPrefHeight(400);
// get your images from 'aDirectory' and add them to your grid pane.
stage.setScene(scene);
// set the new windows Modality.
stage.initModality(Modality.APPLICATION_MODAL);
stage.show();
}
}
This way you would only need the one button and the dialog would show as soon as you've selected a directory. However, if you would still want a Search and Show button then just store the directory as a variable and add a listener on the 'show' button and move the openNewModalStage call to that one and remove the second argument.
Edit:
Also, depending on how many images and exactly what you want to display in the modal window, you might want to reconsider the GridPane and use a TilePane, or an hbox/vbox inside of a scroll pane. It's just a thought but I don't know what you will be doing with the GridPane.

Wizard with JavaFX Accordions

I'm writing a small configuration-wizard-style JavaFX application. I want to force the user through different steps of configuration panes. So I've chosen an accordion container with a few panels. The user is only allowed to proceed to the NEXT or PREVIOUS accordion panel, but may not jump from panel 1 to 3.
I achived this by adding the "Previous" and "Next" button under the accordion and I set the mouse transparency of the accordion to true. Everything works fine so far. The user can walk from panel 1 to 5 and back...
Unfortunately (for any strange reason) the user cannot configure nothing inside the different panels. Wait... I set the mouse transparency to "true", right... But when I set it to false, the user can jump through the panels without any order.
Any suggestions?
One possible way is to set the collapsible property of all the panes to false, and to set each one to true just when it needs to be expanded or collapsed (which you can do programmatically). This is a little ugly, but here's an example:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class AccordionBasedWizard extends Application {
#Override
public void start(Stage primaryStage) {
Accordion accordion = new Accordion();
for (int i = 0 ; i < 5 ; i++) {
TitledPane pane = new TitledPane("Page "+(i+1), new Label("Wizard page "+(i+1)));
accordion.getPanes().add(pane);
pane.setCollapsible(false);
}
accordion.setExpandedPane(accordion.getPanes().get(0));
Button previousButton = new Button("Previous");
previousButton.disableProperty().bind(accordion.expandedPaneProperty().isEqualTo(accordion.getPanes().get(0)));
previousButton.setOnAction(e -> {
TitledPane current = accordion.getExpandedPane();
int index = accordion.getPanes().indexOf(current);
TitledPane previous = accordion.getPanes().get(index - 1);
current.setCollapsible(true);
previous.setCollapsible(true);
accordion.setExpandedPane(previous);
previous.setCollapsible(false);
current.setCollapsible(false);
});
Button nextButton = new Button("Next");
nextButton.disableProperty().bind(accordion.expandedPaneProperty().isEqualTo(accordion.getPanes().get(accordion.getPanes().size()-1)));
nextButton.setOnAction(e -> {
TitledPane current = accordion.getExpandedPane();
int index = accordion.getPanes().indexOf(current);
TitledPane next = accordion.getPanes().get(index + 1);
current.setCollapsible(true);
next.setCollapsible(true);
accordion.setExpandedPane(next);
next.setCollapsible(false);
current.setCollapsible(false);
});
HBox buttons = new HBox(5, previousButton, nextButton);
buttons.setAlignment(Pos.CENTER);
buttons.setPadding(new Insets(5));
BorderPane root = new BorderPane(accordion);
root.setBottom(buttons);
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
For what it's worth, I probably wouldn't try to use an Accordion as a wizard, and would just use a BorderPane, with the current "wizard page" in the center and next and previous buttons in the bottom. You can add a breadcrumb trail too if you need.

java fx gridpane setpadding

I am trying to set the padding for my GridPane, but every time I set the padding it gives me the error message:
incompatible types: java.awt.Insets cannot be converted to javafx.geometry.insets
Every website I go to and every search states to implement it like this:
grid.setPadding(new Insets(10, 10, 10, 10));
And in my code I have it set exactly the same just for testing purposes :
grid.setPadding(new Insets(10, 10, 10, 10));
So I don't understand why it won't allow me to write that, I have also tried to research the error message but nothing comes up.
Here is my code:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package myrectangle2d;
import java.awt.Insets;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
*
* #author macuser
*/
public class Exercise18_29 extends Application {
Stage window;
Label label1, label2, centerXL, centerXR;
TextField textCenterXL, textCenterXR;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
window = primaryStage;
window.setTitle("Triangles");
GridPane grid = new GridPane();
grid.setPadding(new Insets(10, 10, 10, 10));
label1 = new Label("Do the Triangles match");
GridPane.setConstraints(label1, 0, 0);
label2 = new Label("Yes or no");
GridPane.setConstraints(label2, 1, 0);
centerXL = new Label("Center X LEFT");
GridPane.setConstraints(centerXL, 0, 5);
textCenterXL = new TextField();
GridPane.setConstraints(textCenterXL, 1, 5);
centerXR = new Label("Center X RIGHT");
GridPane.setConstraints(centerXL, 0, 5);
textCenterXR = new TextField();
GridPane.setConstraints(textCenterXR, 3, 5);
grid.getChildren().addAll(label1, label2, centerXL, textCenterXL, centerXR, textCenterXR);
Scene scene = new Scene(grid, 400, 600);
window.setScene(scene);
window.show();
}
}
The error message tells you everything you need to know:
incompatible types: java.awt.Insets cannot be converted to javafx.geometry.insets
You have imported java.awt.Insets: (first import line in your code) you need javafx.geometry.Insets.
The answer above is good. You need
import javafx.geometry.Insets;
instead of
import java.awt.Insets;
I generated the error first time when I allowed my IDE to auto import the necessary libraries. Sometimes the shortcuts bite.

How can a dynamically generated JavaFX scene be changed in a single stage?

I'm currently working on a project requiring me to switch back and forward between scenes. I have already written some code for it but it isn't as elegant as I wanted to be, especially as there is few flickers when I switch between them and sometimes even the buttons that I have generated simply disappear only to appear once again when yet another scene has been generated. Moreover, the layout I'm using for my application isn't really fixed and I think that using FXML might be not suitable for what I'm doing.
Thank you.
This is what I'm using to change between scenes:
void changeScene(Stage stage,Scene scene){
stage.setScene(scene);
primaryStage.setFullScreen(true);
}
I assume by "switching between scenes" you mean that you want to change the entire content of the existing window.
There are two (very) slightly different ways you can do this. Either create a new Scene and pass it to the Stage's setScene(...) method. Or create the Parent that is the root of the new UI (either by FXML or otherwise), and pass it to the existing Scene's setRoot(...) method. There's no real advantage that I can see of one over the other.
Here's a minimal implementation of the second option. The UI is irrelevant to the question: the important parts are the event handlers for the "Login" button (which switches from the login scene to the main scene) and the "Logout" button (which switches back).
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
public class MinimalSceneSwitchingExample extends Application {
#Override
public void start(Stage primaryStage) {
LoginView loginView = new LoginView();
Scene scene = new Scene(loginView.getView(), 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class LoginView {
private final IntegerProperty loginAttempts ;
private final GridPane view ;
public LoginView() {
view = new GridPane();
TextField usernameTF = new TextField("user");
TextField passwordTF = new TextField("pass");
// Login button switches to main view:
Button loginButton = new Button("Login");
loginButton.setOnAction(event -> {
if (usernameTF.getText().equalsIgnoreCase("user")
&& passwordTF.getText().equalsIgnoreCase("pass")) {
// *** Switch to main view: ***
Parent mainView = new MainView().getView();
view.getScene().setRoot(mainView);
} else {
loginAttempts.set(loginAttempts.get()+1);
}
});
// just set up login UI... irrelevant to this example:
loginAttempts = new SimpleIntegerProperty();
usernameTF.setPromptText("Hint: user");
passwordTF.setPromptText("Hint: pass");
view.addRow(0, new Label("Username:"), usernameTF);
view.addRow(1, new Label("Password:"), passwordTF);
Label loginErrorMessage = new Label();
loginErrorMessage.textProperty().bind(
Bindings.when(loginAttempts.isEqualTo(0))
.then("")
.otherwise(Bindings.format("Login incorrect (Attempts: %d)",
loginAttempts)));
view.add(loginErrorMessage, 0, 2, 2, 1);
view.add(loginButton, 0, 3, 2, 1);
ColumnConstraints leftCol = new ColumnConstraints();
leftCol.setHgrow(Priority.NEVER);
leftCol.setHalignment(HPos.RIGHT);
ColumnConstraints rightCol = new ColumnConstraints();
rightCol.setHgrow(Priority.ALWAYS);
rightCol.setHalignment(HPos.LEFT);
view.getColumnConstraints().addAll(leftCol, rightCol);
GridPane.setHalignment(loginErrorMessage, HPos.CENTER);
GridPane.setHalignment(loginButton, HPos.CENTER);
view.setHgap(10);
view.setVgap(16);
view.setAlignment(Pos.CENTER);
}
public Parent getView() {
return view ;
}
}
public static class MainView {
private BorderPane view ;
public MainView() {
view = new BorderPane();
// *** logout button switches back to a login view: ***
Button logoutButton = new Button("Log out");
logoutButton.setOnAction(event ->
view.getScene().setRoot(new LoginView().getView()));
// Arbitrary UI, irrelevant to this example:
SplitPane splitPane = new SplitPane();
ListView<String> listView = new ListView<>();
IntStream.rangeClosed(1, 10)
.mapToObj(Integer::toString)
.map("Item "::concat)
.forEach(listView.getItems()::add);
Label bigLabel = new Label();
bigLabel.textProperty().bind(
listView.getSelectionModel().selectedItemProperty());
bigLabel.setFont(Font.font("Verdana", FontWeight.BOLD, 18));
BorderPane.setAlignment(bigLabel, Pos.CENTER);
BorderPane.setMargin(bigLabel, new Insets(10));
Label details = new Label();
details.textProperty().bind(
Bindings.when(
listView.getSelectionModel().selectedItemProperty().isNull())
.then("")
.otherwise(Bindings.format("This is where you would display "
+ "all sorts of details about %1$s. "
+ "If %1$s were really a model object, you "
+ "might have a GridPane displaying all its "
+ "properties, for example.",
listView.getSelectionModel().selectedItemProperty())));
details.setWrapText(true);
BorderPane detailsPane = new BorderPane(details, bigLabel, null, null, null);
splitPane.getItems().addAll(listView, detailsPane);
view.setCenter(splitPane);
view.setBottom(logoutButton);
BorderPane.setAlignment(logoutButton, Pos.CENTER);
BorderPane.setMargin(logoutButton, new Insets(8));
BorderPane.setMargin(splitPane, new Insets(16));
}
public Parent getView() {
return view ;
}
}
public static void main(String[] args) {
launch(args);
}
}

Resources