为啥一个不可见的 TableView 会覆盖一个标签?

Posted

技术标签:

【中文标题】为啥一个不可见的 TableView 会覆盖一个标签?【英文标题】:Why is an invisible TableView covering up a label?为什么一个不可见的 TableView 会覆盖一个标签? 【发布时间】:2017-08-29 04:09:06 【问题描述】:

我有一个奇怪的 GUI 问题。我正在使用 JavaFX 制作应用程序。该应用程序有不同的页面,每个页面都有标题、标签和 tableView。让我们关注欢迎页面。如果我只在我的 vbox 中添加一个 tableView,一切看起来都很正常。

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

但是当我添加所有三个 tableView 时,标题下方的标签会被截断。桌子甚至还看不见!

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

知道为什么会发生这种情况吗?这是我的完整代码。谢谢!

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;
        
    

【问题讨论】:

【参考方案1】:

请以这种方式修改代码,然后检查。

删除这一行:subtitle.setMinHeight(10);或设置:subtitle.setMinHeight(50);

subtitle.setMinHeight(50);

【讨论】:

【参考方案2】:

这个答案是在 Keyur 写他的时候写的。 Keyur 的回答是正确的,但鉴于我已经写了所有这些,我还是会发布它:-)


隐形表格没有遮住字幕标签。

您将字幕的最小高度设置为 10:

subtitle.setMinHeight(10);

当没有足够的空间以首选大小显示布局区域中的所有内容时,布局窗格将开始减小其中的项目大小,直到所有内容都达到最小大小为止。这就是这里发生的事情,VBox 布局管理器正在将字幕的大小减小到您设置的最小大小。

如果去掉最小高度设置,那么字幕标签不会被截断。

您可以将最小高度设置为首选高度:

subtitle.setMinHeight(Control.USE_PREF_SIZE);

这有时很有用,但在这种情况下是不必要的(这里根本不需要设置最小高度,因为 VBox 布局管理器的默认行为将为标签分配足够的空间以使其垂直完全显示) .

即使您看不到它们,不可见的项目仍会占用布局空间。想象一下,如果你的房间有一扇看不见的玻璃门,而你试图离开房间,你会撞到自己的头。会很痛。我已经做到了。很痛。

如果您也不希望不可见节点占用布局空间,则需要将其设置为非托管,请参阅:

JavaFX - setVisible doesn't "hide" the element

其他布局建议

其中大部分内容与您的问题没有直接关系,因此请随意忽略它。只是一些背景信息。

您已经在使用布局窗格,用于对项目(VBox)进行布局。您不应为放置在布局窗格中的项目设置翻译值。翻译值(translateX 和 translateY)实际上应该只是用于临时移动物体,例如用于 OS X 框式弹跳动画。相反,布局应该通过 layoutX 和 layoutY 值进行管理。当您使用布局管理器时,布局管理器负责设置 layoutX 和 layoutY 值,因此您不必设置任何翻译值或布局值。

相反,您在布局管理器上为其管理的节点放置布局约束。例如对于 VBox,要偏移一些项目边距,您可以使用 VBox.setMargin(node) 而不是更改翻译值。设置翻译值的一个问题是布局管理器会忽略它们,因此尽管您可能会移动一个节点,但布局管理器不会自动正确设置其他托管节点的布局,并且您可能会遇到奇怪的重叠问题(尽管那是不是您在这里遇到的问题的根源)。

Gluon SceneBuilder 是了解更多有关 JavaFX 布局的好工具(即使您不想使用 FXML)。

了解布局的一个很好的例子是Layout sans tears。不幸的是,这个例子有点老了,并且使用了不推荐使用的构建器代码,但基本概念仍然有效,并且这些想法很容易转移到更现代的代码中。 oracle也有layout tutorial,可惜还不够全面,其实想到woeful这个词...

Scenic View 是一个很好的工具,可以帮助您了解应用程序的布局(以及解决可能出现的问题,就像您在这里一样)。

为防止您的内容变得小于其首选大小,您可以将其放在ScrollPane 中,并在内容溢出可用区域(如网页)时让用户滚动。

【讨论】:

谢谢,jewelsea!我最近从您的其他 cmets 中学到了很多东西,其中许多与 TextAreas 和 RichTextFX 有关。 你好@jewelsea。我知道这不是管理布局的正确方法。我正在尝试根据用户单击的 menuItem 在 tableView 中显示某些信息。我找不到任何适用于只有一个 tableView 的东西,并且每次都用我想要的数据重新填充它。所以我采用了多表方法并显示/隐藏它们。关于如何使其成为更清洁的单表视图解决方案的任何想法?

以上是关于为啥一个不可见的 TableView 会覆盖一个标签?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 detailTextLabel 不可见?

为啥每次我更改视图并返回它时我的数组都会覆盖自身 - swift 3

Tableview最后一个单元格使用滚动视图iOS不可见

为啥我的 tableView 不向下滚动就不会更新?

UIButton 在 TableView 单元格中不可见

我的tableview单元格上的组件不可见