I have made an application which uses tabpane. I am able to set tooltip and title of each tab dynamically. But how do I set its contents dynamically. I am sure that I can maintain a list of Node object and add it to tab during iteration, but I feel there are other ways to do it. Here is what I have done so far.
public class Index extends Application {
public static void main(String[] args) {
launch(args);
}
final String[] tabContent={"title1"
,"title2"
,"title3"
,"title4"
,"title5"};
final String[] tabToolTip={"tooltip1"
,"tooltip2"
,"tooltip3"
,"tooltip4"
,"tooltip5"};
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Ipas Utility");
Group root = new Group();
Scene scene = new Scene(root, 1000, 600, Color.ALICEBLUE);
TabPane tabPane = new TabPane();
tabPane.setTooltip(new Tooltip("Hover on each tab for an overview"));
BorderPane borderPane = new BorderPane();
for (int i = 0; i < 5; i++) {
Tab tab = new Tab();
tab.setText(tabContent[i]);
tab.setClosable(false);
tab.setTooltip(new Tooltip(tabToolTip[i]));
HBox hbox = new HBox();
hbox.getChildren().add(new Label(tabContent[i]));
hbox.setAlignment(Pos.CENTER);
tab.setContent(hbox);;
tabPane.getTabs().add(tab);
}
// bind to take available space
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
borderPane.setCenter(tabPane);
root.getChildren().add(borderPane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
How I can maintain tabcontent in a list/array outside start block?
That's quite okay what you did. Here's a modified version of your code which allows you to add a tab on button click:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
private static int tabCount = 0;
#Override
public void start(Stage primaryStage) {
TabPane tabPane = new TabPane();
tabPane.getTabs().add(createTab());
tabPane.getTabs().add(createTab());
tabPane.getTabs().add(createTab());
Button addTabButton = new Button( "Add Tab");
addTabButton.setOnAction(e -> {
tabPane.getTabs().add(createTab());
});
Button logButton = new Button( "Log");
logButton.setOnAction(e -> {
for( Tab tab: tabPane.getTabs()) {
System.out.println( "Tab " + tab.getText() + " has content " + tab.getContent());
}
});
HBox toolbar = new HBox();
HBox.setMargin(addTabButton, new Insets(5,5,5,5));
HBox.setMargin(logButton, new Insets(5,5,5,5));
toolbar.getChildren().addAll( addTabButton, logButton);
BorderPane root = new BorderPane();
root.setTop(toolbar);
root.setCenter(tabPane);
Scene scene = new Scene(root, 640, 480);
primaryStage.setScene(scene);
primaryStage.show();
}
public static Tab createTab() {
tabCount++;
Tab tab = new Tab();
tab.setText("Tab " + tabCount);
tab.setTooltip( new Tooltip( "Tooltip Tab " + tabCount));
Node content = new Label( "Content Tab " + tabCount);
tab.setContent(content);
return tab;
}
public static void main(String[] args) {
launch(args);
}
}
In order to access the tabs you can use getTabs. And in order to change the content, i. e. the node that represents the content, you can use setContent.
The example code shows you how to iterate through the tabs by pressing the log button.
Related
I have been trying to display buttons and some text with javafx but it whont work it just displays over eachother in the middle of the screen:
I have been trying to use vbox and ive also tried to use hbox but both dont change how it looks when i run it
(when i run it i get no erors)
(also im using vs code if that has anything to say)
Here is my code so far:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage primaryStage) {
// buttons
VBox vboxBtn = new VBox();
vboxBtn.setPadding(new Insets(10, 10, 10, 10));
vboxBtn.setSpacing(10);
Button btnRoom = new Button("changeRoom");
Button btnMap = new Button("changeMap");
vboxBtn.getChildren().addAll(btnRoom, btnMap);
// text
VBox vboxTxt = new VBox();
vboxTxt.setPadding(new Insets(10, 10, 10, 10));
vboxTxt.setSpacing(10);
Text txtRoom = new Text("Room");
Text txtMap = new Text("Map");
vboxTxt.getChildren().addAll(btnRoom, btnMap);
String currentRoom = "None";
String currentMap = "None";
// button for switching maps
btnMap.setText("Change the map");
// button click
btnMap.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event) {
System.out.println("Hello world");
}
});
// text for maps
txtMap.setText("Map: " + currentMap);
// button for switching rooms
btnRoom.setText("Hello world");
// button click
btnRoom.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello world");
}
});
// text
txtRoom.setText("Room: " + currentRoom);
StackPane root = new StackPane();
root.getChildren().add(btnRoom);
root.getChildren().add(btnMap);
root.getChildren().add(txtRoom);
root.getChildren().add(txtMap);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I think the problem is you are adding butons and txts to the pane instead of Vboxes and Hboxes.
I believe you want them on a 4x4 grid, to do that you need to add your virtual boxes to a hbox then add that hbox to a pane, or u could use a grid.
Or you could set their locations, I dont know if this is possible with code, but you can do that in screenbuilder.
PS: check out screenbuilder for javafx.
I'm trying to create a grid with a textbox on each row where user can enter a number, and corresponding number of new rows are added. This works well, as shown below in the screenshot.
Now I'm trying to extract the text from those textfields created based on the question "how many?" and since they are nested within various node elements, I'm having a hard time identifying the right way.Can anyone tell me what I'm doing wrong? I tried testing it using the save button, but I always go into the else statement of "Vboxgrid2 is empty!"on my console. I don't know why it says that my VBoxgrid2 is empty!
Following is a Minimal, Complete, and Verifiable example I've recreated:
package testing;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ExtractThatText extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("GridPane Experiment");
GridPane gridPane = new GridPane();
for(int i=0;i<5;i++) {
VBox mainVBox = new VBox();
VBox vboxgrid1 = new VBox();
VBox vboxgrid2 = new VBox();
HBox hboxgrid = new HBox();
hboxgrid.setPadding(new Insets(5,5,5,5));
RadioButton rbYes = new RadioButton("Yes");
RadioButton rbNo = new RadioButton("No");
Label howmanyLabel = new Label(" How many? ");
TextField howManytxtB = new TextField();
hboxgrid.getChildren().add(rbYes);
hboxgrid.getChildren().add(rbNo);
hboxgrid.getChildren().add(howmanyLabel);
hboxgrid.getChildren().add(howManytxtB);
vboxgrid1.getChildren().add(hboxgrid);
howManytxtB.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
vboxgrid2.getChildren().clear();
Integer howManyNum = Integer.valueOf(howManytxtB.getText());
for(int row=0;row<howManyNum;row++) {
//creating rows for entering the new entities
HBox innerRowbox = new HBox();
TextField name = new TextField();
ComboBox cb = new ComboBox(); //empty cb for now
name.setPromptText("Enter name of the new Entity");
name.setMinWidth(200);
innerRowbox.getChildren().add(name);
innerRowbox.getChildren().add(cb);
vboxgrid2.getChildren().add(innerRowbox);
}
}
});
mainVBox.getChildren().add(vboxgrid1);
mainVBox.getChildren().add(vboxgrid2);
gridPane.add(mainVBox,1, i);
}
for(int i=0;i<5;i++) {
gridPane.add(new Label("row"+i), 0 , i);
}
Button saveButton = new Button("save content");
saveButton.setOnAction(e-> {
Node mainVBox = gridPane.getChildren().get(1); //get just the first row's 1th column which contains mainVBox
if(mainVBox instanceof VBox) {
Node vboxgrid2 = ((VBox) mainVBox).getChildren().get(1);
if(vboxgrid2 instanceof VBox) {
if(!((VBox) vboxgrid2).getChildren().isEmpty()) {
Node innerRowBox = ((VBox) vboxgrid2).getChildren().get(0);
if(innerRowBox instanceof HBox) {
for(Node howmanyTB:((HBox)innerRowBox).getChildren()) {
if(howmanyTB instanceof TextField) {
System.out.println(((TextField) howmanyTB).getText()); //content to save, extracted from the dnamic textfields created.
}
else System.out.println("howmanyTB not an instance of TextField error!");
}
}
else System.out.println("innerRowBox not an instance of HBox error!");
}
else System.out.println("Vboxgrid2 is empty!");
}
else System.out.println("vboxgrid2 not an instance of VBox error!");
}
else System.out.println("mainVbox not an instance of VBox error!");
});
gridPane.add(saveButton, 1, 5);
gridPane.setHgap(10);
gridPane.setVgap(10);
Scene scene = new Scene(gridPane, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
** If it's difficult to understand the nesting of all my nodes, here is a summary:
gridPane -> mainVBox (in each row of the second/1th column) -> vboxgrid2 (along with vboxgrid1 above it for the radiobutton row in mainVBox) -> innerRowbox -> name (textfield)
If it's difficult to understand the nesting of all my nodes
Since you do seem to realize that your nesting is a bit confusing, it would be preferable to save the TextFields in a data structure that is easier to access than your scene hierarchy. In this case since the number of items is known before they are created, a TextField[][] array could be used, but you could also go for a List<List<TextField>> to allow you to dynamically add (inner) rows.
BTW: since you use index 1 you access the second row, not the first one.
Also using a VBox just to contain your HBox seems unnecessary. You could simply use the HBox directly, since the VBox has no other children.
Label howmanyLabel = new Label(" How many? ");
Better use a margin for this spacing instead of spaces.
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("GridPane Experiment");
GridPane gridPane = new GridPane();
final int rowCount = 5;
TextField[][] textFields = new TextField[rowCount][0];
final Insets hboxPadding = new Insets(5);
final Insets labelMargin = new Insets(0, 15, 0, 15);
for (int i = 0; i < rowCount; i++) {
VBox vboxgrid2 = new VBox();
RadioButton rbYes = new RadioButton("Yes");
RadioButton rbNo = new RadioButton("No");
Label howmanyLabel = new Label("How many?");
HBox.setMargin(howmanyLabel, labelMargin);
TextField howManytxtB = new TextField();
HBox hboxgrid = new HBox(rbYes, rbNo, howmanyLabel, howManytxtB);
hboxgrid.setPadding(hboxPadding);
final int rowIndex = i;
howManytxtB.setOnAction(event -> {
vboxgrid2.getChildren().clear();
int howManyNum = Math.max(0, Integer.parseInt(howManytxtB.getText()));
TextField[] fields = new TextField[howManyNum];
for (int row = 0; row < howManyNum; row++) {
//creating rows for entering the new entities
TextField name = new TextField();
ComboBox cb = new ComboBox(); //empty cb for now
name.setPromptText("Enter name of the new Entity");
name.setMinWidth(200);
HBox innerRowbox = new HBox(name, cb);
vboxgrid2.getChildren().add(innerRowbox);
fields[row] = name;
}
textFields[rowIndex] = fields;
});
VBox mainVBox = new VBox(hboxgrid, vboxgrid2);
gridPane.addRow(i, new Label("row" + i), mainVBox);
}
Button saveButton = new Button("save content");
saveButton.setOnAction(e -> {
TextField[] secondRowFields = textFields[1];
if (secondRowFields.length == 0) {
System.out.println("no TextFields in row1");
} else {
for (TextField textField : secondRowFields) {
System.out.println(textField.getText());
}
}
});
gridPane.add(saveButton, 1, rowCount);
gridPane.setHgap(10);
gridPane.setVgap(10);
Scene scene = new Scene(gridPane, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
In the demo app, I added a List<TextField> textFieldContainer = new ArrayList(); that stores the dynamically create TextFields.
The code below delete the appropriate TextFields if the numbers change and Enter is pressed.
textFieldContainer.removeIf(p -> p.getUserData().toString().startsWith("TextField_" + tempRow));
Full Code:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ExtractThatText extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
List<TextField> textFieldContainer = new ArrayList();
primaryStage.setTitle("GridPane Experiment");
GridPane gridPane = new GridPane();
for(int i=0;i<5;i++) {
VBox mainVBox = new VBox();
VBox vboxgrid1 = new VBox();
VBox vboxgrid2 = new VBox();
HBox hboxgrid = new HBox();
hboxgrid.setPadding(new Insets(5,5,5,5));
RadioButton rbYes = new RadioButton("Yes");
RadioButton rbNo = new RadioButton("No");
Label howmanyLabel = new Label(" How many? ");
TextField howManytxtB = new TextField();
hboxgrid.getChildren().add(rbYes);
hboxgrid.getChildren().add(rbNo);
hboxgrid.getChildren().add(howmanyLabel);
hboxgrid.getChildren().add(howManytxtB);
vboxgrid1.getChildren().add(hboxgrid);
final Integer tempRow = i;
howManytxtB.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
vboxgrid2.getChildren().clear();
Integer howManyNum = Integer.valueOf(howManytxtB.getText());
//The next two lines clears TextFields if you change the amount and/or press enter
textFieldContainer.removeIf(p -> p.getUserData().toString().startsWith("TextField_" + tempRow));
for(int row=0;row<howManyNum;row++) {
//creating rows for entering the new entities
HBox innerRowbox = new HBox();
TextField name = new TextField();
final Integer innerRow = row;
name.setUserData("TextField_" + tempRow + "_" + innerRow);
System.out.println(name.getUserData().toString());
textFieldContainer.add(name);
ComboBox cb = new ComboBox(); //empty cb for now
name.setPromptText("Enter name of the new Entity");
name.setMinWidth(200);
innerRowbox.getChildren().add(name);
innerRowbox.getChildren().add(cb);
vboxgrid2.getChildren().add(innerRowbox);
}
}
});
mainVBox.getChildren().add(vboxgrid1);
mainVBox.getChildren().add(vboxgrid2);
gridPane.add(mainVBox,1, i);
}
for(int i=0;i<5;i++) {
gridPane.add(new Label("row"+i), 0 , i);
}
Button saveButton = new Button("save content");
saveButton.setOnAction(e-> {
System.out.println("Saving these TextField's Text:");
for(TextField textField : textFieldContainer)
{
System.out.println(textField.getUserData() + ": " + textField.getText());
}
});
gridPane.add(saveButton, 1, 5);
gridPane.setHgap(10);
gridPane.setVgap(10);
Scene scene = new Scene(gridPane, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
Output:
Click save content to see the info currently in the TextFields.
Saving these TextField's Text:
TextField_0_0: one
TextField_1_0: two
TextField_1_1: three
TextField_2_0: four
TextField_3_0: seven
TextField_3_1: six
TextField_4_0: five
I have a menu which should be used to navigate through different "views"(layout). The menu should always be visible. The only thing that should change is the displayed content, in dependency of the selected menu item.
I have a very basic example, using two classes, created below:
public class Main extends Application{
static final Pane pane = new Pane();
public void start(Stage stage) {
pane.getChildren().addAll(Menu.getPaneMenu());
Scene scene = new Scene(pane);
stage.setScene(scene);
stage.setMaximized(true);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
public class Menu {
private static final Pane paneMenu = new Pane();
static Pane getPaneMenu() {
Button btn1 = new Button("Menu 1");
btn1.relocate(100, 10);
btn1.setPrefSize(100, 20);
btn1.setOnAction(e -> {
Label lbl = new Label("You clicked Menu1");
lbl.relocate(200, 40);
Main.pane.getChildren().add(lbl);
});
Button btn2 = new Button("Menu 2");
btn2.relocate(300, 10);
btn2.setPrefSize(100, 20);
btn2.setOnAction(e -> {
Label lbl = new Label("You clicked Menu2");
lbl.relocate(200, 40);
Main.pane.getChildren().add(lbl);
});
paneMenu.getChildren().addAll(btn1, btn2);
return paneMenu;
}
}
The challenge I´m facing is, that when clicking a menu, the old menu stays(as you can see, the displayed text overwrites the other):
What would be an efficient way to solve this overlapping?
Here is an example that shows how to load two different Panes in a BorderPane.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Sample extends Application {
#Override public void start(Stage stage) {
BorderPane root = new BorderPane();
Button loadSceneOne = new Button("Load Scene One");
//Event hanlder to load scene one
loadSceneOne.setOnAction((event)->{
root.setCenter(getSceneOne());
});
//Event hanlder to load scene two
Button loadSceneTwo = new Button("Load Scene Two");
loadSceneTwo.setOnAction((event)->{
root.setCenter(getSceneTwo());
});
VBox menu = new VBox();
menu.getChildren().addAll(loadSceneOne, loadSceneTwo);
root.setLeft(menu);
Scene scene = new Scene(root);
stage.setMaximized(true);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
//Scene One
Pane getSceneOne()
{
Pane pane = new Pane();
Label label = new Label("Scene One!");
StackPane stackPane = new StackPane();
stackPane.getChildren().add(label);
pane.getChildren().add(stackPane);
return pane;
}
//Scene Two
Pane getSceneTwo()
{
Pane pane = new Pane();
Label label = new Label("Scene Two!");
StackPane stackPane = new StackPane();
stackPane.getChildren().add(label);
pane.getChildren().add(stackPane);
return pane;
}
}
What about declaring labels as fields of the Menu class (same with buttons)? Then you can add/remove them from the pane. I modified your code a little - it should works in this particular case:
class Menu {
private static final Pane paneMenu = new Pane();
private static final Button btn1 = new Button("Menu 1");
private static final Button btn2 = new Button("Menu 2");
private static final Label firstLabel = new Label("You clicked Menu1");
private static final Label secondLabel = new Label("You clicked Menu2");
static Pane getPaneMenu() {
ObservableList<Node> mainPaneChildren = Main.pane.getChildren();
btn1.relocate(100, 10);
btn1.setPrefSize(100, 20);
btn1.setOnAction(e -> {
firstLabel.relocate(200, 40);
if (mainPaneChildren.contains(secondLabel)) {
mainPaneChildren.remove(secondLabel);
}
if (!mainPaneChildren.contains(firstLabel)) {
mainPaneChildren.add(firstLabel);
}
});
btn2.relocate(300, 10);
btn2.setPrefSize(100, 20);
btn2.setOnAction(e -> {
secondLabel.relocate(200, 40);
if (mainPaneChildren.contains(firstLabel)) {
mainPaneChildren.remove(firstLabel);
}
if (!mainPaneChildren.contains(secondLabel)) {
mainPaneChildren.add(secondLabel);
}
});
paneMenu.getChildren().addAll(btn1, btn2);
return paneMenu;
}
}
If there are going to be more elements than just a Label it would be better if you put them in some kind of a Pane. Than you can add/remove that Pane.
By the way - have a look at Working With Layouts in JavaFX? I don't think that using relocate() is a good practice.
Is there a way to limit the number of visible rows for a menu in JavaFX?
Here is a working example
public class MenuProb extends Application {
public void start(Stage primaryStage) {
Group group = new Group();
Scene scene = new Scene(group, 800, 600);
MenuBar menuBar = new MenuBar();
Menu someValues = new Menu("Values");
for (int i = 0; i < 50; i++) {
MenuItem item = new MenuItem("Value " + i);
someValues.getItems().add(item);
}
menuBar.getMenus().add(someValues);
group.getChildren().addAll(menuBar);
primaryStage.setScene(scene);
primaryStage.show();
}
}
When the above code is run, a menu is created wherein the scrollbar appears only after the menuitems have exceeded the screen height.
Is there a way to limit the number of visible rows to a pre-decided number? That is, a scrollbar appears if the number of rows exceeds that limit.
One approach is to use a CustomMenuItem with a Control that lets you adjust the size. The example below illustrates a ComboBox, which allows setVisibleRowCount(), and a ListView, which includes a prefWidthProperty and prefHeightProperty.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.ListView;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.stage.Stage;
/** #see https://stackoverflow.com/q/44792148/230513 */
public class CustomMenuTest extends Application {
#Override
public void start(Stage primaryStage) {
Group group = new Group();
Scene scene = new Scene(group, 320, 240);
ComboBox<String> comboBox = new ComboBox<>();
for (int i = 0; i < 50; i++) {
comboBox.getItems().add("Value " + i);
}
CustomMenuItem comboMenuItem = new CustomMenuItem(comboBox, false);
comboBox.getSelectionModel().select(0);
comboBox.setVisibleRowCount(16);
ObservableList<String> values = FXCollections.observableArrayList();
for (int i = 0; i < 50; i++) {
values.add("Value " + i);
}
ListView<String> listView = new ListView<>(values);
CustomMenuItem listMenuItem = new CustomMenuItem(listView, false);
MenuBar menuBar = new MenuBar();
Menu comboMenu = new Menu("Combo Values");
comboMenu.getItems().add(comboMenuItem);
Menu listMenu = new Menu("List Values");
listMenu.getItems().add(listMenuItem);
menuBar.getMenus().addAll(comboMenu, listMenu);
group.getChildren().addAll(menuBar);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I'm extremely new to JavaFX, and I'm attempting to get a button(specifically scrapeBtn) into the bottom right corner of an application. Here is what I have so far:
package main;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Driver extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button scrapeBtn = new Button();
scrapeBtn.setText("Scrape!");
scrapeBtn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
System.out.println("Scrape button pressed.");
}
});
TextField console = new TextField();
GridPane root = new GridPane();
GridPane.setConstraints(scrapeBtn, 2, 2, 1, 1);
root.getChildren().add(scrapeBtn);
root.getChildren().add(console);
Scene scene = new Scene(root, 600, 400);
primaryStage.setTitle("Wiki Scraper");
primaryStage.setScene(scene);
primaryStage.show();
}
}
Any ideas as to how I could accomplish this? Some tips in general to aligning and formatting things with JavaFX would also be really appreciated.
Thanks.
I often use a BorderPane for similar purposes (e.g. a Dialog with some text and controls etc. at the center and one or more buttons at the bottom). Therefore, I use the BorderPane as root and a HBox as "button container" at the bottom. Finally, I set the botton alignment to "RIGHT".
Here an example based on your code:
#Override
public void start(Stage primaryStage) {
// center
VBox vbCenter = new VBox(); // use any container as center pane e.g. VBox
TextField console = new TextField();
vbCenter.getChildren().add(console);
// bottom respectively "button area"
HBox hbButtons = new HBox();
Button scrapeBtn = new Button();
scrapeBtn.setText("Scrape!");
scrapeBtn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
System.out.println("Scrape button pressed.");
}
});
hbButtons.getChildren().add(scrapeBtn);
hbButtons.setAlignment(Pos.CENTER_RIGHT);
// root
BorderPane root = new BorderPane();
root.setPadding(new Insets(20)); // space between elements and window border
root.setCenter(vbCenter);
root.setBottom(hbButtons);
Scene scene = new Scene(root, 600, 400);
primaryStage.setTitle("Wiki Scraper");
primaryStage.setScene(scene);
primaryStage.show();
}
This code leads to this (after resizing the window a little bit):
You can use two BorderPanes to place a control bottom right
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
BorderPane bottom = new BorderPane();
bottom.setRight(new Button("I am placed bottom right"));
root.setBottom(bottom);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setWidth(400);
primaryStage.setHeight(400);
primaryStage.show();
}