I am new to JavaFX
I wrote this code however, I dont know how to Display the Menu Bar in all my Scenes. Also I would like to create/fill my scenes with the Layout in my HelloApplication (however thats another issue).
I have a controller, for setting the Stage and launching it.
My MenuBar is in the class MenuLeiste, but I would like it to appear in my Credits class aswell. Im very sorry for the lack of comments and the Layout of this comment.
public class HelloApplication extends Application {
public class Main {
public static void main(String[] args) {
launch(args);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
//set window as primaryStage
Stage window = primaryStage;
//Layout of MenuLeiste is put in l1 and setted as scene1
MenuLeiste l1 = new MenuLeiste();
//menuscene gets its objects fromsceneViewMenu
Scene menuscene = new Scene(l1.sceneViewMenu());
window.setScene(menuscene);
window.setHeight(600);
window.setWidth(800);
window.setTitle("Game Title");
window.show();
}
}
My MenuLeiste class
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class MenuLeiste {
public VBox sceneViewMenu() {
MenuBar menuBar = new MenuBar();
VBox menuBox = new VBox(menuBar);
Menu dataMenu = new Menu("Data");
MenuItem exitItem = new MenuItem("Exit");
exitItem.setOnAction(e -> System.exit(0));
Menu extrasMenu = new Menu("Extras");
MenuItem creditsItem = new MenuItem("Credits");
creditsItem.setOnAction(e -> {
Credits c = new Credits();
Scene scene3 = new Scene(c.sceneView3());
Stage window = (Stage) menuBox.getScene().getWindow();
window.setScene(scene3);
});
extrasMenu.getItems().addAll(creditsItem);
dataMenu.getItems().addAll( exitItem);
menuBar.getMenus().addAll(dataMenu,extrasMenu);
//the scenes layout is saved in layout1
VBox layout1 = new VBox(20);
layout1.getChildren().addAll(menuBox);
return layout1;
}
}
My Credits Class
package view;
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 Credits {
public VBox sceneView3()
{
Label label = new Label("Thanks");
Button backButton = new Button("Back");
backButton.setOnAction(e -> {
MenuLeiste l1 = new MenuLeiste();
Scene menuscene = new Scene(l1.sceneViewMenu());
Stage window = (Stage) backButton.getScene().getWindow();
window.setScene(menuscene);
});
VBox layout1 = new VBox(20);
layout1.getChildren().addAll(label, backButton);
return layout1;
}
}
When you want a node, or a group of nodes, to exist between different "scenes", often the best solution is to not replace the Scene. Instead, you'll want to modify the nodes displayed in the current scene. For example, in your case, you could have a BorderPane as the root of the scene with the MenuBar set as the top node. Then you replace the center node when you want to change the "view".
Here's a minimal runnable example demonstrating this concept. It makes use of "callbacks" to modify the center node of the BorderPane, while using the same MenuBar instance throughout. Though note the example only consists of views. If you have a backing model (i.e., data, business logic, etc.), you'll want to modify the code so you can pass it around. Also, if you write your application similarly to this example, it might be prudent to have all the views implement a common interface in a real application.
I don't have a separate "view class" for the menu bar, but that doesn't mean you can't have one (might even be better that way).
Main.java:
import java.util.function.Consumer;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
var root = new BorderPane();
root.setTop(createMenuBar(root::setCenter));
root.setCenter(new TitleView().getNode());
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.setTitle("Demo");
primaryStage.show();
}
private MenuBar createMenuBar(Consumer<Node> onUpdateView) {
var exitItem = new MenuItem("Exit");
exitItem.setOnAction(e -> Platform.exit());
var creditsItem = new MenuItem("Credits");
creditsItem.setOnAction(e -> {
e.consume();
var view = new CreditsView();
view.setOnGoBack(() -> onUpdateView.accept(new TitleView().getNode()));
onUpdateView.accept(view.getNode());
});
return new MenuBar(
new Menu("File", null, exitItem),
new Menu("Extras", null, creditsItem)
);
}
}
TitleView.java:
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
public class TitleView {
private Node node;
public Node getNode() {
if (node == null) {
node = new StackPane(new Label("Welcome!"));
}
return node;
}
}
CreditsView.java:
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
public class CreditsView {
private Runnable onGoBack;
private Node node;
public Node getNode() {
if (node == null) {
var stack = new StackPane();
stack.setPadding(new Insets(10));
var label = new Label("Credits View");
stack.getChildren().add(label);
var goBackBtn = new Button("Go back");
goBackBtn.setOnAction(e -> {
e.consume();
if (onGoBack != null) {
onGoBack.run();
}
});
stack.getChildren().add(goBackBtn);
StackPane.setAlignment(goBackBtn, Pos.TOP_LEFT);
node = stack;
}
return node;
}
public void setOnGoBack(Runnable action) {
onGoBack = action;
}
}
Here is some basic code that should be easy for a beginner to understand.
The main layout and the potential views to be displayed within it are created upfront.
A menu bar is placed at the top of the border pane in the main layout.
Menu items can be used to switch between views by setting the node to be currently displayed in the center of the border pane.
The existing views are reused rather than being recreated on each navigation.
You could not store references to existing views and create new views on each navigation if preferred.
The views themselves are just nodes, so the example could easily be adapted to use FXML because the output of the FXML loader is also a node. The same goes for anything else which may generate a node to be used as a view in this fashion.
Operation
The scene is initially displayed and the user clicks on the "View" menu to show the list of available views.
The user selects the "View Two" menu item and the second view is displayed. The application menu remains visible and can be used for future operations.
Sample Code
import javafx.application.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class ViewSwitcherApp extends Application {
private BorderPane layout;
private final Node viewOne = new ViewOne();
private final Node viewTwo = new ViewTwo();
#Override
public void start(Stage stage) throws Exception {
// View menu
MenuItem viewOneMenuItem = new MenuItem("View One");
viewOneMenuItem.setOnAction(e -> setView(viewOne));
MenuItem viewTwoMenuItem = new MenuItem("View Two");
viewTwoMenuItem.setOnAction(e -> setView(viewTwo));
Menu viewMenu = new Menu(
"View", null,
viewOneMenuItem, viewTwoMenuItem
);
// File menu
MenuItem exitMenuItem = new MenuItem("Exit");
exitMenuItem.setOnAction(e -> Platform.exit());
Menu fileMenu = new Menu(
"File", null,
exitMenuItem
);
MenuBar menuBar = new MenuBar(
fileMenu, viewMenu
);
menuBar.setMinSize(MenuBar.USE_PREF_SIZE, MenuBar.USE_PREF_SIZE);
// Layout scene
layout = new BorderPane();
layout.setTop(menuBar);
setView(viewOne);
stage.setScene(
new Scene(layout, 300, 200)
);
stage.show();
}
private void setView(Node view) {
layout.setCenter(view);
}
public static void main(String[] args) {
launch(args);
}
}
class ViewOne extends StackPane {
public ViewOne() {
setStyle("-fx-background-color: lightblue; -fx-font-size: 30px;");
getChildren().add(new Label("View One"));
}
}
class ViewTwo extends StackPane {
public ViewTwo() {
setStyle("-fx-background-color: cornsilk; -fx-font-size: 30px;");
getChildren().add(new Label("View Two"));
}
}
Related
I found a little bug in JavaFX TabPane, and am looking for a workaround. I am running JavaFX 13.0.1.
How it happens:
The TabPane's DragPolicy must be set to TabPane.TabDragPolicy.REORDER.
You can navigate between tabs via keyboard shortcuts CTRL + TAB & CTRL + SHIFT + TAB.
However, if I drag, say, the last tab to the very left and release it back to the position it was in (so that nothing should change), these keyboard shortcuts get messed up - no longer pointing to proper next/previous tabs.
You should be able to reproduce it simply with the following code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Test extends Application {
#Override
public void start(Stage primaryStage) {
TabPane tabPane = new TabPane();
tabPane.setTabDragPolicy(TabPane.TabDragPolicy.REORDER);
tabPane.getTabs().add(new Tab("First"));
tabPane.getTabs().add(new Tab("Second"));
tabPane.getTabs().add(new Tab("Third"));
tabPane.getTabs().add(new Tab("Fourth"));
tabPane.getTabs().add(new Tab("Fifth"));
StackPane root = new StackPane();
root.getChildren().add(tabPane);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("TabPane bug");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
An interesting bug. It appears TabPane.getTabs() returns a List which may or may not reflect the visual ordering of the tabs. But the navigation keys always rely on the getTabs() order, not the visual order.
One workaround is to use a Label as a graphic for each Tab, while leaving the Tab’s text as null. You can then keep the Tabs sorted properly yourself, by checking the visual position of each such Label.
import java.util.List;
import java.util.ArrayList;
import javafx.beans.Observable;
import javafx.geometry.Bounds;
import javafx.geometry.NodeOrientation;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TabDragTest2 extends Application {
private static Tab createTab(String title) {
Tab tab = new Tab();
tab.setGraphic(new Label(title));
return tab;
}
#Override
public void start(Stage primaryStage) {
TabPane tabPane = new TabPane();
tabPane.setTabDragPolicy(TabPane.TabDragPolicy.REORDER);
tabPane.getTabs().add(createTab("First"));
tabPane.getTabs().add(createTab("Second"));
tabPane.getTabs().add(createTab("Third"));
tabPane.getTabs().add(createTab("Fourth"));
tabPane.getTabs().add(createTab("Fifth"));
tabPane.getTabs().addListener((Observable o) -> {
List<Tab> tabs = new ArrayList<>(tabPane.getTabs());
NodeOrientation orientation = tabPane.getEffectiveNodeOrientation();
boolean ltr = orientation == NodeOrientation.LEFT_TO_RIGHT;
tabs.sort((t1, t2) -> {
Node title1 = t1.getGraphic();
Node title2 = t2.getGraphic();
Bounds title1Bounds =
title1.localToScene(title1.getLayoutBounds());
Bounds title2Bounds =
title2.localToScene(title2.getLayoutBounds());
if (tabPane.getSide().isHorizontal()) {
if (ltr) {
return Double.compare(
title1Bounds.getMinX(), title2Bounds.getMinX());
} else {
return Double.compare(
title2Bounds.getMaxX(), title1Bounds.getMaxX());
}
} else {
return Double.compare(
title1Bounds.getMinY(), title2Bounds.getMinY());
}
});
if (!tabPane.getTabs().equals(tabs)) {
Platform.runLater(() -> tabPane.getTabs().setAll(tabs));
}
});
StackPane root = new StackPane();
root.getChildren().add(tabPane);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("TabPane bug");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I have a Label and a ProgressBar in a GridPane.
I've registered an onMouseClicked-event handler on the GridPane.
If I click on the Label the handler gets triggered.
If I click on the ProgressBar the handler doesn't get triggered.
Why? How can I fix it?
package test;
import javafx.application.Application;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;
public class ProgressBarTestApplication extends Application {
#Override
public void start(Stage primaryStage) {
GridPane gridPane = new GridPane();
ColumnConstraints columnConstraints0 = new ColumnConstraints();
columnConstraints0.setHgrow(Priority.SOMETIMES);
ColumnConstraints columnConstraints1 = new ColumnConstraints();
columnConstraints1.setHgrow(Priority.NEVER);
gridPane.getColumnConstraints().addAll(columnConstraints0, columnConstraints1);
RowConstraints rowConstraints0 = new RowConstraints();
rowConstraints0.setVgrow(Priority.SOMETIMES);
gridPane.getRowConstraints().add(rowConstraints0);
Label someLabel = new Label("Some Label:");
ProgressBar progressBar = new ProgressBar();
progressBar.setPrefWidth(250.0d);
someLabel.setLabelFor(progressBar);
gridPane.add(someLabel, 0, 0);
gridPane.add(progressBar, 1, 0);
gridPane.setCursor(Cursor.HAND);
gridPane.setHgap(5.0d);
gridPane.setOnMouseClicked(event -> System.out.println("Clicked!"));
Scene scene = new Scene(gridPane, 350, 150);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
It would seem that the MouseEvent is being consumed. I had a quick look through the ProgressBar class and it would seem that the ProgressIndicatorSkin's BehaviourBase may be causing the event to be consumed.
A quick and dirty solution would be to set the mouse clicked EventHandler for the ProgressBar to re-fire the event to the GridPane:
progressBar.setOnMouseClicked(e -> gridPane.fireEvent(e));
or to work with any Parent node:
progressBar.setOnMouseClicked(e -> progressBar.getParent().fireEvent(e));
or subclass ProgressBar to automatically apply this behavior:
public class NoConsumeProgressBar extends ProgressBar {
public NoConsumeProgressBar() {
setOnMouseClicked(e -> {
Parent parent = getParent();
if (parent != null) {
parent.fireEvent(e);
}
});
}
}
As stated in the title, I have fxml files, I have a UI that is set up with three labels/buttons up top and the lower half of the window has a pane. Every time a label/button is clicked, the pane must switch to that corresponding fxml file. So in other words, the pane must always be in the same position, kind of like a tabbed layout but without tabs.
I know I can achieve this with just loading a new instance of an fxml file but, I want to avoid that because when a user click on a tab he previously was on, he should be able to see his earlier input.
I have some main.java that starts the program. Some controller.java that controls the UI when it is first loaded, and some fxml file corresponding to that initial view. How can I go about implementing this transition functionality? P.S. I am very novice at JavaFX.
Here is a MCVE of how you can achieve it.
It can of course be implemented using FXML :
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class StageTest extends Application{
private Pane pane1, pane2, mainPane;
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("Switch Panes");
Button button1 = new Button("Show Pane 1");
button1.setOnAction(e -> showPane1());
Button button2 = new Button("Show Pane 2");
button2.setOnAction(e -> showPane2());
HBox buttonsPane = new HBox(5.);
buttonsPane.getChildren().addAll(button1, button2);
pane1 = getPane("PANE ONE");
pane2 = getPane("PANE TWO");
mainPane = new StackPane(pane1);
BorderPane root = new BorderPane();
root.setTop(buttonsPane);
root.setCenter(mainPane);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
private void showPane1() {
mainPane.getChildren().clear();
mainPane.getChildren().add(pane1);
}
private void showPane2() {
mainPane.getChildren().clear();
mainPane.getChildren().add(pane2);
}
private Pane getPane(String txt) {
VBox pane = new VBox();
pane.getChildren().addAll(new TextArea(txt+" add text here: "));
return pane;
}
public static void main(String[] args) {
launch(args);
}
}
I have created a simple app to simulate dynamic node creation with JAVAFX.
This app has the ability to create a new window whenever user want it by clicking the "New" button.
User can add a new node which is TitledPane to the window by clicking "Add Task" button and then clicking "Add" button on the dialog window.
There are an unexpected behavior which I want to fix. This app is only add new node (TitledPane in this case) to the last created window.
And the all of the nodes on the previous window will vanish.
You can see the following video to better understand what I mean.
VIDEO
https://youtu.be/eaWmu3zuuhE
NETBEANS PROJECT
Just in case you want to play with it.
https://drive.google.com/file/d/0B4Sbb8Ym-lcZLUIyWHV5ZXRSZE0/view?usp=sharing
CODES:
TasksList.java
package taskslist;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.stage.Stage;
public class TasksList extends Application {
DisplayWhich display = new DisplayWhich();
Stage primaryStage;
Parent startWindow;
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
initStart();
}
private void initStart(){
display.showDialogWindow();
}
public static void main(String[] args) {
launch(args);
}
}
TheList.java
package taskslist.view;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import taskslist.DisplayWhich;
public class TheList extends BorderPane {
public static VBox listWrapper;
public static ScrollPane listScroller;
public ObservableList<TitledPane> tasks;
private List<String> titles = new ArrayList<>();
public TheList(){
tasks = FXCollections.observableArrayList();
listWrapper = new VBox(5);
listScroller = new ScrollPane(listWrapper);
}
public void setTitles(String... title){
titles = Arrays.asList(title);
}
public List<String> getTitles(){
return titles;
}
public void loadSavedList(){
for(int i=0; i<getTitles().size();i++){
String ttlString = getTitles().get(i);
this.createTask(ttlString);
}
// Display Tasks
listWrapper.getChildren().addAll(this.tasks);
}
// Dialong for adding a new task and also editing a task
private void addTaskDialog(){
GridPane container = new GridPane();
Scene scene = new Scene(container, 150, 50);
Stage addNewTask = new Stage();
addNewTask.initModality(Modality.APPLICATION_MODAL);
addNewTask.setTitle("Add Task");
TextField title = new TextField();
Button confirm = new Button("Add");
// Create Task
confirm.setOnAction((ev) -> {
String ttlString = title.getText();
this.createTask(ttlString);
listWrapper.getChildren().clear();
listWrapper.getChildren().addAll(this.tasks);
addNewTask.close();
});
container.add(title, 0, 1);
container.add(confirm, 0, 5);
addNewTask.setScene(scene);
addNewTask.showAndWait();
}
// Assemble all this.tasks list components
public void render(){
setCenter(listScroller);
loadSavedList();
Button newProject = new Button("New");
Button addTask = new Button("Add Task");
BorderPane listBottom = new BorderPane();
HBox bottomLeft = new HBox();
bottomLeft.getChildren().add(newProject);
listBottom.setLeft(bottomLeft);
HBox bottomRight = new HBox();
bottomRight.getChildren().add(addTask);
listBottom.setRight(bottomRight);
newProject.setOnAction((evt) -> {
DisplayWhich display = new DisplayWhich();
display.showDialogWindow();
});
addTask.setOnAction((e) -> {
addTaskDialog();
});
setBottom(listBottom);
}
// Cteate task from strings
private void createTask(String... strings){
String taskTitle = strings.length > 0 ? strings[0] : "";
TitledPane task = new TitledPane();
task.setPrefWidth(647);
task.setExpanded(false);
task.setText(taskTitle);
this.tasks.add(task);
}
}
NewDialog.java
package taskslist.view;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import taskslist.DisplayWhich;
public class NewDialog {
DisplayWhich display = new DisplayWhich();
Stage stage = new Stage();
Parent startWindow = new AnchorPane();
#FXML
private Button cancelNew;
#FXML
private Button confirmCreation;
/**
* Initializes the controller class.
*/
#FXML
private void initialize() {
}
#FXML
private void cancelNewCreation(ActionEvent event) {
((Stage)cancelNew.getScene().getWindow()).close();
}
#FXML
private void confirmCreateNew(ActionEvent event) {
((Stage)confirmCreation.getScene().getWindow()).close();
TheList wrap = new TheList();
TheWindow window = new TheWindow();
window.makeWindow(wrap);
wrap.setTitles("one", "two", "three", "four");
wrap.render();
}
}
DisplayWhich.java
package taskslist;
import java.io.IOException;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import taskslist.view.TheList;
public class DisplayWhich {
Stage stage = new Stage();
Parent startWindow = new AnchorPane();
public DisplayWhich(){}
public Stage showDialogWindow(){
try {
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle("Create New Project");
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/taskslist/view/newDialog.fxml"));
startWindow = loader.load();
Scene scene = new Scene(startWindow);
stage.setScene(scene);
stage.setOnCloseRequest((event) -> {
System.out.println("test");
});
stage.showAndWait();
} catch (IOException ex) {
ex.printStackTrace();
}
return stage;
}
}
TheWindow.java
package taskslist.view;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TheWindow {
public TheWindow(){}
public void makeWindow(BorderPane group) {
Stage mainWindow = new Stage();
Scene scene = new Scene(group, 650, 550);
mainWindow.setScene(scene);
mainWindow.setTitle("Task List");
mainWindow.centerOnScreen();
mainWindow.show();
}
}
Why that weird behavior happening and how to fix it so it only adds new node to the same window where the clicked "Add Task" button is located?
These fields should not be static:
public static VBox listWrapper;
public static ScrollPane listScroller;
How do I add lets say a label inside the first tab of a TabPane. I'm new with java fx but swing is totally different. I'm not familiar with the terminology. Is pane a JPanel essentially? or is a scene?
Here's my class, I'm trying to add a Table inside my tabs but I can't get it to appear.
import java.io.IOException;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
public class Viewer {
private Scene mainScene;
private MenuBar menubar;
private Menu menu;
private MenuItem menuItem, menuItem2, menuItem3;
private TableView table, table2;
private ScrollPane scroll;
private Pane npcPane, itemPane;
public Viewer() {
}
public Scene mainScene() {
BorderPane layout = new BorderPane();
BorderPane tabLayout = new BorderPane();
Label label = new Label("Test");
mainScene = new Scene(layout, 400, 600);
TabPane tabPane = new TabPane();
Tab tab = new Tab("Item");
tab.setClosable(false);
tab.setContent(tabLayout);
tabPane.getTabs().add(tab);
tabLayout.getChildren().add(label);
layout.setCenter(tabPane);
return mainScene;
}
private Node npcContent(){
BorderPane layout = new BorderPane();
npcPane = new Pane();
TableColumn<NPC, Integer> idColumn = new TableColumn<>("ID:");
idColumn.setMinWidth(100);
idColumn.setCellValueFactory(new PropertyValueFactory<>("id"));
TableColumn<NPC, String> nameColumn = new TableColumn<>("Name:");
nameColumn.setMinWidth(250);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
table = new TableView<NPC>();
table.setItems(getNpcs());
table.getColumns().addAll(idColumn, nameColumn);
scroll = new ScrollPane(table);
layout.setCenter(scroll);
return npcPane;
}
private Node itemContent() {
itemPane = new Pane();
TableColumn<Item, Integer> idColumn = new TableColumn<>("ID:");
idColumn.setMinWidth(100);
idColumn.setCellValueFactory(new PropertyValueFactory<>("id"));
TableColumn<Item, String> nameColumn = new TableColumn<>("Name:");
nameColumn.setMinWidth(250);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
table = new TableView<Item>();
table.setItems(getItems());
table.getColumns().addAll(idColumn, nameColumn);
scroll = new ScrollPane(table);
itemPane.getChildren().addAll(scroll);
itemPane.setMinSize(500, 500);
return itemPane;
}
public ObservableList<NPC> getNpcs() {
ObservableList<NPC> npcs = FXCollections.observableArrayList();
ReadFile readFile = new ReadFile("./lists/npclist.txt");
try {
String[] npcList = readFile.openNPCFile();
for(NPC npc : ReadFile.npcs) {
if (npc != null) {
npcs.add(new NPC(npc.getId(), npc.getName()));
}
}
} catch (IOException e) {
e.printStackTrace();
}
return npcs;
}
public ObservableList<Item> getItems() {
ObservableList<Item> items = FXCollections.observableArrayList();
ReadFile readFile = new ReadFile("./lists/itemlist.txt");
try {
String[] itemList = readFile.openNPCFile();
for(Item item : ReadFile.items) {
if (item != null) {
items.add(new Item(item.getId(), item.getName()));
}
}
} catch (IOException e) {
e.printStackTrace();
}
return items;
}
}
To answer your question your layout is the parent Node of your stage
mainScene = new Scene(layout, 400, 600);
and your tabPane is next in your Node hierarchy which is your layout child, by default the Borderpane computes this range based on its content - or the size of its children if not explicitly set, you never set the size of the BorderPane & Tabpane & Label you only set the size for your scene which your Stage will automatically use. so to solve your problem implement this method
Region.setPrefSize(width,height);
in every Node you have, so FX can know how to position your Node in its respective Parent
related quesion
hope it helps
Using tabobj.setContent(node); You Can Add Any Control or Layout into the tab.