javafx - JavaFX TableView 上下文菜单获取选定的 ID
问题描述
我有一个 TableView,我在其中显示数据库中的数据。TableView 本身并没有硬编码在特定的表上,而是添加了列和数据。我添加了上下文菜单,所以当用户右键单击一个项目时,它会删除它。它工作正常,但我不知道如何获取第一列的 ID。请注意,我不想要选定的索引,而是 tableView (第一列)中的 ID。
被质疑的片段:
removeMenuItem.setOnAction(event -> {
System.out.println(row.getItem()); // HERE
this.tableView.getItems().remove(row.getItem());
});
基本上,row.getItem()
返回记录:
[2, Name, Stuff, Test Test, Category]
问题是如何获得 ID(在本例中为 2)或名称?
完整代码:
package controllers;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.util.Callback;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TableController {
@FXML
private Label descriptionLabel;
@FXML
private TableView tableView;
public void setTableResultSet(String label, ResultSet resultSet) throws SQLException {
// Create context menu
createContextMenu();
// Set label text
descriptionLabel.setText(label);
// Resolve columns
ObservableList<ObservableList> data = resolveTableColumns(resultSet);
// Add records
addTableRecords(resultSet, data);
}
/**
* Create a context menu responsible for removing items.
*/
private void createContextMenu() {
tableView.setRowFactory(tableView -> {
final TableRow row = new TableRow();
final ContextMenu contextMenu = new ContextMenu();
final MenuItem removeMenuItem = new MenuItem("Remove");
removeMenuItem.setOnAction(event -> {
System.out.println(row.getItem()); // HERE
this.tableView.getItems().remove(row.getItem());
});
contextMenu.getItems().add(removeMenuItem);
// Set context menu on row, but use a binding to make it only show for non-empty rows:
row.contextMenuProperty().bind(
Bindings.when(row.emptyProperty())
.then((ContextMenu) null)
.otherwise(contextMenu)
);
return row;
});
}
/**
* Resolves table columns based on a ResultSet.
*
* @param resultSet the ResultSet.
* @return
* @throws SQLException
*/
private ObservableList<ObservableList> resolveTableColumns(ResultSet resultSet) throws SQLException {
ObservableList<ObservableList> data = FXCollections.observableArrayList();
for (int i = 0; i < resultSet.getMetaData().getColumnCount(); i++) {
final int j = i;
TableColumn col = new TableColumn(resultSet.getMetaData().getColumnName(i + 1));
col.setCellValueFactory((Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>) param -> {
return new SimpleStringProperty(param.getValue().get(j).toString());
});
tableView.getColumns().add(col);
}
return data;
}
/**
* Adds table data from a ResultSet.
*
* @param resultSet the ResultSet.
* @param data the data.
* @throws SQLException
*/
private void addTableRecords(ResultSet resultSet, ObservableList<ObservableList> data) throws SQLException {
while (resultSet.next()) {
ObservableList<String> row = FXCollections.observableArrayList();
for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
row.add(resultSet.getString(i));
}
data.add(row);
}
tableView.setItems(data);
}
}
根据@James_D 的评论进行编辑:
package controllers;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.util.Callback;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TableController {
@FXML
private Label descriptionLabel;
@FXML
private TableView<ObservableList<String>> tableView;
public void setTableResultSet(String label, ResultSet resultSet) throws SQLException {
// Create context menu
createContextMenu();
// Set label text
descriptionLabel.setText(label);
// Resolve columns
ObservableList<ObservableList<String>> data = resolveTableColumns(resultSet);
// Add records
addTableRecords(resultSet, data);
}
/**
* Create a context menu responsible for removing items.
*/
private void createContextMenu() {
tableView.setRowFactory(tableView -> {
final TableRow<ObservableList<String>> row = new TableRow<>();
final ContextMenu contextMenu = new ContextMenu();
final MenuItem removeMenuItem = new MenuItem("Изтрий");
removeMenuItem.setOnAction(event -> {
System.out.println(row.getItem().get(1));
this.tableView.getItems().remove(row.getItem());
});
contextMenu.getItems().add(removeMenuItem);
// Set context menu on row, but use a binding to make it only show for non-empty rows:
row.contextMenuProperty().bind(
Bindings.when(row.emptyProperty())
.then((ContextMenu) null)
.otherwise(contextMenu)
);
return row;
});
}
/**
* Resolves table columns based on a ResultSet.
*
* @param resultSet the ResultSet.
* @return
* @throws SQLException
*/
private ObservableList<ObservableList<String>> resolveTableColumns(ResultSet resultSet) throws SQLException {
ObservableList<ObservableList<String>> data = FXCollections.observableArrayList();
for (int i = 0; i < resultSet.getMetaData().getColumnCount(); i++) {
final int j = i;
TableColumn col = new TableColumn(resultSet.getMetaData().getColumnName(i + 1));
col.setCellValueFactory((Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>) param -> {
return new SimpleStringProperty(param.getValue().get(j).toString());
});
tableView.getColumns().add(col);
}
return data;
}
/**
* Adds table data from a ResultSet.
*
* @param resultSet the ResultSet.
* @param data the data.
* @throws SQLException
*/
private void addTableRecords(ResultSet resultSet, ObservableList<ObservableList<String>> data) throws SQLException {
while (resultSet.next()) {
ObservableList<String> row = FXCollections.observableArrayList();
for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
row.add(resultSet.getString(i));
}
data.add(row);
}
tableView.setItems(data);
}
}
解决方案
不要使用原始类型:这样您就可以访问从表中检索到的数据的适当方法(无需在任何地方向下转换)。
具体来说,您声明您将数据表示为
ObservableList<ObservableList>
,这意味着每一行都表示为 (raw) ObservableList
。因为,看看你的addTableRecords
方法,一行的每个元素都是 a String
,所以行应该表示为ObservableList<String>
,而整体数据表示为ObservableList<ObservableList<String>>
。
和相关的TableView
UI 元素也应该被参数化:即你应该使用
TableView<ObservableList<String>>
TableColumn<ObservableList<String>, String>
TableRow<ObservableList<String>
如果您进行这些更改,那么在您的createContextMenu()
方法中,您将拥有
TableRow<ObservableList<String>> row = new TableRow<>();
因此,返回类型row.getItem()
将是,您可以在返回值上ObservableList<String>
调用ObservableList
(或更一般地说, )中定义的方法。List
具体来说,调用get(...)
将String
在行中的给定单元格中返回 :
String id = row.getItem().get(0);
String name = row.getItem().get(1);
等等
放在一起,这看起来像
package controllers;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.util.Callback;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TableController {
@FXML
private Label descriptionLabel;
@FXML
private TableView<ObservableList<String>> tableView;
public void setTableResultSet(String label, ResultSet resultSet) throws SQLException {
// Create context menu
createContextMenu();
// Set label text
descriptionLabel.setText(label);
// Resolve columns
ObservableList<ObservableList<String>> data = resolveTableColumns(resultSet);
// Add records
addTableRecords(resultSet, data);
}
/**
* Create a context menu responsible for removing items.
*/
private void createContextMenu() {
tableView.setRowFactory(tableView -> {
final TableRow<ObservableList<String>> row = new TableRow<>();
final ContextMenu contextMenu = new ContextMenu();
final MenuItem removeMenuItem = new MenuItem("Изтрий");
removeMenuItem.setOnAction(event -> {
String id = row.getItem().get(0);
String name = row.getItem().get(1);
// do whatever you need with id and name, etc.
this.tableView.getItems().remove(row.getItem());
});
contextMenu.getItems().add(removeMenuItem);
// Set context menu on row, but use a binding to make it only show for non-empty rows:
row.contextMenuProperty().bind(
Bindings.when(row.emptyProperty())
.then((ContextMenu) null)
.otherwise(contextMenu)
);
return row;
});
}
/**
* Resolves table columns based on a ResultSet.
*
* @param resultSet the ResultSet.
* @return
* @throws SQLException
*/
private ObservableList<ObservableList<String>> resolveTableColumns(ResultSet resultSet) throws SQLException {
ObservableList<ObservableList<String>> data = FXCollections.observableArrayList();
for (int i = 0; i < resultSet.getMetaData().getColumnCount(); i++) {
final int j = i;
TableColumn<ObservableList<String>, String> col = new TableColumn<>(resultSet.getMetaData().getColumnName(i + 1));
col.setCellValueFactory(param ->
new SimpleStringProperty(param.getValue().get(j))
);
tableView.getColumns().add(col);
}
return data;
}
/**
* Adds table data from a ResultSet.
*
* @param resultSet the ResultSet.
* @param data the data.
* @throws SQLException
*/
private void addTableRecords(ResultSet resultSet, ObservableList<ObservableList<String>> data) throws SQLException {
while (resultSet.next()) {
ObservableList<String> row = FXCollections.observableArrayList();
for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
row.add(resultSet.getString(i));
}
data.add(row);
}
tableView.setItems(data);
}
}
推荐阅读
- python - Django 模板继承在文件夹文件中不起作用。怎么做?
- php - 在使用 AJAX 调用的 PHP 中检索 JSON 数据
- wpf - 将 setter 属性的值绑定到属性颜色后面的代码
- python - 欧几里得距离 - 循环函数
- angular - Cannot order the date by desc on Lodash
- android - Android如何在AppWidget上添加一个圆形边框ImageView?
- date - 添加到 DATE 小时 - TSQL
- python - 基于数组更新数据框列中的值,其中行号指示范围的开始
- python - 烧瓶如何保存 SQLAlchemyobject 的实例
- sql - 已添加具有相同密钥的项目 - mscorlib