Disable TableRow based on data

2019-02-26 02:02发布

I face a problem with TableView in JavaFX 2.1. I want to disable TableRow based on data.

For eg.:

public class RowData() {
private String name;
private boolean used;

public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public boolean isUsed(){
return this.used;
}
public void setUsed(boolean used) {
this.used = used;
}

}

In program:

    public class ViewController implements Initializable {
    @FXML
        private TableView<RowData> tableAttribute;
    public void initialize(URL location, ResourceBundle resources) {
    List<RowData> data = new ArrayList<RowData>();
            // datatype col
            TableColumn<DataRow, String> attNameCol = new TableColumn<DataRow, DataRow>(
            "Name");
            attNameCol 
            .setCellValueFactory(new PropertyValueFactory<DataRow, String>(
                    "name"));
            attNameCol .setMinWidth(110.0);
            tableComponent.getColumns().addAll(attNameCol );
    loadData(data);

    tableAttribute.setItems(FXCollections.observableList(data));

    //I want to disable row which used = true, enable otherwise

    }
}

How can I do to achieve that?

标签: javafx-2
1条回答
欢心
2楼-- · 2019-02-26 02:35

Example strategies for disabling a row based on the value of a row field:

  1. Use a rowFactory which renders the row content as disabled as needed.
  2. After the table has been shown, lookupAll the TableRows and render them as disabled as appropriate.

I create a sample app which uses the second principle.

The key logic in the sample is the following code executed after the table has been shown on an active stage, which enables and disables rows as needed (as well as applying style classes to each row so that they can be styled separately if required). Note, for this approach, if the rows in the table change or are reordered, then the lookup and enabling/disabling code will have to be re-run over the table after the table has been re-rendered so that the table is correctly styled and has the correct disabled properties for rows.

// highlight the table rows depending upon whether we expect to get paid.
int i = 0;
for (Node n: table.lookupAll("TableRow")) {
  if (n instanceof TableRow) {
    TableRow row = (TableRow) n;
    if (table.getItems().get(i).getWillPay()) {
      row.getStyleClass().add("willPayRow");
      row.setDisable(false);
    } else {
      row.getStyleClass().add("wontPayRow");
      row.setDisable(true);
    }
    i++;
    if (i == table.getItems().size())
      break;
  }
}

When using a fxml controller the lookupAll return 0 "TableRow" nodes. It seems that after table.setItems(data) when doing lookup rows are populated why ?

Before answering this, I will note that using a rowFactory is really the preferred solution to this question, rather than using a lookup. Some of the reasons why will become apparent in the rest of this answer. For a sample of a rowFactory approach, please refer to this linked sample code by james-d.

A lookup is a CSS operation and it requires that css has been applied to the nodes being looked up. To explicitly apply css, call applyCss after the node has been placed in a scene.

A difficulty with a controller is that, in the initialize call, the node might not yet be in a scene. To work around that issue you can apply the following pattern:

Pane parent = (Pane) table.getParent();
parent.getChildren().remove(table);
Scene applyCssScene = new Scene(table);
table.applyCss();
table.layout();
applyCssScene.setRoot(null);
if (parent != null) {
    // Assumes that the original order in the parent does not matter.
    // If it did, you would also need to keep track of the child list position.
    parent.getChildren().add(table);
}
. . .
// perform css based lookup operation on the table.

This creates a dummy holder scene with the table in it, applies CSS (after which CSS based lookup operations will work) and then removes the table from the scene so that you can add it to the real scene at a later time and afterwards places the table back in it's original parent. As you may have noted this is a bit confusing. Note that I didn't try to actually execute the CSS application process outlined above in an example application with an FXML controller, however I believe it will work.

In the sample app I linked which uses lookups, the above complexity is not needed because the lookup is made after the stage containing the table has been initially shown. The stage.show() call implicitly runs layout and css application passes on the scene to be shown (it needs to do this to determine the initial size of the stage based upon the calculated size of the initial scene and perhaps for other reasons).

查看更多
登录 后发表回答