JavaFX - 使用setRowFactory突出显示新行

时间:2018-02-25 22:19:24

标签: css javafx tableview

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

1 个答案:

答案 0 :(得分:1)

TableRowTableView创建,以填充其视口并包含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属性...