TableView,自定义单元格编辑行为
Posted
技术标签:
【中文标题】TableView,自定义单元格编辑行为【英文标题】:TableView, custom cell editing behaviour 【发布时间】:2015-02-04 21:55:14 【问题描述】:我有这个适用于 TableView 的应用程序。它添加/删除新的行或列并为每个单元格存储数据。
public class MyTable extends Application
private BorderPane root;
private HBox hBox;
private TableView<MyData> tableView;
private Button buttAddColumn, buttDeleteColumn;
private Button buttAddRow, buttDeleteRow;
private int numberOfColumns = 0;
private ObservableList<MyData> dataList = FXCollections.observableArrayList();
@Override
public void init() throws Exception
root = new BorderPane();
hBox = new HBox();
buttAddColumn = new Button("Add columns");
buttDeleteColumn = new Button("Delete columns");
buttAddRow = new Button("Add rows");
buttDeleteRow = new Button("Delete rows");
tableView = new TableView<>();
tableView.setEditable(true);
tableView.setItems(dataList);
hBox.getChildren().addAll(buttAddColumn,buttDeleteColumn,buttAddRow,buttDeleteRow);
root.setTop(hBox);
root.setCenter(tableView);
//----------------------------------------------------------------
buttAddColumn.setOnAction(new EventHandler<ActionEvent>()
@Override
public void handle(ActionEvent event)
buttAddColumnAction(event);
);
buttDeleteColumn.setOnAction(new EventHandler<ActionEvent>()
@Override
public void handle(ActionEvent event)
buttDeleteColumnAction(event);
);
buttAddRow.setOnAction(new EventHandler<ActionEvent>()
@Override
public void handle(ActionEvent event)
buttAddRowAction(event);
);
buttDeleteRow.setOnAction(new EventHandler<ActionEvent>()
@Override
public void handle(ActionEvent event)
buttDeleteRowAction(event);
);
private void buttAddColumnAction(ActionEvent event)
int i = numberOfColumns;// thats the key for lambda expression. Unicate number for column to access its variable;
if(dataList.size() > 0)//resizing each data object with new variable
for(MyData x: dataList)
x.addNew(i);
TableColumn<MyData, Integer> newColumn = new TableColumn<>("#" + String.valueOf(++numberOfColumns));
newColumn.setCellValueFactory(cellData -> cellData.getValue().getCellValue(i).asObject());
newColumn.setCellFactory(TextFieldTableCell.<MyData, Integer>forTableColumn(new IntegerStringConverter()));
tableView.getColumns().add(newColumn);
private void buttDeleteColumnAction(ActionEvent event)
if(numberOfColumns > 0)
tableView.getColumns().remove(numberOfColumns-1);
--numberOfColumns;
if(dataList.size() > 0)
for(MyData x: dataList) //deleting unnecesary variable
x.deleteLast();
private void buttAddRowAction(ActionEvent event)
dataList.add(new MyData(numberOfColumns));
private void buttDeleteRowAction(ActionEvent event)
if(dataList.size() > 0)//resizing each data object with new variable
dataList.remove(dataList.size()-1);
//*******************************************************************
public class MyData //dont forget about public because you wont get acces to properties
private ObservableList<SimpleIntegerProperty> cellValue = FXCollections.observableArrayList();
public MyData(int howManyColumns)
for(int i=0; i<howManyColumns; ++i)
this.cellValue.add(new SimpleIntegerProperty(new Random().nextInt(10)));
public SimpleIntegerProperty getCellValue(int whichOne)
return cellValue.get(whichOne);
public void setCellValue(int cellValue, int whichOne)
this.cellValue.set(whichOne, new SimpleIntegerProperty(cellValue));
public void addNew(int numberOfNewElement) //ads another variable for another column
cellValue.add(new SimpleIntegerProperty(new Random().nextInt(10)));
public void deleteLast() //deletes last variable when column is deleted
cellValue.remove(cellValue.size()-1);
//*******************************************************************
@Override
public void start(Stage primaryStage) throws Exception
try
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
catch(Exception e)
e.printStackTrace();
public static void main(String[] args)
launch(args);
我怎样才能改变它,所以当用户双击单元格时,程序会等到他按下 0-9 的单个数字,然后自动接受它并打开下一个单元格来放置另一个数字(所以他不需要手动打开/关闭它们)?
我目前不知道如何做到这一点。甚至如何使空单元格等待数据(也许数据类应该由char
变量而不是Integer
组成,所以我可以将值""
放入单元格???)
【问题讨论】:
【参考方案1】:6 小时左右,我成功了……
我必须在每一列中添加类似的内容,这是处理单元格编辑事件的类。
Callback<TableColumn<MyData, Integer>, TableCell<MyData, Integer>> cellFactoryInt = (TableColumn<MyData, Integer> p) -> new EditingCellNumbers(tableView);
newColumn.setCellFactory(cellFactoryInt);
这里实现这个类:
package application;
import application.MyTable.MyData;
import javafx.beans.value.ObservableValue;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
//Klasa ta pozwala na definiowania zachowania komórek, które edytuje użytkownik
public class EditingCellNumbers extends TableCell<MyData, Integer>
private TextField textField;
private TableView<MyData> parentTableView;
public static int numberOfColumns;
public EditingCellNumbers(TableView<MyData> parent)
this.parentTableView = parent;
numberOfColumns = parent.getColumns().size();
@Override
public void startEdit()
if (!isEmpty())
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
textField.requestFocus();
@Override
public void cancelEdit()
super.cancelEdit();
setText(String.valueOf(getItem()));
setGraphic(null);
@Override
public void updateItem(Integer item, boolean empty)
super.updateItem(item, empty);
if (empty)
setText(null);
setGraphic(null);
else
if (isEditing())
if (textField != null)
textField.setText(getString());
setText(null);
setGraphic(textField);
else
setText(getString());
setGraphic(null);
private void createTextField()
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
textField.focusedProperty().addListener(
(ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) ->
if (!arg2)
commitEdit(Integer.valueOf(textField.getText()));
);
textField.setOnKeyReleased(new EventHandler<Event>()
@Override
public void handle(Event event)
try
int i = Integer.valueOf(textField.getText());
//digit given...
if( (i>=0) && (i<10) )//making sure cell is filled with just one digit
commitEdit(Integer.valueOf(textField.getText()));
int selectedColumn = parentTableView.getSelectionModel().getSelectedCells().get(0).getColumn(); // gets the number of selected column
int selectedRow = parentTableView.getSelectionModel().getSelectedCells().get(0).getRow();
if(selectedColumn < numberOfColumns-1)
parentTableView.getSelectionModel().selectNext();
parentTableView.edit(selectedRow, parentTableView.getColumns().get(selectedColumn+1));
else
parentTableView.getSelectionModel().select(selectedRow+1, parentTableView.getColumns().get(0));
parentTableView.edit(selectedRow+1, parentTableView.getColumns().get(0));
else
textField.clear();
catch(NumberFormatException e)
textField.clear();
);
private String getString()
return getItem() == null ? "" : getItem().toString();
这里是一点点编辑的应用程序类:
public class MyTable extends Application
private BorderPane root;
private HBox hBox;
private TableView<MyData> tableView;
private Button buttAddColumn, buttDeleteColumn;
private Button buttAddRow, buttDeleteRow;
private int numberOfColumns = 0;
private ObservableList<MyData> dataList = FXCollections.observableArrayList();
@Override
public void init() throws Exception
root = new BorderPane();
buttAddColumn = new Button("Add columns");
buttDeleteColumn = new Button("Delete columns");
buttAddRow = new Button("Add rows");
buttDeleteRow = new Button("Delete rows");
tableView = new TableView<>();
hBox = new HBox();
hBox.getChildren().addAll(buttAddColumn,buttDeleteColumn,buttAddRow,buttDeleteRow);
tableView.setEditable(true);
tableView.getSelectionModel().setCellSelectionEnabled(true);
tableView.setItems(dataList);
root.setTop(hBox);
root.setCenter(tableView);
//----------------------------------------------------------------
buttAddColumn.setOnAction(new EventHandler<ActionEvent>()
@Override
public void handle(ActionEvent event)
buttAddColumnAction(event);
);
buttDeleteColumn.setOnAction(new EventHandler<ActionEvent>()
@Override
public void handle(ActionEvent event)
buttDeleteColumnAction(event);
);
buttAddRow.setOnAction(new EventHandler<ActionEvent>()
@Override
public void handle(ActionEvent event)
buttAddRowAction(event);
);
buttDeleteRow.setOnAction(new EventHandler<ActionEvent>()
@Override
public void handle(ActionEvent event)
buttDeleteRowAction(event);
);
private void buttAddColumnAction(ActionEvent event)
int i = numberOfColumns;// thats the key for lambda expression. Unicate number for column to access its variable;
if(dataList.size() > 0)//resizing each data object with new variable
for(MyData x: dataList)
x.addNew(i);
TableColumn<MyData, Integer> newColumn = new TableColumn<>("#" + String.valueOf(++numberOfColumns));
newColumn.setCellValueFactory(cellData -> cellData.getValue().getCellValue(i).asObject());
newColumn.setCellFactory(TextFieldTableCell.<MyData, Integer>forTableColumn(new IntegerStringConverter()));
Callback<TableColumn<MyData, Integer>, TableCell<MyData, Integer>> cellFactoryInt = (TableColumn<MyData, Integer> p) -> new EditingCellNumbers(tableView);
newColumn.setCellFactory(cellFactoryInt);
tableView.getColumns().add(newColumn);
private void buttDeleteColumnAction(ActionEvent event)
if(numberOfColumns > 0)
tableView.getColumns().remove(numberOfColumns-1);
--numberOfColumns;
--EditingCellNumbers.numberOfColumns;
if(dataList.size() > 0)
for(MyData x: dataList) //deleting unnecesary variable
x.deleteLast();
private void buttAddRowAction(ActionEvent event)
dataList.add(new MyData(numberOfColumns));
private void buttDeleteRowAction(ActionEvent event)
if(dataList.size() > 0)//resizing each data object with new variable
dataList.remove(dataList.size()-1);
//*******************************************************************
public class MyData //dont forget about public because you wont get acces to properties
private ObservableList<SimpleIntegerProperty> cellValue = FXCollections.observableArrayList();
public MyData(int howManyColumns)
for(int i=0; i<howManyColumns; ++i)
this.cellValue.add(new SimpleIntegerProperty(new Random().nextInt(10)));
public SimpleIntegerProperty getCellValue(int whichOne)
return cellValue.get(whichOne);
public void setCellValue(int cellValue, int whichOne)
this.cellValue.set(whichOne, new SimpleIntegerProperty(cellValue));
public void addNew(int numberOfNewElement) //ads another variable for another column
cellValue.add(new SimpleIntegerProperty(new Random().nextInt(10)));
public void deleteLast() //deletes last variable when column is deleted
cellValue.remove(cellValue.size()-1);
//*******************************************************************
@Override
public void start(Stage primaryStage) throws Exception
try
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
catch(Exception e)
e.printStackTrace();
public static void main(String[] args)
launch(args);
很多代码,但也许将来有人会使用它:P
【讨论】:
以上是关于TableView,自定义单元格编辑行为的主要内容,如果未能解决你的问题,请参考以下文章
在单元格内编辑textview时,将另一个单元格添加到tableview
添加另一个部分时将编辑的文本保留在自定义单元格中([tableView 刷新数据])
使用 UITextField 在 tableView 中显示 100 个自定义单元格
带有自定义 UITextView 单元格的 TableView 将导航栏滚动到屏幕外