2017-03-24 37 views
2

所以我写了一个javafx应用程序,我需要能够从列表视图中选择单元格(用于复制粘贴的目的),但我不想让它可编辑,我的意思是,内容不能改变,除非我想(例如通过按钮)。如何使ListView可选但不可编辑

所以我有以下代码:

import javafx.application.Application; 
import javafx.collections.FXCollections; 
import javafx.scene.Scene; 
import javafx.scene.control.ListView; 
import javafx.scene.control.cell.TextFieldListCell; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
public class Main extends Application { 

    @Override 
    public void start(Stage primaryStage) throws Exception{ 
     List<String> contacts = new ArrayList<>(Arrays.asList("968787522","3424234234","2343234324")); 
     ListView<String> contactsList = new ListView(); 
     contactsList.setItems(FXCollections.observableArrayList(contacts)); 
     //this gives me the ability to edit the row as text field but I want this text field to not be editable 
     contactsList.setCellFactory(TextFieldListCell.forListView()); 
     StackPane pane = new StackPane(); 
     pane.getChildren().add(contactsList); 
     primaryStage.setScene(new Scene(pane, 300, 275)); 
     primaryStage.show(); } 


    public static void main(String[] args) { 
     launch(args); 
    } 
} 

,如果我设置“contactsList”作为不可编辑,我不能编辑,既没有选择。你可以看到(图像波纹管),我正在编辑单元格,但我希望能够选择文本(而不是项目),但我不想删除字符(文本可选但不可编辑)。 enter image description here

+0

您的代码工作正常,我。 [编辑]你的问题,以包括一个[MCVE],演示问题。 –

+0

@James_D编辑。希望它更好。 –

回答

1

因此,在突破我的头,大量研究和API阅读之后,我想出了一个解决方案。这完全是我想要做的。这里是演示如果有人需要它;) 所以这个想法是,每当我们想要选择一行的内容,我们需要选择行,获取textField并将编辑设置为true或false(每次) 。 因此,在我制作的演示中,我放置了一个按钮,以便您可以将编辑切换为真或假,以确保它正在工作,以及如何工作。

干杯。

为了更好地理解,我评论了一些代码,如果您对此有任何疑问,请让我知道。

package sample; 

import com.sun.javafx.scene.control.skin.VirtualFlow; 
import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.collections.FXCollections; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.control.*; 
import javafx.scene.control.cell.TextFieldListCell; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 


public class Main extends Application { 
private boolean editable = false; 

public static IndexedCell getCell(final Control control, final int index) { 
    return getVirtualFlow(control).getCell(index); 
} 

public static VirtualFlow<?> getVirtualFlow(Control control) { 
    Group group = new Group(); 
    Scene scene = new Scene(group); 
    Stage stage = new Stage(); 

    if(control.getScene() == null) { 
     group.getChildren().setAll(control); 
     stage.setScene(scene); 
     stage.show(); 
    } 

    VirtualFlow<?>flow = (VirtualFlow<?>) control.lookup("#virtual-flow"); 
    return flow; 
} 

public void setEditable(ListView contactsList){ 
     //this needs to be done since we need to run our code after the text field was rendered 
     //so we need to invoke our code after this happens, if not it will throw a null pointer... 
     Platform.runLater(() -> { 
      //this is one of the most important guys because javafx api says that 
      //TextFieldListCell.forListView() allows editing of the cell content when the cell is double-clicked, 
      // or when {@link ListView#edit(int)} is called. 
      int rowIndex = contactsList.getSelectionModel().getSelectedIndex(); 
      contactsList.edit(rowIndex); 
      ListCell rootCell = (ListCell) getCell(contactsList, rowIndex); 
      TextField textField = (TextField) rootCell.getGraphic(); 
      textField.setEditable(editable); 
     }); 
} 

@Override 
public void start(Stage primaryStage) throws Exception{ 
    List<String> contacts = new ArrayList<>(Arrays.asList("968787522","3424234234","2343234324")); 
    ListView<String> contactsList = new ListView(); 
    contactsList.setItems(FXCollections.observableArrayList(contacts)); 
    contactsList.setEditable(true); 

    //this gives me the ability to edit the row as text field but I want this text field to not be editable 
    contactsList.setCellFactory(TextFieldListCell.forListView()); 
    contactsList.setOnEditStart(e -> { 
     setEditable(contactsList); 
    }); 

    StackPane pane = new StackPane(); 
    Button editBtn = new Button("Toggle edit"); 
    editBtn.setOnAction(event -> { 
     editable = !editable; 
     editBtn.setText("Editing = " + editable); 
     //to cancel any editing that might be occuring 
     contactsList.getSelectionModel().clearSelection(); 
    }); 
    pane.getChildren().addAll(contactsList,editBtn); 
    primaryStage.setScene(new Scene(pane, 300, 275)); 
    primaryStage.show(); 
} 

public static void main(String[] args) { 
    launch(args); 
} 
} 
0

如果我正确理解你,没有必要将listview设置为'not editable',因为默认行为应该足以满足你的目的。看看这个代码,例如:

import javafx.application.Application; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.control.ListView; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class NewFXMain extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     ListView listView = new ListView(); 
     listView.getItems().addAll("one","two","three","four"); 

     listView.setOnMouseClicked(new EventHandler<MouseEvent>() { 
      @Override 
      public void handle(MouseEvent event) { 
       System.out.println(listView.getSelectionModel().getSelectedItem()); 
      } 
     }); 

     StackPane root = new StackPane(); 
     root.getChildren().add(listView); 
     Scene scene = new Scene(root, 300, 250); 

     primaryStage.setTitle("ListView Example"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

} 

我什么也没有改变对ListView控件的编辑属性,但我可以选择每个项目,而不能对其进行编辑(以改变其价值感)。您可以轻松地将一个EventHandler添加到ListView中以执行您想要执行的任何操作。您也可以通过操作CellFactory将EventHandler添加到ListView的每个单元格中,如下面的答案所示:How to handle ListView item clicked action?

+0

同样的问题,我编辑了我的问题给你一个明确的例子。 –

+0

我一开始并不理解你的问题,当我做了,我无法弄清楚:D很好的解决方案,虽然工作得很好:) –

+0

感谢和感谢您的帮助;) –

0

这里对我来说是什么在起作用:

TableView<DataBean> table = new TableView<>(); 
    table.setItems(...); // list of some DataBean objects with dataBeanField proprty 
    table.setEditable(true); 

    TableColumn<DataBean, String> column = new TableColumn<>("SomeData"); 
    column.setCellValueFactory(new PropertyValueFactory<DataBean, String>("dataBeanField")); 
    column.setCellFactory(new Callback<TableColumn<DataBean, String>, TableCell<DataBean, String>>() { 
     @Override 
     public TableCell<DataBean, String> call(TableColumn<DataBean, String> param) { 
      return new TextFieldTableCell<>(new DefaultStringConverter() { 
       private String defaultValue = ""; 

       @Override 
       public String fromString(String newValue) { 
        return super.fromString(defaultValue); 
       } 

       @Override 
       public String toString(String value) { 
        return defaultValue = super.toString(value); 
       } 
      }); 
     } 
    });