我正在编写一个JavaFX应用程序,其中一系列消息出现在TableView中。当出现新消息时,表中的行应突出显示,这意味着其背景颜色应为橙色或其他颜色。用户单击后,应清除背景颜色,确认已读取消息。应该很简单。
我做了足够的研究,意识到我需要使用rowFactory来设置或清除行的背景。但我正在努力解决setRowFactory()
的机制问题。关于Oracle的文档是我的头脑,我上传的每个例子都与上一个完全不同。
以下是我所拥有的:
public class Message {
private boolean readOnce;
private int date;
private String msg;
public Message(int date, String msg, String msg2){
this.readOnce = false;
this.date = date;
this.msg = msg;
}
public boolean isReadOnce() {
return readOnce;
}
public void setReadOnce(){
readOnce = true;
}
// ...and more standard getters & setters here...
}
TableView在主控制器中设置:
@FXML TableView<Message> messageTable;
@FXML TableColumn<Message, Integer> Col1;
@FXML TableColumn<Message, String> Col2;
ObservableList<Message> tableItems;
// ...
// Setting up the Table:
PropertyValueFactory<Message, Integer> dateProperty = new PropertyValueFactory<Message, Integer>("date");
PropertyValueFactory<Message, String> msgProperty = new PropertyValueFactory<Message, String>("msg");
Col1.setCellValueFactory( dateProperty );
Col2.setCellValueFactory( msgProperty );
messageTable.setItems( tableItems );
// If we click an item in the table: messageTable.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if (newSelection != null) {
System.out.println("Troubleshoot: You clicked: "+newSelection.getMsg());
newSelection.setReadOnce(true);
}
});
如果我想在表格中添加新消息,我只需将其添加到可观察列表中:
public void addMsg(int num, String msg){
tableItems.add(new Message(num, msg));
}
到目前为止,非常简单。但是对于rowFactory来说,我只是大拇指:
messageTable.setRowFactory(messageTable -> {
TableRow<Message> row = new TableRow<>();
ObjectProperty<Message> opMsg = row.itemProperty();
Message tmpMsg = opMsg.get();
if(!tmpMsg.isReadOnce()){
row.getStyleClass().add("highlight-message"); // defined in CSS
} else {
row.getStyleClass().add("clear-message"); // defined in CSS
}
return row;
});
说实话,我不知道我在这做什么。我知道rowFactory接受整个表并逐个重新生成每一行。我不明白的是RowFactory代码如何检查表中的每条消息以及如何访问它们?最初我认为这些行可能允许我在行中看到消息:
TableRow<Message> row = new TableRow<>();
ObjectProperty<Message> opMsg = row.itemProperty();
Message tmpMsg = opMsg.get();
但是当我调试代码时,tmpMsg == NULL。这是一个很大的死胡同。
任何人都能看到我做错了什么?我已经研究了大约一个星期,绝对没有 - 在哪里。任何人都可以提供任何帮助都是非常感激的。
非常感谢, -RAO
答案 0 :(得分:1)
TableRow
由TableView
创建,以填充其视口并包含TableCell
。在创建它们时,item
属性仍包含默认值null
。您可以向该属性注册一个侦听器,但通常我更喜欢覆盖单元格的updateItem
方法。
使用PseudoClass
也比使用样式类更简单。可以将新项目分配给一行;这可能导致多次添加相同的样式类,甚至两个样式类都可以添加到同一个单元格中。然而,PseudoClass
可以打开/关闭,而无需关注删除其他类。
final PseudoClass highlightMessage = PseudoClass.getPseudoClass("highlight-message");
messageTable.setRowFactory(messageTable -> new TableRow<Message>() {
{
selectedProperty().addListener((o, oldVal, newVal) -> {
if (newVal) {
Message item = getItem();
if (item != null) {
item.setReadOnce();
pseudoClassStateChanged(highlightMessage, false);
}
}
});
}
@Override
protected void updateItem(Message item, boolean empty) {
super.updateItem(item, empty);
pseudoClassStateChanged(highlightMessage, item != null && !item.isReadOnce());
}
});
在CSS样式表中,您可以使用以下规则:
.table-row-cell:filled {
/* style for non-highlighted rows */
}
.table-row-cell:filled:highlight-message {
/* style for highlighted rows */
}
请注意,这不允许您以编程方式更改读取状态。它会更新选择单元格的状态。您可以向BooleanProperty
添加Message
或使用ObservableSet
存储突出显示的消息,并在需要以编程方式更新readOnce
属性时更新侦听器中的单元格状态。在后一种情况下,您无需在readOnce
本身存储Message
属性...