2016-01-20 38 views
0

我有一個包含具有圖像的自定義列的TableView。其他列由ObservableList填充,但不是自定義填充!JavaFX - 在TableView中更改所選TableRow的TableCell列

在雙擊該行時,我想更改該圖像,但不知道如何獲取TableCell對象,我只獲取包含其他列數據的ObservableList(在我的代碼中查找TODO) 。

Here's一些示例代碼:

import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
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.TableView; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 
import javafx.scene.layout.VBox; 
import javafx.scene.text.Font; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

public class TableViewSample extends Application { 

    private TableView<Person> table = new TableView<>(); 

    private final ObservableList<Person> data = 
      FXCollections.observableArrayList(
        new Person("Jacob", "Smith"), 
        new Person("Isabella", "Johnson"), 
        new Person("Ethan", "Williams"), 
        new Person("Emma", "Jones"), 
        new Person("Michael", "Brown") 
      ); 


    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(450); 
     stage.setHeight(500); 

     Label label = new Label("Address Book"); 
     label.setFont(new Font("Arial", 20)); 

     table.setEditable(true); 

     TableColumn<Person, String> firstNameCol = new TableColumn<>("Name"); 
     firstNameCol.setMinWidth(100); 
     firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName")); 

     TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name"); 
     lastNameCol.setMinWidth(100); 
     lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName")); 

     TableColumn<Person, String> customCol = new TableColumn<>("Status"); 
     customCol.setMinWidth(200); 
     // Install custom cell renderer 
     customCol.setCellFactory(new Callback<TableColumn<Person, String>, TableCell<Person, String>>() { 

      @Override 
      public TableCell<Person, String> call(TableColumn<Person, String> param) { 

       TableCell<Person, String> cell = new TableCell<Person, String>() { 

        ImageView image = new ImageView (new Image ("grey.png")); 

        @Override 
        public void updateItem (String item, boolean empty) { 

         super.updateItem (item, empty); 

         if (empty) { 

          setGraphic (null); 
          setText  (null); 
         } 
         else { 

          setGraphic (image); 
          setText  (null); 
         } 
        } 
       }; 

       return cell; 
      } 

     }); 

     table.setItems(data); 
     table.getColumns().addAll(firstNameCol, lastNameCol, customCol); 

     table.setOnMousePressed ((event) -> { 

      if (event.getClickCount() == 2) { 

       System.out.println("double clicked, but dunno know how to change last columns image??"); 

      // TODO Only returns data of the other columns, but nothing from my custom column ... 
      System.out.println(this.table.getSelectionModel().getSelectedItems()); 
      } 
     }); 

     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 Person(String fName, String lName) { 
      this.firstName = new SimpleStringProperty(fName); 
      this.lastName = new SimpleStringProperty(lName); 
     } 

     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); 
     } 
    } 

} 

也許有人可以給我意見如何更改的最後一列的形象?

非常感謝和問候

Wiesi;)

+2

如果你想改變圖像,爲什麼不添加一個新的屬性到'Person'? – fabian

+0

我想過,但我不知道如何在我的doubleclick-listener和我的cellFactory裏的updateItem-method中引用這個值?你能否提供一個有效的例子? – Wiesi

+0

您需要一個單元格值工廠以及一個單元工廠。列中的單元格需要某種數據才能顯示。你將該列定義爲一個'TableColumn ',所以你需要提供一些字符串數據(雖然我不知道你在這裏設計什麼)。那麼具體是,你想要做什麼?你如何提出從「人」對象獲取圖像?當該行被雙擊時,你想要顯示什麼圖像? –

回答

2

你的問題不是很精確,但也許這會有所幫助。這個例子顯示了一個Item s的表格。它維護一組已成功驗證的Item。 (在這個例子中,如果一個項目的值是偶數,那麼這個項目是有效的)。第三列顯示了一個圖像,如果該項目沒有被成功驗證(即無效或未執行驗證)和綠色矩形(如果它已被驗證)(即,它具有偶數值並且已經執行驗證)。如果雙擊表格中的一行,將會對該項目進行驗證,如果該項目沒有成功驗證(所以雙擊一個偶數值的項目將使其圖像變爲綠色,雙擊一個奇數值的項目將不起作用)。 (雙擊一個已經驗證的項目會將其從驗證的集合中刪除,這使測試更容易。)

