我有一个带自定义单元工厂的ListView。我在单元格minWidth上计算最大值,并将其设置为整个ListView的minWidth。因此,布局中受其他区域约束的ListView会缩小到minWidth。但它所拥有的细胞大小调整为首选宽度,而不是最小。因此,节点不适合包含视口,并显示水平滚动条。
这很讨厌。我想让每个单元格完全适合ListView,并摆脱滚动条。更确切。当ListView减小到最小宽度时,其所有单元格也应减小到这个最小宽度。
我正在寻找一些控制属性来切换一些黑客的单元大小调整策略,以便在没有预定义开关的情况下实现所描述的行为。
更新:添加了图片示例
我创建了SplitPane来简化测试布局。我可以通过用鼠标移动它的分隔符来定义布局限制。
第一个镜头显示了初始问题:不遵守单元节点的实际尺寸(min,max,pref)。 ListView始终使用prefWidth,即使它大于视口宽度。因此,可以避免使用水平滚动。
之后我尝试手动设置首选宽度更小。所以细胞现在完全可见。这不是解决方案。我给出这个镜头来证明单元格具有足够小的minWidth以适合ListView。
最后一枪也是丑陋的。它留下了可能充满细胞内容的自由空间。这很自然:如果视口大于首选宽度且小于最大宽度,则应该用于调整单元格内容的大小。
可以通过切换到显式指定的静态大小的元素来抑制该问题。但这样做意味着放弃动态布局的所有好处:程序员每次使用CSS应用新皮肤时都必须更改大小常量,并禁止用户调整窗口大小或使用鼠标移动分隔符。
这也是一个糟糕的解决方案。我需要什么 - 使javafx的布局引擎工作。 ListView的最小宽度应该是其单元格的最小最小宽度。 ListView的最大宽度应该是其单元格的最大最大宽度。 ListView的首选宽度应该是其单元格的最大首选宽度。并且ListView的实际宽度应该由其父(本例中的SplitPane)设置,并且与所有三个布局边界相关。之后,这个大小应该传递给细胞。
仅当某些单元格的最小宽度太大而无法放入视口时,才会显示水平滚动条。
答案 0 :(得分:2)
只需将单元格prefWidthProperty
绑定到ListView的widthProperty
即可。我为边界等减去了一点。
使用字符串,您将获得省略号...而不是滚动条。
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class CellSize extends Application {
@Override
public void start(Stage stage) {
ObservableList<String> items = FXCollections.observableArrayList(
"hello world", "This is a test", "this is not a drill","vroom...this IS a drill");
ListView<String> lv = new ListView(items);
final VBox leftBox = new VBox(lv,new Button("Unused"));
lv.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
@Override
public ListCell<String> call(ListView<String> param) {
ListCell lc = new ListCell<String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
setGraphic(null);
if (item == null) setText("null");
else {
setText(item);
double minWidth = 5 * item.length();
double maxWidth = 10 * item.length();
leftBox.setMinWidth(Math.max(minWidth, leftBox.getMinWidth()));
leftBox.setMaxWidth(maxWidth);
}
}
}
};
lc.prefWidthProperty().bind(lv.widthProperty().subtract(4));
return lc;
}
});
SplitPane root = new SplitPane();
root.getItems().addAll(leftBox,new VBox(new Label("Hello")));
Scene scene = new Scene(root, 300, 250);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}