我的问题是如何在第一列中使用tableRow的索引在JavaFX中创建一个新表。
所以我创建了一个类:NrCellFactory。
public class NrCellFactory<S, String> extends TableCellFactory<S,String> {
private class NrCell<S,String> extends TableCell<S,String>{
public NrCell(){
setText(this.getTableRow().getIndex()+"");
}
}
@Override
protected TableCell<S, String> createTableCell(TableColumn<S, String> column) {
return new NrCell();
}
}
然后我将我的列设置为应显示数字:
nrCol.setCellFactory(new NrCellFactory<Person,String>());
当我加载项目时,nrCol没有数据......
任何人都可以解决问题吗?
由于
答案 0 :(得分:20)
示例解决方案
以下是使用细胞工厂的解决方案:
TableColumn numberCol = new TableColumn("#");
numberCol.setCellValueFactory(new Callback<CellDataFeatures<Person, Person>, ObservableValue<Person>>() {
@Override public ObservableValue<Person> call(CellDataFeatures<Person, Person> p) {
return new ReadOnlyObjectWrapper(p.getValue());
}
});
numberCol.setCellFactory(new Callback<TableColumn<Person, Person>, TableCell<Person, Person>>() {
@Override public TableCell<Person, Person> call(TableColumn<Person, Person> param) {
return new TableCell<Person, Person>() {
@Override protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
if (this.getTableRow() != null && item != null) {
setText(this.getTableRow().getIndex()+"");
} else {
setText("");
}
}
};
}
});
numberCol.setSortable(false);
简单替代解决方案
使用单元格值工厂的简单示例,对于正常情况下没有单元格工厂,表格的后备数据列表中的所有项目都是唯一的,并且可以通过table.getItems().indexOf(p.getValue())
查找其索引:< / p>
TableColumn numberCol = new TableColumn("#");
numberCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() {
@Override public ObservableValue<String> call(CellDataFeatures<Person, String> p) {
return new ReadOnlyObjectWrapper(table.getItems().indexOf(p.getValue()) + "");
}
});
numberCol.setSortable(false);
为什么尝试这样做失败
我无法确切地说出为什么尝试这样做会失败,因为我认为您的问题中没有足够的代码来准确诊断故障。我的猜测是你没有为行提供单元格值工厂,也没有在单元格的构造函数中设置文本而不是updateItem
调用导致它无法工作。
可执行样本
这是一个可执行的示例:
import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;
public class NumberedTableViewSample extends Application {
private TableView<Person> table = new TableView<Person>();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith@example.com"),
new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
new Person("Ethan", "Williams", "ethan.williams@example.com"),
new Person("Emma", "Jones", "emma.jones@example.com"),
new Person("Michael", "Brown", "michael.brown@example.com")
);
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(470);
stage.setHeight(500);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
TableColumn numberCol = new TableColumn("#");
numberCol.setMinWidth(20);
numberCol.setCellValueFactory(new Callback<CellDataFeatures<Person, Person>, ObservableValue<Person>>() {
@Override public ObservableValue<Person> call(CellDataFeatures<Person, Person> p) {
return new ReadOnlyObjectWrapper(p.getValue());
}
});
numberCol.setCellFactory(new Callback<TableColumn<Person, Person>, TableCell<Person, Person>>() {
@Override public TableCell<Person, Person> call(TableColumn<Person, Person> param) {
return new TableCell<Person, Person>() {
@Override protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
if (this.getTableRow() != null && item != null) {
setText(this.getTableRow().getIndex()+"");
} else {
setText("");
}
}
};
}
});
numberCol.setSortable(false);
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("email"));
table.setItems(data);
table.getColumns().addAll(numberCol, firstNameCol, lastNameCol, emailCol);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
}
答案 1 :(得分:16)
在java 8中,使用lambda表达式可以更轻松地完成:
TableColumn<Person, Number> indexColumn = new TableColumn<Person, Number>("#");
indexColumn.setSortable(false);
indexColumn.setCellValueFactory(column-> new ReadOnlyObjectWrapper<Number>(YourTable.getItems().indexOf(column.getValue())));
答案 2 :(得分:3)
这是一个可以在任何地方使用的通用(通用)单元工厂:
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project com.aepona.monetization.core: Compilation failure
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.apache.maven.plugin.compiler.CompilationFailureException: Compilation failure
at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:858)
at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:129)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
... 20 more
用法:public class LineNumbersCellFactory<T, E> implements Callback<TableColumn<T, E>, TableCell<T, E>> {
public LineNumbersCellFactory() {
}
@Override
public TableCell<T, E> call(TableColumn<T, E> param) {
return new TableCell<T, E>() {
@Override
protected void updateItem(E item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
setText(this.getTableRow().getIndex() + 1 + "");
} else {
setText("");
}
}
};
}
}
如果您需要0索引行,请删除+1。
编辑:删除项目时添加了colRowNum.setCellFactory(new LineNumbersCellFactory());
阻止
答案 3 :(得分:0)
一种不依赖于indexOf(item)
或updateItem()
的简单方法(可能是或者可能不是您需要监听的唯一事件)是绑定文本属性TableCell
到其行索引:
TableColumn<S, Integer> indexColumn = new TableColumn<>();
indexColumn.setCellFactory(col -> {
TableCell<S, Integer> indexCell = new TableCell<>();
ReadOnlyObjectProperty<TableRow<S>> rowProperty = indexCell.tableRowProperty();
ObjectBinding<String> rowBinding = Bindings.createObjectBinding(() -> {
TableRow<S> row = rowProperty.get();
if (row != null) { // can be null during CSS processing
int rowIndex = row.getIndex();
if (rowIndex < row.getTableView().getItems().size()) {
return Integer.toString(rowIndex);
}
}
return null;
}, rowProperty);
indexCell.textProperty().bind(rowBinding);
return indexCell;
});
如果您不关心行是否包含数据,则可以删除rowIndex < ...size()
支票:
TableRow<S> row = rowProperty.get();
return row == null ? null : Integer.toString(row.getIndex());