我想在A和B列值相等时将行颜色更改为绿色,而在它们不同时将其更改为红色。我完全不知道如何改编SO上的示例。我添加监听器?使用Observable
?我添加了为进一步更改准备的完整代码。
sample.fxml:
GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<TableView fx:id="tableView" GridPane.columnIndex="0" GridPane.rowIndex="0" editable="true">
<columns>
<TableColumn fx:id="colA" text="A">
<cellValueFactory>
<PropertyValueFactory property="A"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="colB" text="B">
<cellValueFactory>
<PropertyValueFactory property="B"/>
</cellValueFactory>
</TableColumn>
</columns>
<items>
<FXCollections fx:factory="observableArrayList"/>
</items>
</TableView>
</GridPane>
RowTest.java:
public class RowTest {
private SimpleIntegerProperty a;
private SimpleIntegerProperty b;
private SimpleBooleanProperty validRow;
public RowTest(int a, int b) {
this.a = new SimpleIntegerProperty(a);
this.b = new SimpleIntegerProperty(b);
this.validRow = new SimpleBooleanProperty();
this.validRow.bind(Bindings.createBooleanBinding(() -> this.a.get() == this.b.get()));
}
public int getA() {
return a.get();
}
public SimpleIntegerProperty aProperty() {
return a;
}
public void setA(int a) {
this.a.set(a);
}
public int getB() {
return b.get();
}
public SimpleIntegerProperty bProperty() {
return b;
}
public void setB(int b) {
this.b.set(b);
}
public boolean isValidRow() {
return validRow.get();
}
public SimpleBooleanProperty validRowProperty() {
return validRow;
}
public void setValidRow(boolean validRow) {
this.validRow.set(validRow);
}
}
Controller.java:
public class Controller implements Initializable {
@FXML
private TableView<RowTest> tableView;
@FXML
private TableColumn<RowTest, Integer> colB;
@FXML
private ObservableList<RowTest> data;
@Override
public void initialize(URL location, ResourceBundle resources) {
data = FXCollections.observableArrayList();
populateData();
setColumnsEditable();
}
private void setColumnsEditable() {
tableView.setRowFactory(tv -> new TableRow<RowTest>() {
@Override
public void updateItem(RowTest item, boolean empty) {
super.updateItem(item, empty);
if (item == null) {
setStyle("");
} else if (item.isValidRow()) {
setStyle("-fx-background-color: LightGreen; -fx-text-fill: Black;");
} else if (!item.isValidRow()) {
setStyle("-fx-background-color: Red; -fx-text-fill: Black;");
} else {
setStyle("");
}
}
});
colB.setCellFactory(TextFieldTableCellAutoCmt.forTableColumn(new IntToStringConverter<Integer>()));
colB.setOnEditCommit(
(TableColumn.CellEditEvent<RowTest, Integer> t) -> {
((RowTest) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setB(t.getNewValue());
});
data.addListener(new ListChangeListener<RowTest>() {
@Override
public void onChanged(Change<? extends RowTest> c) {
while (c.next()) {
if (c.wasUpdated()) {
}
}
}
});
}
private void populateData() {
data.add(new RowTest(1, 1));
data.add(new RowTest(1, 0));
tableView.setItems(data);
}
}
IntToStringConverter.java:
public class IntToStringConverter<Integer> extends StringConverter<java.lang.Integer> {
@Override
public String toString(java.lang.Integer object) {
return object.toString();
}
@Override
public java.lang.Integer fromString(String string) {
return java.lang.Integer.parseInt(string);
}
}
Main.java:
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Hello World");
Scene scene = new Scene(root, 600, 275);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
TextFieldTableCellAutoCmt.java:
public class TextFieldTableCellAutoCmt<S, T> extends TextFieldTableCell<S, T> {
protected TextField textField;
protected boolean isEdit;
public TextFieldTableCellAutoCmt() {
this(null);
}
public TextFieldTableCellAutoCmt(final StringConverter<T> conv) {
super(conv);
}
public static <S> Callback<TableColumn<S, String>, TableCell<S, String>> forTableColumn() {
return forTableColumn(new DefaultStringConverter());
}
public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> forTableColumn(final StringConverter<T> conv) {
return list -> new TextFieldTableCellAutoCmt<S, T>(conv);
}
@Override
public void startEdit() {
super.startEdit();
isEdit = true;
if (updateTextField()) {
textField.focusedProperty().addListener(this::onFocusChange);
textField.setOnKeyPressed(this::onKeyPress);
}
}
/**
* @return whether {@link #textField} has been changed
*/
protected boolean updateTextField() {
final Node g = getGraphic();
final boolean isUpd = g != null && textField != g;
if (isUpd) {
textField = g instanceof TextField ? (TextField) g : null;
}
return isUpd;
}
@Override
public void commitEdit(final T valNew) {
if (isEditing()) {
super.commitEdit(valNew);
} else {
final TableView<S> tbl = getTableView();
if (tbl != null) {
final TablePosition<S, T> pos = new TablePosition<>(tbl, getTableRow().getIndex(), getTableColumn()); // instead of tbl.getEditingCell()
final TableColumn.CellEditEvent<S, T> ev = new TableColumn.CellEditEvent<>(tbl, pos, TableColumn.editCommitEvent(), valNew);
Event.fireEvent(getTableColumn(), ev);
}
updateItem(valNew, false);
if (tbl != null) {
tbl.edit(-1, null);
}
// TODO ControlUtils.requestFocusOnControlOnlyIfCurrentFocusOwnerIsChild(tbl);
}
}
public void onFocusChange(final ObservableValue<? extends Boolean> obs, final boolean v0, final boolean v1) {
if (isEdit && !v1) {
commitEdit(getConverter().fromString(textField.getText()));
}
}
protected void onKeyPress(final KeyEvent e) {
switch (e.getCode()) {
case ESCAPE:
isEdit = false;
cancelEdit(); // see CellUtils#createTextField(...)
e.consume();
break;
case TAB:
if (e.isShiftDown()) {
getTableView().getSelectionModel().selectPrevious();
} else {
getTableView().getSelectionModel().selectNext();
}
e.consume();
break;
case UP:
getTableView().getSelectionModel().selectAboveCell();
e.consume();
break;
case DOWN:
getTableView().getSelectionModel().selectBelowCell();
e.consume();
break;
default:
break;
}
}
}
从这个地方怎么走:
data.addListener(new ListChangeListener<RowTest>() {
@Override
public void onChanged(Change<? extends RowTest> c) {
while (c.next()) {
if (c.wasUpdated()) {
}
}
}
});
获得对行的访问权限?因此,基于ObservableList项目,我想获取其Row容器。我不知道该怎么做。
编辑:
此绑定错误:
this.validRow.bind(Bindings.createBooleanBinding(() -> this.a.get() == this.b.get()));
我改为:
this.validRow.bind(Bindings.createBooleanBinding(() -> this.a.get() == this.b.get(), this.aProperty(), this.bProperty()));
答案 0 :(得分:1)
这解决了我的问题,但是我不确定这是否是正确的解决方案。
data = FXCollections.observableArrayList(e -> new Observable[]{e.validRowProperty()});
在这里找到并修改了此代码:
Changing table row color using a property that would not be visible in any column
tableView.setRowFactory(tv -> new TableRow<RowTest>() {
@Override
protected void updateItem(final RowTest item, final boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
this.styleProperty().bind(Bindings.createStringBinding(() -> {
if (item.isValidRow()) {
return "-fx-background-color: green;";
} else {
return "-fx-background-color: red;";
}
}, item.validRowProperty()));
} else {
setText(null);
setGraphic(null);
this.styleProperty().unbind();
setStyle(" ");
}
}
});
我更改了RowTest
中的绑定:
this.validRow.bind(Bindings.createBooleanBinding(() ->
this.a.get() == this.b.get(), this.aProperty(), this.bProperty()));