使用在任何列中都不可见的属性来更改表行颜色 [英] Changing table row color using a property that would not be visible in any column
问题描述
我需要使用在tableview
的任何列中都不可见的属性来更改表行的颜色.我做了以下事情:
I need to change the table row color using a property that would not be visible in any column of a tableview
. I did the following:
- 创建模型类
Person
(serialNumber
,first
,last
). - 使用提取器创建
Person
的observableList. - 创建两个表视图(
tableview1
,tableview2
)和一个listview
,它们都共享相同的数据. -
tableview1
具有serialCol1
列,其可见属性设置为 错误.
- create a model class
Person
(serialNumber
,first
,last
). - create an observableList of
Person
using an extractor. - create two tableviews(
tableview1
,tableview2
) and onelistview
that all sharing the same data. tableview1
has aserialCol1
column with a visible property set to false.
我想使用绑定到tableview2
中列的serialNumber
属性更改tableview1
行颜色.
I want to change tableview1
row color using the serialNumber
property that is bound to a column in a tableview2
.
这是完整的程序:
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;
/**
*
* @author kachna
*/
public class Extractor extends Application {
private final TableView<Person> tableView1 = new TableView<>();
private final TableView<Person> tableView2 = new TableView<>();
private final ListView<Person> listView = new ListView<>();
//observable list with extractor
private final ObservableList<Person> data = FXCollections.observableArrayList(p -> new Observable[]{p.serialNumberProperty(), p.firstProperty(), p.lastProperty()});
static class Person {
final IntegerProperty serialNumber;
final StringProperty first;
final StringProperty last;
public Person(int serialNumber, String first, String last) {
this.first = new SimpleStringProperty(first);
this.last = new SimpleStringProperty(last);
this.serialNumber = new SimpleIntegerProperty(serialNumber);
}
public IntegerProperty serialNumberProperty() {
return serialNumber;
}
public StringProperty firstProperty() {
return first;
}
public StringProperty lastProperty() {
return last;
}
@Override
public String toString() {
return "Person{" + "first=" + first.get() + ", last=" + last.get() + '}';
}
}
@Override
public void start(Stage stage) {
BorderPane root = new BorderPane();
VBox vBox = new VBox(10);
VBox.setVgrow(tableView2, Priority.ALWAYS);
root.setPadding(new Insets(10));
initTableViews();
initListView();
getData();
Label label1 = new Label("TableView 1");
label1.setStyle("-fx-font-size: 24px;\n"
+ "-fx-font-weight: bold;");
Label label2 = new Label("TableView 2");
label2.setStyle("-fx-font-size: 24px;\n"
+ "-fx-font-weight: bold;");
vBox.getChildren().addAll(label1, tableView1,label2, tableView2);
root.setCenter(vBox);
root.setRight(listView);
Scene scene = new Scene(root, 600, 400);
stage.setScene(scene);
stage.show();
}
private void initTableViews() {
// first table view
tableView1.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
tableView1.setEditable(true);
tableView1.setRowFactory(tv -> new TableRow<Person>() {
@Override
protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
if (item.serialNumber.get() % 2 == 0) {
setStyle("-fx-background-color: orange;");
} else {
setStyle(" ");
}
} else {
setStyle(" ");
}
}
});
TableColumn<Person, Number> serialCol1 = new TableColumn<>("Serial Number");
serialCol1.setCellValueFactory(cellData -> cellData.getValue().serialNumberProperty());
serialCol1.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<Number>() {
@Override
public String toString(Number object) {
return object.toString();
}
@Override
public Number fromString(String string) {
return Integer.parseInt(string);
}
}));
// make the serialCol1 column invisible
serialCol1.setVisible(false);
TableColumn<Person, String> firstCol1 = new TableColumn<>("First Name");
firstCol1.setCellValueFactory(cellData -> cellData.getValue().firstProperty());
firstCol1.setCellFactory(TextFieldTableCell.forTableColumn());
TableColumn<Person, String> lastCol1 = new TableColumn<>("Last Name");
lastCol1.setCellFactory(TextFieldTableCell.forTableColumn());
lastCol1.setCellValueFactory(cellData -> cellData.getValue().lastProperty());
tableView1.getColumns().addAll(serialCol1, firstCol1, lastCol1);
tableView1.setItems(data);
// second table view
tableView2.setEditable(true);
tableView2.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
TableColumn<Person, Number> serialCol = new TableColumn<>("Serial Number");
serialCol.setCellValueFactory(cellData -> cellData.getValue().serialNumberProperty());
serialCol.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<Number>() {
@Override
public String toString(Number object) {
return object.toString();
}
@Override
public Number fromString(String string) {
return Integer.parseInt(string);
}
}));
TableColumn<Person, String> firstCol2 = new TableColumn<>("First Name");
firstCol2.setCellValueFactory(cellData -> cellData.getValue().firstProperty());
TableColumn<Person, String> lastCol2 = new TableColumn<>("Last Name");
lastCol2.setCellFactory(TextFieldTableCell.forTableColumn());
lastCol2.setCellValueFactory(cellData -> cellData.getValue().lastProperty());
tableView2.getColumns().addAll(serialCol, firstCol2, lastCol2);
tableView2.setItems(data);
}
private void initListView() {
//list view
listView.setCellFactory(list -> new ListCell<Person>() {
@Override
protected void updateItem(Person value, boolean empty) {
super.updateItem(value, empty);
if (!empty && value != null) {
if (value.serialNumber.get() % 2 == 0) {
setStyle("-fx-background-color: orange;");
} else {
setStyle(" ");
}
setText(String.format("%s %s %s", value.serialNumber.get(), value.firstProperty().get(), value.lastProperty().get()));
} else {
setText(null);
setStyle(" ");
}
}
});
listView.setItems(data);
}
private void getData() {
data.setAll(IntStream.range(0, 10)
.mapToObj(i -> new Person(i, "first" + i, "last" + i))
.collect(Collectors.toList()));
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
问题:
-
tableview1
的样式在应用 改变.我必须滚动浏览各行才能看到样式更新.listview
的样式立即更改,没有任何问题.
- the style of
tableview1
doesn't change instantly after applying a change. I have to scroll hrough the rows to see the style updated. the style of thelistview
is changed instantly without any problems.
推荐答案
updateItem
方法未绑定到其项的属性生命周期(项不得为Observable),而是由View调用( ListView/TableView),只要它认为有必要更新数据表示形式即可.在屏幕上滚动行时,该行将为空(出于性能原因,我认为是),并在屏幕上再次更新.
The updateItem
method is not bound to the property lifecycle of its item ( an item must not be an Observable ), but rather gets called by the View (ListView/TableView) whenever it deems it necessary to update the data representation. When you scroll a Row off screen it gets nulled ( I assume for performance reasons ) and updated again when in screen.
您要执行的操作是将行的styleProperty
绑定到其项serialNumberProperty
,如下所示:
What you want to do is to bind the styleProperty
of the row to its items serialNumberProperty
like so:
tableView1.setRowFactory( tv -> new TableRow<Person>()
{
@Override
protected void updateItem( final Person item, final boolean empty )
{
super.updateItem( item, empty );
if ( !empty && item != null )
{
this.styleProperty().bind( Bindings.createStringBinding( () ->
{
if ( item.serialNumber.get() % 2 == 0 )
{
return "-fx-background-color: orange;";
}
return " ";
} , item.serialNumberProperty() ) );
}
else
{
/*
* As per comment in the Cell API
*/
setText( null );
setGraphic( null );
this.styleProperty().unbind();
setStyle( " " );
}
}
} );
我还建议查阅javafx.scene.control.Cell#updateitem(...)
的文档,因为它被标记为专家API".
I also recommend consulting the documentation of javafx.scene.control.Cell#updateitem(...)
as it is marked as "Expert API".
这篇关于使用在任何列中都不可见的属性来更改表行颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!