JavaFX TableView粗体整行iff`message.isUnread()== true`

时间:2017-07-05 12:49:11

标签: uitableview javafx

我正在尝试在Javafx TableView中复制Gmail行为。新的未读邮件行应以粗体显示。以下是我迄今为止所做的事情:

enter image description here

我可以更改整行的背景,并加粗单元格,但不能加粗整行。 如何解释Javafx这样做?

for each Cell cell in tableview: 
    get Message m corresponding to row.
    String style = m.isUnread() ? "
    cell.setStyle("-fx-font-weight: 800" : "-fx-font-weight: 100")




import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Message {
    final static public ObservableList<Message> data = FXCollections.observableArrayList(
            new Message("Bob", "Where are you?", true, true),
            new Message("Elise", "Payment", false, false),
            new Message("Charlie", "Read this book: 'Clean code'", true, true),
            new Message("Oscar", "Golf class tonight", true, false),
            new Message("Sam", "How is your TableView progress?", false, true),
            new Message("Alice", "Latte", true, true)
    );

    final private String  name;
    final private String  title;
    private boolean isUnread;
    private boolean isArchived;

    public Message(String name, String title, boolean isUnread, boolean isArchived) {
        this.name = name; this.title = title; this.isUnread = isUnread;this.isArchived = isArchived;
    }
    public String  getName()    { return name;    }
    public String  getTitle()  { return title;  }
    public boolean getIsUnread() { return isUnread; }
    public boolean getisArchived() { return isArchived; }


    public void setIsUnread(boolean isUnread) { this.isUnread = isUnread;     }
 }

MyTable.java

import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;


public class MyTable extends Application {
    public static void main(String[] args) throws Exception { launch(args); }
    public void start(final Stage stage) throws Exception {
        stage.setTitle("Inbox");

        // create a table.
        TableView<Message> table = new TableView(Message.data);
        table.getColumns().addAll(makeStringColumn("Name", "name", 150), makeStringColumn("Title", "title", 300), makeBooleanColumn("New", "isUnread", 150));
        table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        table.setPrefHeight(250);

        stage.setScene(new Scene(table));
        stage.getScene().getStylesheets().add(getClass().getResource("message.css").toExternalForm());
        stage.show();

        // highlight the table rows depending upon whether we expect to get paid.
        int i = 0;
        for (Node n: table.lookupAll("TableRow")) {
            if (n instanceof TableRow) {
                TableRow row = (TableRow) n;
                if (table.getItems().get(i).getIsUnread()) {
                    row.getStyleClass().add("isReadRow");
                } else {
                    row.getStyleClass().add("isUnreadRow");
                }
                i++;
                if (i == table.getItems().size())
                    break;
            }
        }
    }

    private TableColumn<Message, String> makeStringColumn(String columnName, String propertyName, int prefWidth) {
        TableColumn<Message, String> column = new TableColumn<>(columnName);
        column.setCellValueFactory(new PropertyValueFactory<Message, String>(propertyName));
        column.setCellFactory(new Callback<TableColumn<Message, String>, TableCell<Message, String>>() {
            @Override public TableCell<Message, String> call(TableColumn<Message, String> soCalledFriendStringTableColumn) {
                return new TableCell<Message, String>() {
                    @Override public void updateItem(String item, boolean empty) {
                        super.updateItem(item, empty);
                        if (item != null) {
                            setText(item);
                        }
                    }
                };
            }
        });
        column.setPrefWidth(prefWidth);
        column.setSortable(false);
        return column;
    }

    private TableColumn<Message, Boolean> makeBooleanColumn(String columnName, String propertyName, int prefWidth) {
        TableColumn<Message, Boolean> column = new TableColumn<>(columnName);
        column.setCellValueFactory(new PropertyValueFactory<Message, Boolean>(propertyName));
        column.setCellFactory(new Callback<TableColumn<Message, Boolean>, TableCell<Message, Boolean>>() {
            @Override public TableCell<Message, Boolean> call(TableColumn<Message, Boolean> soCalledFriendBooleanTableColumn) {
                return new TableCell<Message, Boolean>() {
                    @Override public void updateItem(final Boolean item, final boolean empty) {
                        super.updateItem(item, empty);
                        if (item != null) {
                            setText(item.toString());
                            this.getStyleClass().add(item ? "isUnreadCell" : "isReadCell");
                        }
                    }
                };
            }
        });
        column.setPrefWidth(prefWidth);
        column.setSortable(false);
        return column;
    }
}

