我目前正在尝试实现以下内容:
>
以ObservableList作为数据集的TableView,有两列,每列都包含字符串(播放器的名称)。这部分很简单。
单击播放器(名称)后,应在选定播放器下方注入自定义FlowPane。如果单击另一个播放器,则流窗格应消失并注入当前单击的播放器下方。
下面的代码实现了TableView(减去鼠标侦听器部分)。请帮我让FlowPane跨越整行。我猜我需要一个RowFactory,但不知道如何让它为我的目的工作:)
另外,显然我的两列现在显示相同的数据。令人困惑的是:)有没有办法告诉一列使用一半的数据集,另一列使用另一半?我显然不希望我的数据显示两次。
public class main extends Application
{
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage stage) throws Exception
{
try
{
FlowPane f = new FlowPane();
Scene scene = new Scene(f, 300, 200);
Player p1 = new Player("player 1 ");
Player p2 = new Player("player 2 ");
Player p3 = new Player("player 3 ");
ArrayList<Object> players = new ArrayList<>();
players.add(p1);
players.add(p2);
players.add(p3);
ObservableList<Object> observableList = FXCollections.observableArrayList(players);
TableView<Object> table = createTableView(observableList, 300, 200);
f.getChildren().add(table);
injectFlowPane(table);
stage.setScene(scene);
stage.show();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public TableView<Object> createTableView(ObservableList<Object> items, double width, double height)
{
TableView<Object> table = new TableView<>();
table.setItems(items);
table.getColumns().add(createTableColumn(width / 2));
table.getColumns().add(createTableColumn(width / 2));
table.setMinSize(width, height);
table.setPrefSize(width, height);
table.setMaxSize(width, height);
return table;
}
private TableColumn<Object, Object> createTableColumn(double width)
{
TableColumn<Object, Object> tableColumn = new TableColumn<>();
tableColumn.setCellFactory(
new Callback<TableColumn<Object, Object>, TableCell<Object, Object>>() {
@Override
public TableCell<Object, Object> call(TableColumn<Object, Object> arg0)
{
return new PlayerCell();
}
});
tableColumn.setCellValueFactory(cellDataFeatures -> {
Object item = cellDataFeatures.getValue();
return new SimpleObjectProperty<>(item);
});
tableColumn.setMinWidth(width);
return tableColumn;
}
private void injectFlowPane(TableView<Object> table)
{
FlowPane f = new FlowPane();
f.setMinSize(50, 50);
f.setBackground(new Background(new BackgroundFill(Color.DARKGREEN, CornerRadii.EMPTY, Insets.EMPTY)));
table.getItems().add(1, f);
}
}
public class PlayerCell extends TableCell<Object, Object>
{
@Override
protected void updateItem(Object item, boolean empty)
{
super.updateItem(item, false);
// if (empty)
if (item != null)
{
if (item instanceof Player)
{
setText(((Player) item).getName());
setGraphic(null);
}
else if (item instanceof FlowPane)
{
setGraphic((FlowPane) item);
}
else
{
setText("N/A");
setGraphic(null);
}
}
else
{
setText(null);
setGraphic(null);
}
}
}
public class Player
{
private String name;
public Player(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
编辑:
我现在已经实现了James\u D的ExpandingTableRow,它可以灵活地显示所选TableRow下面的流程窗格。我还设法改变了我的数据结构,使每一列现在显示不同的玩家,而不是每一列中的相同玩家。
但是,创建的FlowPane实际上应该取决于在行中单击的实际玩家(单元格)。在James的示例中:如果选择了FirstName或LastName,则会创建不同的FlowPane(即使对于同一行)。FlowPane应该以相同的方式显示——在选定行的下方——但它是一个不同的新FlowPane,具体取决于是否单击了FirstName,或者是否单击了LastName。我如何才能做到这一点?
我已经研究了如何使用:
table.getSelectionModel().setCellSelectionEnabled(true);
但这实际上似乎禁用了James\u d的解决方案。
此解决方案仅适用于Java9及更高版本。
行的显示由TableRow
管理,该行的实际布局由其皮肤(aTableRowSkin
)执行。因此,要管理它,您需要TableRow
的子类来安装自定义皮肤。
行实现非常简单:在此示例中,我添加了一个属性,用于在选择行时显示“附加内容”。它还覆盖了createDefaultSkin()
方法以指定自定义皮肤实现。
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Node;
import javafx.scene.control.Skin;
import javafx.scene.control.TableRow;
public class ExpandingTableRow<T> extends TableRow<T> {
private final ObjectProperty<Node> selectedRowContent = new SimpleObjectProperty<>();
public final ObjectProperty<Node> selectedRowContentProperty() {
return this.selectedRowContent;
}
public final Node getSelectedRowContent() {
return this.selectedRowContentProperty().get();
}
public final void setSelectedRowContent(final Node selectedRowContent) {
this.selectedRowContentProperty().set(selectedRowContent);
}
public ExpandingTableRow(Node selectedRowContent) {
super();
setSelectedRowContent(selectedRowContent);
}
public ExpandingTableRow() {
this(null);
}
@Override
protected Skin<?> createDefaultSkin() {
return new ExpandingTableRowSkin<T>(this);
}
}
皮肤实现必须完成布局工作。它需要重写计算高度的方法,如果需要,考虑额外内容的高度;如果需要,它需要重写layoutChildren()方法来定位额外内容。最后,它必须管理附加内容,如果行的选定状态更改(或附加内容本身更改),则添加或删除附加内容。
import javafx.scene.control.skin.TableRowSkin;
public class ExpandingTableRowSkin<T> extends TableRowSkin<T> {
private ExpandingTableRow<T> row;
public ExpandingTableRowSkin(ExpandingTableRow<T> row) {
super(row);
this.row = row;
row.selectedRowContentProperty().addListener((obs, oldContent, newContent) -> {
if (oldContent != null) {
getChildren().remove(oldContent);
}
if (newContent != null && row.isSelected()) {
getChildren().add(newContent);
}
if (row.getTableView() != null) {
row.getTableView().requestLayout();
}
});
row.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected && row.getSelectedRowContent() != null
&& !getChildren().contains(row.getSelectedRowContent())) {
getChildren().add(row.getSelectedRowContent());
} else {
getChildren().remove(row.getSelectedRowContent());
}
});
}
@Override
protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset,
double leftInset) {
if (row.isSelected() && row.getSelectedRowContent() != null) {
return super.computeMaxHeight(width, topInset, rightInset, bottomInset, leftInset)
+ row.getSelectedRowContent().maxHeight(width);
}
return super.computeMaxHeight(width, topInset, rightInset, bottomInset, leftInset);
}
@Override
protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset,
double leftInset) {
if (row.isSelected() && row.getSelectedRowContent() != null) {
return super.computeMinHeight(width, topInset, rightInset, bottomInset, leftInset)
+ row.getSelectedRowContent().minHeight(width);
}
return super.computeMinHeight(width, topInset, rightInset, bottomInset, leftInset);
}
@Override
protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset,
double leftInset) {
if (row.isSelected() && row.getSelectedRowContent() != null) {
return super.computePrefHeight(width, topInset, rightInset, bottomInset, leftInset)
+ row.getSelectedRowContent().prefHeight(width);
}
return super.computePrefHeight(width, topInset, rightInset, bottomInset, leftInset);
}
@Override
protected void layoutChildren(double x, double y, double w, double h) {
if (row.isSelected()) {
double rowHeight = super.computePrefHeight(w, snappedTopInset(), snappedRightInset(), snappedBottomInset(),
snappedLeftInset());
super.layoutChildren(x, y, w, rowHeight);
row.getSelectedRowContent().resizeRelocate(x, y + rowHeight, w, h - rowHeight);
} else {
super.layoutChildren(x, y, w, h);
}
}
}
最后是一个测试(使用Oracle的常见示例或其版本):
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class ExpandingTableRowTest extends Application {
@Override
public void start(Stage primaryStage) {
TableView<Person> table = new TableView<>();
table.getColumns().add(column("First Name", Person::firstNameProperty));
table.getColumns().add(column("Last Name", Person::lastNameProperty));
table.setRowFactory(tv -> {
Label label = new Label();
FlowPane flowPane = new FlowPane(label);
TableRow<Person> row = new ExpandingTableRow<>(flowPane) {
@Override
protected void updateItem(Person person, boolean empty) {
super.updateItem(person, empty);
if (empty) {
label.setText(null);
} else {
label.setText(String.format("Some additional information about %s %s here",
person.getFirstName(), person.getLastName()));
}
}
};
return row;
});
table.getItems().addAll(
new Person("Jacob", "Smith"),
new Person("Isabella", "Johnson"),
new Person("Ethan", "Williams"),
new Person("Emma", "Jones"),
new Person("Michael", "Brown")
);
Scene scene = new Scene(table);
primaryStage.setScene(scene);
primaryStage.show();
}
private static <S, T> TableColumn<S, T> column(String title, Function<S, ObservableValue<T>> property) {
TableColumn<S, T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
return col;
}
public static class Person {
private final StringProperty firstName = new SimpleStringProperty();
private final StringProperty lastName = new SimpleStringProperty();
public Person(String firstName, String lastName) {
setFirstName(firstName);
setLastName(lastName);
}
public final StringProperty firstNameProperty() {
return this.firstName;
}
public final String getFirstName() {
return this.firstNameProperty().get();
}
public final void setFirstName(final String firstName) {
this.firstNameProperty().set(firstName);
}
public final StringProperty lastNameProperty() {
return this.lastName;
}
public final String getLastName() {
return this.lastNameProperty().get();
}
public final void setLastName(final String lastName) {
this.lastNameProperty().set(lastName);
}
}
public static void main(String[] args) {
launch(args);
}
}
如您所见,可能需要对样式和大小进行一些细化才能使其准备好生产,但这显示了可行的方法。
我当前的代码如下所示: 注意:STable是一个包含每个列的所有setter和getter的类,我还设置了CellFactory。 任何关于如何做到这一点的指导都将是伟大的!
问题内容: 我想填充与 我只有两列。我做不到 到目前为止,我尝试过的是: 桌上什么也没显示。但是当我进行打印时,我看到的是我添加的数据。但是在桌子上什么也没显示。 我创建列如下: 我在Internet上看到了一些示例,这些示例中创建了一个对象来填充对象,但我不想仅为表视图创建类。还有其他可行的方法吗? 编辑: 我只想拥有这样的东西: 问题答案: 首先,您必须在FXML文件或代码中创建table’c
我有一个问题,我不能从一个对象加载3个属性显示在表视图上。我有一个付款对象,它由一个受益人对象(包括3个字符串-name、accountnumber和code)、一个金额字符串和一个引用字符串组成。如果这些项目都是同一个对象的一部分,我可以查看它们,但是当我将它们拆分时,它不会引起问题,并且单元格是空的。 每次我尝试将付款加载到tableView时,只有金额和引用是可见的。我尝试使用Propert
我刚启动JavaFx,有点拘泥于TableView,它显示了每个列的非常长的字符串表示,如: 而我预计细胞中只会出现“大”、“5000”、“3000”。 这是我的模型: fxml: 最后是控制器: 看起来控制器很好,它能够从数据库中获取值并向TableView添加行,但为什么TableView显示属性对象的字符串表示,而不仅仅是显示值? 非常感谢!
getter称为getShowName()、getEpsWatched()和getShowStatus(),它们获得变量showName、epsWatched和showStatus。 这里怎么了?显示字符串,但不显示int。
我是JavaFX的新手,我正在尝试将旧的Swing应用程序重构为JavaFX应用程序。 我还使用JPA(带有EclipseLink实现)来保存/检索数据。 所以我定义了一些带注释的POJO。 下面是我的注释POJO: TableViewControl有些问题: null