JavaFX-使用setRowFactory突出显示新行 [英] JavaFX - using setRowFactory to highlight new rows
问题描述
我正在编写一个JavaFX应用程序,其中一系列消息出现在TableView中.出现新消息时,表中的行应突出显示,这意味着其背景颜色应为橙色或其他颜色.用户单击它后,背景色应清除,以确认已读取该消息.应该很简单.
I am writing a JavaFX app where a series of messages appear in a TableView. When a new message appears, its row in the table should be highlighted, meaning its background color should be orange or something. Once the user clicks it, the background color should clear, acknowledging the message was read. Should be simple.
我已经进行了足够的研究,意识到我需要使用rowFactory来设置或清除行的背景.但是我在 setRowFactory()
的机制上苦苦挣扎.关于Oracle的文档已使我头疼,我在网上提出的每个示例似乎都与上一个示例截然不同.
I've done enough research to realize that I need to use a rowFactory to set or clear a row's background. But I'm struggling with the mechanics of setRowFactory()
. The documentation on Oracle is over my head, and every example I pull up online seems radically different than the last one.
这就是我所拥有的:
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在主控制器中设置:
The TableView is set up in the main controller:
@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);
}
});
如果我想向表中添加新消息,只需将其添加到可观察列表中:
And if I want to add a new message to the table, I just add it into the observable list:
public void addMsg(int num, String msg){
tableItems.add(new Message(num, msg));
}
到目前为止,非常简单.但是当涉及到rowFactory时,我都很反对:
So far, pretty easy. But I'm all thumbs when it comes to the 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代码如何检查表中的每个Message,以及如何访问它们?最初,我认为这些行可能会让我在该行中看到消息":
To be very honest, I have no idea what I'm doing here. I understand that the rowFactory takes in the entire table and regenerates each row one-by-one. What I don't understand is how does the RowFactory code examine each Message in the table and how can I access them? Originally I thought these line might allow me to see the Message within the row:
TableRow<Message> row = new TableRow<>();
ObjectProperty<Message> opMsg = row.itemProperty();
Message tmpMsg = opMsg.get();
但是当我调试代码时,tmpMsg == NULL.所以那是一个很大的胖死胡同.
But when I debug the code, tmpMsg == NULL. So that's a big fat dead end.
有人知道我在做什么错吗?我已经研究了大约一个星期,但绝对没有结果.任何人都能提供的任何帮助都将受到极大的赞赏.
Anyone see what I'm doing wrong? I've been researching this for about a week, getting absolutely no-where. Any help anyone can offer is wildly appreciated.
非常感谢,-RAO
推荐答案
TableRow
是由 TableView
创建的,以填充其视口并包含 TableCell
s.在创建它们时, item
属性仍包含默认值 null
.您可以为该属性注册一个侦听器,但通常我更喜欢覆盖单元格的 updateItem
方法.
TableRow
s are created by TableView
to fill it's viewport and contain TableCell
s. At the time they are created the item
property still contains the default value null
. You could register a listener to that property but usually I prefer overriding the updateItem
method of a cell.
使用 PseudoClass
也比使用样式类更简单.可以将新项目分配到一行;这可能导致同一样式类被多次添加,甚至两个样式类都可以添加到同一单元格中.但是, PseudoClass
es可以打开/关闭,而无需照顾删除其他类.
Also using PseudoClass
is simpler than using style classes. New items can be assigned to a row; this could result in the same style class being added multiple times and even both style classes could be added to the same cell. PseudoClass
es however can be switched on/of without the need to take care of removing other classes.
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样式表中,您可以使用如下规则:
In a CSS stylesheet you could use rules like this:
.table-row-cell:filled {
/* style for non-highlighted rows */
}
.table-row-cell:filled:highlight-message {
/* style for highlighted rows */
}
请注意,这不允许您以编程方式更改读取状态.它会在选择单元格时更新状态.您可以在 Message
中添加 BooleanProperty
或使用 ObservableSet
存储突出显示的消息,并在需要时更新来自侦听器的单元状态以编程方式更新 readOnce
属性.在后一种情况下,您不需要在 Message
本身中存储 readOnce
属性...
Note that this does not allow you to programmatically alter the read state. It updates the state on selecting a cell. You could add a BooleanProperty
to Message
or use a ObservableSet
to store the highlighted messages and update the state of cells from a listener if you need to programmatically update the readOnce
property. In the latter case you do not need to store a readOnce
property in the Message
itself...
这篇关于JavaFX-使用setRowFactory突出显示新行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!