I have a ListView with some Labels in it. The labels' width property is bound to the width property of the ListView but they seem to be slightly larger meaning that a horizontal scrollbar is shown on the list view. What I want is to fit the labels in the list view without the scrollbar on the bottom. I have looked at various padding and insets values on both the label and the list view but none I have found are the culprit (most are zero).
我有一个带有一些标签的ListView。标签的width属性绑定到ListView的width属性,但它们似乎略大,这意味着列表视图上会显示水平滚动条。我想要的是在列表视图中放置标签,而底部没有滚动条。我在标签和列表视图中查看了各种填充和插入值,但我找不到的是罪魁祸首(大多数为零)。
Here is an example which demonstrates the problem.
这是一个演示问题的例子。
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
public class ListViewScrollExample extends Application {
private ListView<Node> listView;
@Override
public void start(Stage stage) throws Exception {
listView = new ListView<>();
addItem("Some quite long string to demonstrate the problem");
Scene scene = new Scene(listView);
stage.setScene(scene);
stage.show();
}
public void addItem(String item) {
Label label = new Label(item);
label.setWrapText(true);
label.maxWidthProperty().bind(listView.widthProperty());
listView.getItems().add(label);
}
public static void main(String[] args){
Application.launch(args);
}
}
2 个解决方案
#1
3
The default CSS file adds padding to a ListCell
(line 2316 in the current release):
默认CSS文件将填充添加到ListCell(当前版本中的第2316行):
.list-cell {
-fx-padding: 0.25em 0.583em 0.25em 0.583em; /* 3 7 3 7 */
}
It generally a bad idea to use Node
instances as the data backing a ListView
: you should use String
in this example, and use the cell factory to create a label displaying the string that is configured as you need. The following seems to work for your example:
使用Node实例作为支持ListView的数据通常是一个坏主意:在此示例中应使用String,并使用单元工厂创建一个标签,显示根据需要配置的字符串。以下似乎适用于您的示例:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
public class ListViewScrollExample extends Application {
private ListView<String> listView;
@Override
public void start(Stage stage) throws Exception {
listView = new ListView<>();
listView.getItems().add("Some quite long string to demonstrate the problem");
listView.setCellFactory(lv -> {
ListCell<String> cell = new ListCell<String>() {
private Label label = new Label();
{
label.setWrapText(true);
label.maxWidthProperty().bind(Bindings.createDoubleBinding(
() -> getWidth() - getPadding().getLeft() - getPadding().getRight() - 1,
widthProperty(), paddingProperty()));
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
label.setText(item);
setGraphic(label);
}
}
};
return cell ;
});
Scene scene = new Scene(listView);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args){
Application.launch(args);
}
}
Here I created a list cell that displays a label as its graphic, with the text of the label set to the string to be displayed. The constructor for the cell binds the label's max width to the width of the cell, less any space required for padding. The call to setContentDisplay(ContentDisplay.GRAPHIC_ONLY)
appears necessary, so the cell doesn't try to allocate any space for text.
在这里,我创建了一个列表单元格,将标签显示为图形,标签文本设置为要显示的字符串。单元格的构造函数将标签的最大宽度绑定到单元格的宽度,减去填充所需的任何空间。必须调用setContentDisplay(ContentDisplay.GRAPHIC_ONLY),因此单元格不会尝试为文本分配任何空间。
It may be possible to do this by setting the text directly on the list cell and calling setWrapText(true)
on the cell (which is, after all, also a subclass of Labeled
), but I couldn't get it to work this way.
有可能通过直接在列表单元格上设置文本并在单元格上调用setWrapText(true)来实现这一点(毕竟,这也是Labeled的子类),但我无法通过这种方式工作。
#2
-1
I couldn't replicate the problem but you can try the following instead of label.maxWidthProperty().bind(listView.widthProperty());
我无法复制问题,但你可以尝试以下代替label.maxWidthProperty()。bind(listView.widthProperty());
double i = Double.parseDouble(listView.widthProperty().toString());
label.setMaxWidth((i-2.0));
You can change the 2.0 to any pixel count you need to alter the screen by.
您可以将2.0更改为更改屏幕所需的任何像素数。
#1
3
The default CSS file adds padding to a ListCell
(line 2316 in the current release):
默认CSS文件将填充添加到ListCell(当前版本中的第2316行):
.list-cell {
-fx-padding: 0.25em 0.583em 0.25em 0.583em; /* 3 7 3 7 */
}
It generally a bad idea to use Node
instances as the data backing a ListView
: you should use String
in this example, and use the cell factory to create a label displaying the string that is configured as you need. The following seems to work for your example:
使用Node实例作为支持ListView的数据通常是一个坏主意:在此示例中应使用String,并使用单元工厂创建一个标签,显示根据需要配置的字符串。以下似乎适用于您的示例:
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
public class ListViewScrollExample extends Application {
private ListView<String> listView;
@Override
public void start(Stage stage) throws Exception {
listView = new ListView<>();
listView.getItems().add("Some quite long string to demonstrate the problem");
listView.setCellFactory(lv -> {
ListCell<String> cell = new ListCell<String>() {
private Label label = new Label();
{
label.setWrapText(true);
label.maxWidthProperty().bind(Bindings.createDoubleBinding(
() -> getWidth() - getPadding().getLeft() - getPadding().getRight() - 1,
widthProperty(), paddingProperty()));
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
label.setText(item);
setGraphic(label);
}
}
};
return cell ;
});
Scene scene = new Scene(listView);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args){
Application.launch(args);
}
}
Here I created a list cell that displays a label as its graphic, with the text of the label set to the string to be displayed. The constructor for the cell binds the label's max width to the width of the cell, less any space required for padding. The call to setContentDisplay(ContentDisplay.GRAPHIC_ONLY)
appears necessary, so the cell doesn't try to allocate any space for text.
在这里,我创建了一个列表单元格,将标签显示为图形,标签文本设置为要显示的字符串。单元格的构造函数将标签的最大宽度绑定到单元格的宽度,减去填充所需的任何空间。必须调用setContentDisplay(ContentDisplay.GRAPHIC_ONLY),因此单元格不会尝试为文本分配任何空间。
It may be possible to do this by setting the text directly on the list cell and calling setWrapText(true)
on the cell (which is, after all, also a subclass of Labeled
), but I couldn't get it to work this way.
有可能通过直接在列表单元格上设置文本并在单元格上调用setWrapText(true)来实现这一点(毕竟,这也是Labeled的子类),但我无法通过这种方式工作。
#2
-1
I couldn't replicate the problem but you can try the following instead of label.maxWidthProperty().bind(listView.widthProperty());
我无法复制问题,但你可以尝试以下代替label.maxWidthProperty()。bind(listView.widthProperty());
double i = Double.parseDouble(listView.widthProperty().toString());
label.setMaxWidth((i-2.0));
You can change the 2.0 to any pixel count you need to alter the screen by.
您可以将2.0更改为更改屏幕所需的任何像素数。