2012-10-03 56 views
2

我需要更改具有可變列數的TableView中任意單元格的樣式。下面的代碼顯示了基本問題。JavaFX 2刷新表單元格更改樣式

ExampleRow類是來自電子表格的真實數據的代理,它的其他功能是保存突出顯示信息。由於我不知道會有多少列,我只需保留應突出顯示的列的列表(列重新排列將不被支持)。 ExampleTableCell類只設置單元格的文本並在需要時應用高亮。

如果我在繪製表格[單元格(2,2)]之前設置了高光,那麼應用程序啓動時單元格會正確顯示爲紅色文本。問題是單擊按鈕將單元格(1,1)突出顯示,但表格不會更改。如果我將應用程序窗口的大小調整爲無,然後將其重新打開,單元格(1,1)的高亮顯示將被正確繪製 - 大概是因爲此過程會強制完全重繪。

我想知道的是,如何觸發表格來重新繪製新突出顯示的單元格(或所有可見單元格),以便樣式正確?

TIA

package example; 

import java.util.HashSet; 
import java.util.Set; 
import javafx.application.Application; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.value.ObservableValue; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 
import javafx.util.Callback; 

public class CellHighlightExample extends Application { 

    private final int columnCount = 4; 
    private final int rowCount = 5; 
    private TableView<ExampleRow> table = new TableView<>(); 

    @Override 
    public void start(Stage stage) { 
     BorderPane root = new BorderPane(); 
     Scene scene = new Scene(root); 

     Callback<TableColumn.CellDataFeatures<ExampleRow, String>, ObservableValue<String>> cellValueFactory = new Callback<TableColumn.CellDataFeatures<ExampleRow, String>, ObservableValue<String>>() { 
      @Override 
      public ObservableValue<String> call(TableColumn.CellDataFeatures<ExampleRow, String> p) { 
       int row = p.getValue().getRow(); 
       int col = p.getTableView().getColumns().indexOf(p.getTableColumn()); 
       return new SimpleObjectProperty<>("(" + row + ", " + col + ")"); 
      } 
     }; 

     Callback<TableColumn<ExampleRow, String>, TableCell<ExampleRow, String>> cellFactory = new Callback<TableColumn<ExampleRow, String>, TableCell<ExampleRow, String>>() { 
      @Override 
      public TableCell<ExampleRow, String> call(TableColumn<ExampleRow, String> p) { 
       return new ExampleTableCell<>(); 
      } 
     }; 

     for (int i = 0, n = columnCount; i < n; i++) { 
      TableColumn<ExampleRow, String> column = new TableColumn<>(); 
      column.setCellValueFactory(cellValueFactory); 
      column.setCellFactory(cellFactory); 
      table.getColumns().add(column); 
     } 

     ObservableList<ExampleRow> rows = FXCollections.observableArrayList(); 
     for (int i = 0, n = rowCount; i < n; i++) { 
      ExampleRow row = new ExampleRow(i); 
      //Force a cell to be highlighted to show that highlighting works. 
      if (i == 2) { row.addHighlightedColumn(2); } 
      rows.add(row); 
     } 
     table.setItems(rows); 

     Button b = new Button("Click to Highlight"); 
     b.setOnAction(new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent t) { 
       ExampleRow row = table.getItems().get(1); 
       row.addHighlightedColumn(1); 
       //How to trigger a redraw of the table or cell to reflect the new highlighting? 
      } 
     }); 

     root.setTop(b); 
     root.setCenter(table); 
     stage.setScene(scene); 
     stage.show(); 
    } 

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

    private class ExampleTableCell<S extends ExampleRow, T extends String> extends TableCell<S, T> { 

     @Override 
     public void updateItem(T item, boolean empty) { 
      super.updateItem(item, empty); 

      if (item == null) { 
       setText(null); 
       setGraphic(null); 
      } else { 
       setText(item); 
       int colIndex = getTableView().getColumns().indexOf(getTableColumn()); 
       ExampleRow row = getTableView().getItems().get(getIndex()); 
       if (row.isHighlighted(colIndex)) { 
        setTextFill(Color.RED); 
       } 
      } 
     } 
    } 

    private class ExampleRow { 

     private SimpleIntegerProperty row; 
     private Set<Integer> highlightedColumns = new HashSet<>(); 

     public ExampleRow(int row) { 
      this.row = new SimpleIntegerProperty(row); 
     } 

     public int getRow() { return row.get(); } 
     public void setRow(int row) { this.row.set(row); } 
     public SimpleIntegerProperty rowProperty() { return row; } 

     public boolean isHighlighted(int col) { 
      if (highlightedColumns.contains(col)) { 
       return true; 
      } 
      return false; 
     } 

     public void addHighlightedColumn(int col) { 
      highlightedColumns.add(col); 
     } 
    } 
} 

回答

6

有很多關於這個問題,改變項目(S)後,即令人耳目一新的tableview討論。
參見
JavaFX 2.1 TableView refresh items
問題
http://javafx-jira.kenai.com/browse/RT-21822
http://javafx-jira.kenai.com/browse/RT-22463
http://javafx-jira.kenai.com/browse/RT-22599

解決方案是將觸發內部的tableview更新方法。有的建議刪除tableview中的項目,然後再添加他們迎戰。但你的情況下,簡單的解決方法似乎是:

b.setOnAction(new EventHandler<ActionEvent>() { 
    @Override 
    public void handle(ActionEvent t) { 
     ExampleRow row = table.getItems().get(1); 
     row.addHighlightedColumn(1); 
     //How to trigger a redraw of the table or cell to reflect the new highlighting? 
     // Workaround 
     table.getColumns().get(0).setVisible(false); 
     table.getColumns().get(0).setVisible(true); 
    } 
}); 

這上面鏈接問題的意見中。這是一個真正的解決方法還是錯覺?你需要深入挖掘自己。

+0

謝謝Uluk,答案是現貨。我已經投票贊成你鏈接到的錯誤。 – wobblycogs