JavaFX-使用setRowFactory突出显示新行 [英] JavaFX - using setRowFactory to highlight new rows

查看:191
本文介绍了JavaFX-使用setRowFactory突出显示新行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个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 方法.

TableRows are created by TableView to fill it's viewport and contain TableCells. 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. PseudoClasses 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