1

I have a weird GUI problem. I'm using JavaFX to make an app. The app has different pages, each with a title, label, and tableView. Let's focus on the Welcome page. If I add just one tableView to my vbox, everything appears normal.

vbox.getChildren().addAll(title, subtitle, reqTable);

But when I add all three tableViews, the label below the title gets cut off. The tables are not even visible yet!

vbox.getChildren().addAll(title, subtitle, reqTable, tempTable, ontTable);

Any idea why this would happen? Here's my full code. Thanks!

package FLOOR;

// --- Imports
import javafx.application.Application;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

// --- Main Class
public class Example extends Application {

    // --- All Pages
    final Page[] pages = new Page[] {
        new Page("Welcome!",
                "Use the File menu to... \n"),
        };

    // --- All Tables
    TableView<ObservableList<StringProperty>> reqTable = new TableView<>();
    TableView<ObservableList<StringProperty>> tempTable = new TableView<>();
    TableView<ObservableList<StringProperty>> ontTable = new TableView<>();

    // --- Current Page
    final Label title = new Label();
    final Label subtitle = new Label();

    // --- Main
    public static void main(String[] args) {
        launch(args);
    }

    // --- Start
    @Override
    public void start(Stage stage) {
        // --- Stage & Scene
        stage.setTitle("APP");
        Scene scene = new Scene(new VBox(), 900, 500);
        MenuBar menuBar = new MenuBar();

        // --- VBox
        final VBox vbox = new VBox();
        vbox.setAlignment(Pos.CENTER);
        vbox.setSpacing(10);
        vbox.setPadding(new Insets(5, 20, 0, 20));
        vbox.getChildren().addAll(title, subtitle, reqTable, tempTable, ontTable);
        //vbox.getChildren().addAll(title, subtitle, reqTable);
        reqTable.setVisible(false);
        tempTable.setVisible(false);
        ontTable.setVisible(false);
        reqTable.setMinHeight(300);
        tempTable.setMinHeight(300);
        ontTable.setMinHeight(300);
        reqTable.translateYProperty().set(100);
        tempTable.translateYProperty().set(-100);
        ontTable.translateYProperty().set(-300);

        // --- Welcome Page
        title.setFont(new Font("Arial", 24));
        title.translateYProperty().set(10);
        title.setText(pages[0].title);
        subtitle.setText(pages[0].subtitle);
        subtitle.setMinHeight(10);

        // --- Menus 
        // --- File Menu
        // --- Import Submenu
        Menu menuFile = new Menu("File");
        Menu importMenu = new Menu("Import");
        MenuItem opt1 = new MenuItem("opt_1");
        MenuItem opt2 = new MenuItem("opt_2");
        MenuItem opt3 = new MenuItem("opt_3");
        importMenu.getItems().addAll(opt1, opt2, opt3);

        MenuItem export = new MenuItem("Export");
        MenuItem exit = new MenuItem("Exit");
        menuFile.getItems().addAll(importMenu, export, new SeparatorMenuItem(), exit);
        menuBar.getMenus().addAll(menuFile);

        // --- Show 
        ((VBox) scene.getRoot()).getChildren().addAll(menuBar, vbox);
        stage.setScene(scene);
        stage.show();
    }

    // Page Class
    private class Page {
        public String title;
        public String subtitle;
        public Page(String title, String subtitle) {
            this.title = title;
            this.subtitle = subtitle;
        }
    }
}
Ted
  • 45
  • 4

2 Answers2

1

Please modified code in this way and then check.

remove this line : subtitle.setMinHeight(10); or set : subtitle.setMinHeight(50);

subtitle.setMinHeight(50);
Keyur Bhanderi
  • 1,524
  • 1
  • 11
  • 17
0

This answer was written while Keyur was writing his. Keyur's answer is correct, but given I've written all this, I'll post it anyway :-)


The invisible table is not covering up the subtitle label.

You set the minimum height of the subtitle to 10:

subtitle.setMinHeight(10);

When there is not enough room to display everything in a layout region at the preferred size, then a layout pane will start reducing the size of items inside it until either everything fits of the minimum size is reached. This is what is happening here, the VBox layout manager is reducing the size of the subtitle to the minimum size you set.

If you remove the minimum height setting, then the subtitle label will not be truncated.

You can set the minimum height to the preferred height:

subtitle.setMinHeight(Control.USE_PREF_SIZE);

That is sometimes useful, but in this case is unnecessary (no setting at all for the minimum height is required here as the default behaviour of the VBox layout manager will allocate sufficient space to the label for it to be fully displayed vertically).

Invisible items still take up layout space even though you cannot see them. Imagine if your room had an invisible glass door and you tried to leave the room, you would hit your head. It would hurt. I've done that. It hurt.

If you also don't want the invisible node to take up layout space then you need to set it to unmanaged, see:


Other layout advice

Most of this is not directly related to your question, so feel free to ignore it. Just some background info.

You are already using a layout pane, which lays out items (the VBox). You should not set translate values for items placed in the layout pane. Translate values (translateX and translateY) are really supposed to just be for temporarily moving things around, for instance for a OS X box style bounce animation. Instead layout is supposed to be managed via layoutX and layoutY values. When you are using a layout manager, the layout manager is responsible for setting layoutX and layoutY values, so you shouldn't have to set any of the translate values or layout values.

Instead you place layout constraints on the layout manager for the nodes it manages. For instance for a VBox, to offset some items by a margin, you can use VBox.setMargin(node) instead of changing translate values. An issue with setting translate values is a layout manager will ignore them, so although you might move one node, the layout of the other managed nodes will not be automatically set correctly by the layout manager and you can get weird overlapping issues (though that wasn't the source of the issue you experienced here).

Gluon SceneBuilder is a good tool for learning more about JavaFX layout (even if you don't want to use FXML).

A good example for learning about layout is Layout sans tears. Unfortunately the example is a bit old and uses deprecated builder code, but the basic concepts are still valid and the ideas are easy enough to transfer into more modern code. Oracle also have a layout tutorial, but unfortunately it is far from comprehensive, in fact the word woeful comes to mind...

Scenic View is a great tool for understanding the layout of an app (and troubleshooting issues which might arise with it as you have here).

To prevent your content from getting sized smaller than its preferred size, you can put it in a ScrollPane and have the user scroll when the content overflows the available area (like a web page).

Community
  • 1
  • 1
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Thanks, jewelsea! I have learned a lot recently from your other comments, many relating to TextAreas and RichTextFX. – Ted Apr 05 '17 at 01:21
  • Hi again @jewelsea. I knew this wasn't the right way to manage the layout. I'm trying to display certain information in a tableView, based on what menuItem the user clicks. I couldn't find anything that would work for having just one tableView, and re-filling it with the data I want each time. So I went with the multi-table approach and showing/hiding them. Any thoughts on how to make it a cleaner, one-tableView solution? – Ted Apr 05 '17 at 01:28