当托管为false时,使组件可见

时间:2015-10-14 14:51:07

标签: listview javafx

假设我有以下布局:

<VBox xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <TextField fx:id="textField" />
      <ListView fx:id="list" visible="true" />
   </children>
</VBox>

只要我调用listView.setManaged(false),无论我设置哪种布局属性,ListView都是不可见的。也许我错过了一些。

为了查看具有这些样本值的ListView,我必须设置哪些属性:
左= 100
顶部= 200
宽度= 300
高度= 400

1 个答案:

答案 0 :(得分:1)

解决方案

将ListView包装在非托管容器中。任何容器都可以,例如,Group或任何Pane或Pane子类。不要将ListView本身设置为不受管理。

背景

在此上下文中未受管理,表示在容器节点上显式调用setManaged(false)。这意味着对节点禁用自动布局,并且用户应用程序代码必须显式管理布局属性(例如节点大小和宽度以及请求非托管节点的子级的自动布局)。所以矛盾的是你的应用程序代码必须明确地管理容器布局。

如果你使ListView本身不受管理,我的猜测(这只是一个猜测)是这打破了ListView的内部布局算法并阻止ListView正确显示,因为ListView中的组件可能期望ListView本身要管理。

当你将ListView放在另一个非托管的容器中时,ListView本身仍然在内部进行管理,其布局不会中断,但布局与场景的常规布局不相交,非托管容器成为根的ListView的布局。这样,您可以手动设置非托管容器(及其子容器)的位置和首选大小,从而有效地实现了为ListView提供应用程序托管布局的目标。

适用性

我注意到其他控件(如TextField)的行为相同,因此这可能是一种通用模式,可用于任何控件的非托管显示。

另请注意,此请求有点不寻常。对于大多数应用程序,不需要非托管控件。内置布局管理器可以处理各种布局需求。当需要自定义布局时,方法是创建自定义布局管理器(例如,新的Pane子类)并覆盖layoutChildren()和computePrefHeight / computePrefWidth / computeMinHeight / computeMinWidth方法。这允许您的应用程序或组件以友好的方式与自动JavaFX布局系统进行交互。有关此类功能样式的示例,请查看内置布局管理器的代码,例如StackPane

示例

这是一个示例应用程序,用于演示这些原则,并在您的问题中实现为ListView规定的大小和放置目标。我将屏幕截图的大小调整为一半,因此不会占用太多空间。测量结果有点具有欺骗性,因为它看起来不像列表放置在100,200,尺寸为300,400但我在图形应用程序中测量它并按预期放置和调整尺寸。

unmanaged

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Unmanageable extends Application {
    @Override
    public void start(final Stage stage) throws Exception {
        TextField textField = new TextField();

        ListView<String> listView = new ListView<>();
        listView.getItems().addAll("Sally", "Sells", "Seashells", "At", "The", "Seashore");
        listView.setStyle("-fx-base: lightcoral;");

        Group unmanagedContainer = new Group(listView);
        unmanagedContainer.setManaged(false);
        unmanagedContainer.relocate(100, 200);

        listView.setMinSize(ListView.USE_PREF_SIZE, ListView.USE_PREF_SIZE);
        listView.setPrefSize(300, 400);
        listView.setMaxSize(ListView.USE_PREF_SIZE, ListView.USE_PREF_SIZE);

        VBox layout = new VBox(textField, unmanagedContainer);
        layout.setMinSize(600, 800);
        layout.setStyle("-fx-background-color: azure;");

        stage.setScene(new Scene(layout));
        stage.show();

        System.out.println(unmanagedContainer.getBoundsInParent());
    }

    public static void main(String[] args) throws Exception {
        launch(args);
    }
}

输出:

BoundingBox [minX:100.0, minY:200.0, minZ:0.0, width:300.0, height:400.0, depth:0.0, maxX:400.0, maxY:600.0, maxZ:0.0]