(Message.css)

   .column-header-background         { -fx-background-color: azure;       }
   .isReadRow                       { -fx-background-color: palegreen;   }
   .isUnreadRow                       { -fx-background-color: yellow;       }
   .isReadCell                      { -fx-font-weight: 100 ; -fx-text-fill: darkgreen;}
   .isUnreadCell                     { -fx-font-weight: 800 ; -fx-text-fill: red;}

2 个答案:

答案 0 :(得分:1)

要加粗行关联RowFactory,如下所示。

table.setPrefHeight(250);
        table.setRowFactory(new Callback<TableView<Message>, TableRow<Message>>() {
            @Override
            public TableRow<Message> call(TableView<Message> param) {
                final TableRow<Message> row = new TableRow<Message>() {
                    @Override
                    protected void updateItem(Message row, boolean empty) {
                        super.updateItem(row, empty);
                        if (!empty)
                            styleProperty().bind(Bindings.when(row.selectedProperty())
                                    .then("-fx-font-weight: bold; -fx-font-size: 16;")
                                    .otherwise(""));
                    }
                };
                return row;
            }
        });

        stage.setScene(new Scene(table));

在上面的示例中,Message行调用了selectedProperty()函数。 selectedProperty()函数返回布尔变量isUnread的值。如果isUnread值为true,那么整行将以粗体显示,否则它将不会。

 final private String  title;
    private boolean isUnread;
    private boolean isArchived;
    private BooleanProperty selected;

    public boolean getSelected() {return selected.get();}
    public BooleanProperty selectedProperty(){return selected;}


    public Message(String name, String title, boolean isUnread, boolean isArchived) {
        this.name = name; this.title = title; this.isUnread = isUnread;this.isArchived = isArchived;
        this.selected = new SimpleBooleanProperty(isUnread);
    }

将字体样式设置为粗体,大小设置为16,得到以下输出:

enter image description here

答案 1 :(得分:1)

我建议使用PseudoClass es来表示已读/未读行。使用rowFactory设置PseudoClass es。同时使用属性作为读/未读状态也是可取的,因为这允许您更新行而不刷新整个表:

private final BooleanProperty unread;

public void setUnread(boolean value) {
    this.unread.set(value);
}

public boolean isUnread() {
    return this.unread.get();
}

public BooleanProperty unreadProperty() {
    return unread;
}

public Message(String name, String title, boolean isUnread, boolean isArchived) {
    this.name = name;
    this.title = title;
    this.unread = new SimpleBooleanProperty(isUnread);
    this.isArchived = isArchived;
}
final PseudoClass read = PseudoClass.getPseudoClass("read");
final PseudoClass unread = PseudoClass.getPseudoClass("unread");
table.setRowFactory(tv -> new TableRow<Message>() {

    private void setState(boolean readState, boolean unreadState) {
        pseudoClassStateChanged(unread, unreadState);
        pseudoClassStateChanged(read, readState);
    }

    private void setUnreadState(boolean unreadState) {
        setState(!unreadState, unreadState);
    }

    private final ChangeListener<Boolean> unreadListener = (observable, oldValue, newValue) -> setUnreadState(newValue);

    @Override
    protected void updateItem(Message item, boolean empty) {
        // remove listener from old item
        Message oldItem = getItem();
        if (oldItem != null) {
            oldItem.unreadProperty().removeListener(unreadListener);
        }

        super.updateItem(item, empty);

        if (empty || item == null) {
            setState(false, false);
        } else {
            // set appropriate state & add listener
            setUnreadState(item.isUnread());
            item.unreadProperty().addListener(unreadListener);
        }
    }

});

stage.setScene(new Scene(table));
.table-row-cell:read {
    -fx-background-color: palegreen;
}

.table-row-cell:unread {
    -fx-background-color: yellow;
}

.table-row-cell:read>.table-cell {
    -fx-font-weight: 100;
    -fx-text-fill: darkgreen;
}

.table-row-cell:unread>.table-cell {
    -fx-font-weight: 800;
    -fx-text-fill: red;
}

即使它们变空,也要确保设置text的{​​{1}}。否则你可以看到“幽灵内容”:

TableCell
@Override
public void updateItem(String item, boolean empty) {
    super.updateItem(item, empty);
    if (item != null) {
        setText(item);
    } else {
        setText("");
    }
}