它的工作方式是維護代表驗證項目的ObservableSet<Item>。單元格值工廠返回一個布爾綁定,觀察該集合,如果該項目在集合中,則返回true;否則返回false。單元格工廠只返回一個單元格,用於檢查布爾值並設置適當的圖像。

import java.util.Random; 
import java.util.function.Function; 

import javafx.application.Application; 
import javafx.beans.binding.Bindings; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableSet; 
import javafx.scene.Scene; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableRow; 
import javafx.scene.control.TableView; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Rectangle; 
import javafx.stage.Stage; 

public class TableWithValidationColumn extends Application { 

    private final Image validImage = createImage(20, 20, Color.GREEN); 
    private final Image invalidImage = createImage(20, 20, Color.RED); 

    @Override 
    public void start(Stage primaryStage) { 
     TableView<Item> table = new TableView<>(); 
     table.getColumns().add(column("Item", Item::nameProperty)); 
     table.getColumns().add(column("Value", Item::valueProperty)); 

     TableColumn<Item, Boolean> validColumn = new TableColumn<>("Validated"); 

     ObservableSet<Item> validItems = FXCollections.observableSet(); 

     validColumn.setCellValueFactory(cellData -> { 
      Item item = cellData.getValue() ; 
      return Bindings.createBooleanBinding(() -> validItems.contains(item), validItems); 
     }); 

     validColumn.setCellFactory(col -> new TableCell<Item, Boolean>() { 
      private final ImageView imageView = new ImageView(); 
      @Override 
      protected void updateItem(Boolean valid, boolean empty) { 
       super.updateItem(valid, empty); 
       if (empty) { 
        setGraphic(null); 
       } else { 
        if (valid) { 
         imageView.setImage(validImage); 
        } else { 
         imageView.setImage(invalidImage); 
        } 
        setGraphic(imageView); 
       } 
      } 
     }); 

     table.getColumns().add(validColumn); 

     // validate on double-click: 

     table.setRowFactory(tv -> { 
      TableRow<Item> row = new TableRow<>(); 
      row.setOnMouseClicked(e -> { 
       if ((! row.isEmpty()) && e.getClickCount() == 2) { 
        Item item = row.getItem() ; 
        if (validItems.contains(item)) { 
         validItems.remove(item); 
        } else { 
         if (validate(item)) { 
          validItems.add(item); 
         } 
        } 
       } 
      }); 
      return row ; 
     }); 

     Random rng = new Random(); 
     for (int i = 1 ; i <= 100 ; i++) { 
      table.getItems().add(new Item("Item "+i, rng.nextInt(100))); 
     } 

     BorderPane root = new BorderPane(table); 
     Scene scene = new Scene(root, 600 ,600); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private boolean validate(Item item) { 
     // items with even values validate: 
     return item.getValue() % 2 == 0; 
    } 

    private static <S,T> TableColumn<S,T> column(String text, Function<S, ObservableValue<T>> property) { 
     TableColumn<S,T> col = new TableColumn<>(text); 
     col.setCellValueFactory(cellData -> property.apply(cellData.getValue())); 
     return col ; 
    } 

    private final Image createImage(int w, int h, Color color) { 
     Rectangle rect = new Rectangle(w, h, color); 
     return rect.snapshot(null, null); 
    } 

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

    public static class Item { 
     private final StringProperty name = new SimpleStringProperty(); 
     private final IntegerProperty value = new SimpleIntegerProperty(); 

     public Item(String name, int value) { 
      setName(name); 
      setValue(value); 
     } 

     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); 
     } 


     public final IntegerProperty valueProperty() { 
      return this.value; 
     } 


     public final int getValue() { 
      return this.valueProperty().get(); 
     } 


     public final void setValue(final int value) { 
      this.valueProperty().set(value); 
     } 



    } 
} 
+0

謝謝James_D,我能夠抽象出我的需求! – Wiesi