假设我有以下布局:
<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
答案 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但我在图形应用程序中测量它并按预期放置和调整尺寸。
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]