当自定义 TreeTableView 内的单元格然后选择任意行时,条形图的颜色采用默认的 modena 样式,到目前为止它是正确的。
失去焦点后选择栏的文本不再是默认的黑色
如何在 JavaFX 中解决这个问题,有没有优雅的解决方案?
我试过
tableRowProperty().flatMap(TreeTableRow::focusedProperty).addListener((obs, wasSelected, isNowSelected) -> updateTextFill());
但失去焦点时它也无法正常工作
符合预期
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Callback;
public class SelectionBarColorFocus extends Application {
BorderPane bp = new BorderPane();
@Override
public void start(Stage primaryStage) {
TreeTableView<Person> treeTableView = new TreeTableView<>();
// Criar colunas
TreeTableColumn<Person, String> nameColumn = new TreeTableColumn<>("Name");
nameColumn.setCellValueFactory(cellData -> cellData.getValue().getValue().nameProperty());
nameColumn.setCellFactory((TreeTableColumn<Person, String> param) -> {
TreeTableCell<Person, String> cell = new TreeTableCell<Person, String>() {
final ImageView imv = new ImageView();
final Text text = new Text("");
HBox hbox = new HBox(imv, text);
{
tableRowProperty().flatMap(TreeTableRow::selectedProperty).addListener((obs, wasSelected, isNowSelected) -> updateTextFill());
// tableRowProperty().flatMap(TreeTableRow::focusedProperty).addListener((obs, wasSelected, isNowSelected) -> updateTextFill());
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
text.setFill(Color.ORANGE);
text.setText(item);
setGraphic(hbox);
}else {
text.setText("");
setGraphic(null);
}
}
private void updateTextFill() {
text.setFill(getTableRow().isSelected() ? Color.WHITE: Color.ORANGE);
}
};
return cell;
}
);
TreeTableColumn<Person, String> addressColumn = new TreeTableColumn<>("Address");
addressColumn.setCellValueFactory(cellData -> cellData.getValue().getValue().addressProperty());
TreeTableColumn<Person, Number> ageColumn = new TreeTableColumn<>("Age");
ageColumn.setCellValueFactory(cellData -> cellData.getValue().getValue().ageProperty());
ageColumn.setCellFactory((TreeTableColumn<Person, Number> param) -> {
TreeTableCell<Person, Number> cell = new TreeTableCell<Person, Number>() {
boolean flat = false;
final Text text = new Text("");
{
focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
System.out.println("jorge focused="+isNowFocused);
}
);
}
@Override
public void updateItem(Number item, boolean empty) {
super.updateItem(item, empty);
if(flat == false) {
tableRowProperty().flatMap(TreeTableRow::selectedProperty).addListener((obs, wasSelected, isNowSelected) -> updateTextFill(item, empty));
flat = true;
}
updateTextFill(item, empty);
}
private void updateTextFill(Number item, boolean empty) {
if(item != null && item.intValue() != -1) {
text.setFill(Color.BLUE);
text.setText(item.toString());
setGraphic(text);
}else {
text.setText("");
setText("");
setGraphic(null);
}
text.setFill(getTableRow().isSelected() ? Color.WHITE: Color.BLUE);
}
};
return cell;
});
nameColumn.setPrefWidth(150);
addressColumn.setPrefWidth(200);
ageColumn.setPrefWidth(100);
treeTableView.getColumns().addAll(nameColumn, addressColumn, ageColumn);
TreeItem<Person> rootItem = new TreeItem<>(new Person("Persons", "", -1));
rootItem.getChildren().addAll(
new TreeItem<>(new Person("Alice", "456 Park Ave", 25)),
new TreeItem<>(new Person("Bob", "789 Broadway", 35)),
new TreeItem<>(new Person("Carol", "987 Elm St", 40)),
new TreeItem<>(new Person("John", "123 Main St", 40))
);
rootItem.setExpanded(true);
treeTableView.setRoot(rootItem);
Button b = new Button("Row Lost Focus");
StackPane st = new StackPane();
st.getChildren().add(b);
bp.setCenter(treeTableView);
bp.setBottom(st);
Scene scene = new Scene(bp, 500, 300);
primaryStage.setScene(scene);
primaryStage.setTitle("JavaFX TreeTableView SelectionBar Lost Focus");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class Person {
private StringProperty name;
private StringProperty address;
private IntegerProperty age;
public Person(String name, String address, int age) {
this.name = new SimpleStringProperty(name);
this.address = new SimpleStringProperty(address);
this.age = new SimpleIntegerProperty(age);
}
public StringProperty nameProperty() {
return name;
}
public StringProperty addressProperty() {
return address;
}
public IntegerProperty ageProperty() {
return age;
}
}
}
单元格(和其他控件)中的默认颜色在 modena CSS 文件中定义,其源代码可在此处查看。对于单元格,文本填充具有以下定义:
其中各个颜色定义为
然后将其应用于各种控件中的文本,在本例中为
这意味着,如果文本绘制在深色物体
fx-background
(强度低于 45%)上,文本将为白色 (-fx-light-text-color
);如果背景为“中等”(强度在 46% 到 59% 之间),文本将为黑色 ( )-fx-dark-text-color
,如果文本绘制在浅色背景(强度高于 60%)上,文本将为深灰色 (-fx-mid-text-color: #333;
)。默认情况下,背景为浅灰色,因此文本显示为深灰色。当行被选中并聚焦时,背景为强调色,强度小于 45%,因此文本自动变为白色。当行被选中但未聚焦时,背景为浅灰色(不像未选中的背景那样浅),文本再次变为深灰色(“中间文本颜色”)。
修改样式的推荐方法是提供您自己的样式表。由于您使用的是文本对象,因此默认情况下这些对象没有样式,因此您需要为它们指定样式类(或 ID,但由于同一列中会有多个文本对象,我建议使用 CSS 类)。
据我了解,您的要求是,您希望姓名列的文本为橙色,年龄列的文本为蓝色,但仅限于未选择行时。选择行后,您需要默认颜色(无论是选择+聚焦还是选择+未聚焦的默认颜色)。
您可以通过以下方式实现此目的:
和样式表
通过将 明确设置
-fx-text-background-color
为橙色或蓝色,然后恢复所选行中的默认梯子,即可实现此目的。这里还有其他解决方案:例如请注意,没有监听器并且单元实现非常基础。
只需使用单元格的文本属性而不是显式文本对象即可简化此操作。目前尚不清楚您是否出于某些未指明的原因在实际应用中需要这些属性,但以下是我在此特定示例中实现单元格的方法:
和
使用(同样更简单的)样式表