gpt4 book ai didi

JavaFx - tableView 中的 String 和 FlowPane (行?)?

转载 作者:行者123 更新时间:2023-12-02 09:36:16 32 4
gpt4 key购买 nike

我目前正在尝试实现以下内容:

  • 一个以 ObservableList 作为数据集的 TableView,有两列,每列包含字符串(玩家姓名)。这部分很简单。

  • 单击玩家(名称)后,应在所选玩家下方注入(inject)自定义 FlowPane。如果单击另一个玩家,则流程 Pane 应该消失并注入(inject)到当前单击的玩家下方。

下面的代码实现了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_D 的 ExpandingTableRow,就显示所选 TableRow 下方的 FlowPane 而言,它工作得很好。我还设法更改了我的数据结构,以便每列现在显示不同的玩家,而不是每列中的相同玩家。

但是,创建的 FlowPane 实际上应该取决于在行中单击的实际玩家(单元格)。在 James 的示例中:如果选择了 FirstName 或 LastName(即使对于同一行),将会创建一个不同的 FlowPane。 FlowPane 应以相同的方式显示 - 在所选行下方 - 但它是一个不同,新的 FlowPane 取决于是否单击了 FirstName,或者是否单击了 LastName。我怎样才能做到这一点?

我考虑过使用:

table.getSelectionModel().setCellSelectionEnabled(true);

但这实际上似乎禁用了 James_d 的解决方案。

最佳答案

此解决方案仅适用于 Java 9 及更高版本。

行的显示由 TableRow 管理,该行的实际布局由其外观(TableRowSkin)执行。因此,要管理此问题,您需要安装自定义外观的 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);
}
}

正如您所看到的,可能需要对样式和尺寸进行一些改进才能使其做好生产准备,但这表明了可行的方法。

enter image description here

关于JavaFx - tableView 中的 String 和 FlowPane (行?)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49158338/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com