JavaFX ListView编辑文本字段ListCell
我正在开发一个客户机-服务器解决方案,并且我与连接的客户机有一个列表视图。用户只需在ListView中编辑名称,就可以远程重命名客户端。我已经阅读了很多关于编辑ListView单元格的内容,但是我还没有找到一个好的示例,可以在其中更改类的成员属性。大多数示例都有字符串列表,我认为这不是现代软件开发,如果ListView中的项目不仅仅是字符串 我想做的是更改客户机内部的属性JavaFX ListView编辑文本字段ListCell,java,listview,javafx,javafx-8,Java,Listview,Javafx,Javafx 8,我正在开发一个客户机-服务器解决方案,并且我与连接的客户机有一个列表视图。用户只需在ListView中编辑名称,就可以远程重命名客户端。我已经阅读了很多关于编辑ListView单元格的内容,但是我还没有找到一个好的示例,可以在其中更改类的成员属性。大多数示例都有字符串列表,我认为这不是现代软件开发,如果ListView中的项目不仅仅是字符串 我想做的是更改客户机内部的属性name。 class Client { private String name; public S
name
。
class Client {
private String name;
public String getName(){
return name;
}
public String setName(String val){
name = val;
}
}
我不在乎是否必须将成员name
实现为JavaFX属性(事实上我已经这样做了,但为了可读性和简单性而忽略了它)
尝试使用TextFieldListCell工厂失败
如果您感兴趣,我已尝试使用TextFieldListCell单元工厂:
this.listViewClients.setCellFactory(TextFieldListCell
.forListView(new NetworkClientStringConverter(this.clientController)));
但我发现了一些棘手的事情:
- 每次名称更改时,我都无法访问该对象。显然,我应该做的是创建一个新的客户端并返回它(
)。fromString
- 通过将客户端控制器传递给
,我解决了这个问题。(这不太好,我更愿意访问我正在更改的客户端。)StringConverter
- 通过将客户端控制器传递给
- 尽管如此,这个名字并没有改变
TextFieldListCell
,这有点棘手,但下面的方法似乎可行
假设在这个问题中有一个客户机模型类:
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Client {
private final StringProperty name = new SimpleStringProperty();
public final StringProperty nameProperty() {
return this.name;
}
public final String getName() {
return this.nameProperty().get();
}
public final void setName(final String name) {
this.nameProperty().set(name);
}
}
(fwiw我认为如果您使用标准的javabean属性而不是JavaFX属性,那么这里的一切仍然适用)
创建引用单元格的转换器类:
public class ClientConverter extends StringConverter<Client> {
private final ListCell<Client> cell;
public ClientConverter(ListCell<Client> cell) {
this.cell = cell ;
}
@Override
public String toString(Client client) {
return client.getName();
}
@Override
public Client fromString(String string) {
Client client = cell.getItem();
client.setName(string);
return client ;
}
}
使用此单元实现的SSCCE是
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class EditableListView extends Application {
@Override
public void start(Stage primaryStage) {
ListView<Client> listViewClients = new ListView<>();
for (int i= 1 ; i <= 20; i++) {
Client c = new Client();
c.setName("Client "+i);
listViewClients.getItems().add(c);
}
listViewClients.setEditable(true);
listViewClients.setCellFactory(lv -> new ClientListCell());
// debug:
Button debug = new Button("Show clients");
debug.setOnAction(e -> listViewClients.getItems().stream().map(Client::getName).forEach(System.out::println));
BorderPane root = new BorderPane(listViewClients, null, null, debug, null);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
导入javafx.application.application;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.ContentDisplay;
导入javafx.scene.control.ListCell;
导入javafx.scene.control.ListView;
导入javafx.scene.control.TextField;
导入javafx.scene.input.KeyCode;
导入javafx.scene.input.KeyEvent;
导入javafx.scene.layout.BorderPane;
导入javafx.stage.stage;
公共类EditableListView扩展了应用程序{
@凌驾
公共无效开始(阶段primaryStage){
ListView ListViewClient=新建ListView();
for(int i=1;i new ClientListCell());
//调试:
按钮调试=新按钮(“显示客户端”);
setOnAction(e->listViewClients.getItems().stream().map(Client::getName).forEach(System.out::println));
BorderPane root=新的BorderPane(ListViewClient,null,null,debug,null);
primaryStage.setScene(新场景(根));
primaryStage.show();
}
公共静态void main(字符串[]args){
发射(args);
}
}
是的,我已经说过了:)是的,对不起,我刚刚注意到:)我不想去cell factory的原因是我显然无法将它轻松地划分为自己的类。只是内联实现它需要很多代码?明天我们将对此进行研究,谢谢James。将其作为一个独立类重写非常简单。当我回到计算机前时,我会更新。仅供参考:我创建了自己的StringConverter类(实际上几乎相同),因为它不是内部的(或lambda),所以我必须将客户机控制器传递给它。也许我可以尝试使用单元格而不是控制器来调整它。你应该能够将单元格的引用传递给它。@ElMac paddling back:当涉及到编辑时,这是一个难题。。。类型是硬编码的(celll必须具有与列表相同的参数类型,从而导致方法/事件携带该类型-无法找到任何方法绕过…)
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class EditableListView extends Application {
@Override
public void start(Stage primaryStage) {
ListView<Client> listViewClients = new ListView<>();
for (int i= 1 ; i <= 20; i++) {
Client c = new Client();
c.setName("Client "+i);
listViewClients.getItems().add(c);
}
listViewClients.setEditable(true);
listViewClients.setCellFactory(lv -> {
TextFieldListCell<Client> cell = new TextFieldListCell<>();
cell.setConverter(new ClientConverter(cell));
return cell ;
});
// debug:
Button debug = new Button("Show clients");
debug.setOnAction(e -> listViewClients.getItems().stream().map(Client::getName).forEach(System.out::println));
BorderPane root = new BorderPane(listViewClients, null, null, debug, null);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static class ClientConverter extends StringConverter<Client> {
private final ListCell<Client> cell;
public ClientConverter(ListCell<Client> cell) {
this.cell = cell ;
}
@Override
public String toString(Client client) {
return client.getName();
}
@Override
public Client fromString(String string) {
Client client = cell.getItem();
client.setName(string);
return client ;
}
}
public static void main(String[] args) {
launch(args);
}
}
public class ClientListCell extends ListCell<Client> {
private final TextField textField = new TextField();
public ClientListCell() {
textField.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
if (e.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
});
textField.setOnAction(e -> {
getItem().setName(textField.getText());
setText(textField.getText());
setContentDisplay(ContentDisplay.TEXT_ONLY);
});
setGraphic(textField);
}
@Override
protected void updateItem(Client client, boolean empty) {
super.updateItem(client, empty);
if (isEditing()) {
textField.setText(client.getName());
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setContentDisplay(ContentDisplay.TEXT_ONLY);
if (empty) {
setText(null);
} else {
setText(client.getName());
}
}
}
@Override
public void startEdit() {
super.startEdit();
textField.setText(getItem().getName());
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.requestFocus();
textField.selectAll();
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().getName());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class EditableListView extends Application {
@Override
public void start(Stage primaryStage) {
ListView<Client> listViewClients = new ListView<>();
for (int i= 1 ; i <= 20; i++) {
Client c = new Client();
c.setName("Client "+i);
listViewClients.getItems().add(c);
}
listViewClients.setEditable(true);
listViewClients.setCellFactory(lv -> new ClientListCell());
// debug:
Button debug = new Button("Show clients");
debug.setOnAction(e -> listViewClients.getItems().stream().map(Client::getName).forEach(System.out::println));
BorderPane root = new BorderPane(listViewClients, null, null, debug, null);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}