Древетаблевиев. Полоса выбора имеет шаблон, а в MODENA фон полосы синий. и цвет белой буквы.
Когда внутри ячейки используется «обновление», она помещается, например, Оранжевый цвет буквы, при нажатии на строку она не появляется буква белого цвета на панели выбора.
В таком случае, как выбор может остаться по умолчанию, то есть с синим фоном и белыми буквами.
«Без использования CSS»
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.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Callback;
public class SelectionBarColor extends Application {
@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(new Callback<TreeTableColumn<Person, String>, TreeTableCell<Person, String>>() {
@Override
public TreeTableCell<Person, String> call(TreeTableColumn<Person, String> param) {
TreeTableCell<Person, String> cell = new TreeTableCell<Person, String>() {
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setTextFill(Color.ORANGE);
setText(item);
}else {
setText("");
setGraphic(null);
}
}
};
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>() {
@Override
public void updateItem(Number item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
if (item.doubleValue() != -1) {
setTextFill(Color.BLUE);
// setStyle("-fx-text-fill: blue;");
setText(""+item.intValue());
setGraphic(null);
}else {
setText("");
setGraphic(null);
}
}else {
setText("");
setGraphic(null);
}
}
};
return cell;
});
nameColumn.setPrefWidth(150);
addressColumn.setPrefWidth(200);
ageColumn.setPrefWidth(100);
// Adicionar colunas ao TreeTableView
treeTableView.getColumns().addAll(nameColumn, addressColumn, ageColumn);
// Criar raiz e adicionar itens
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);
Scene scene = new Scene(treeTableView, 500, 300);
primaryStage.setScene(scene);
primaryStage.setTitle("JavaFX TreeTableView SelectionBar");
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;
}
}
}
Ну, у меня есть случай, когда мне постоянно нужно вызывать applyCSS() и Layout(), чтобы перерисовать что-то, а обновление applyCSS() в любом случае занимает больше времени, если нет возможности, я все равно приму предложение с использованием CSS
«У меня есть случай, когда мне постоянно нужно вызывать applyCSS() и Layout(), чтобы перерисовать что-то». Тогда у вас все неправильно настроено. Нет необходимости делать это с помощью виртуализированного управления.
Что такое виртуализированное управление?
Виртуализированные элементы управления — это элементы управления, которые создают ячейки для отображения элементов и повторно используют ячейки «на лету» (поэтому они могут поддерживать очень большое количество элементов без необходимости большого количества ячеек из соображений производительности). ListView
, TreeView
, TableView
и TreeTableView
— это виртуализированные элементы управления.
Верно, я знаю об этой концепции, просто не знал названия. Просто эти виртуальные элементы управления часто находятся на уровне ниже, где выше находится множество других элементов управления CSS. В будущем я опубликую вопрос по этому поводу и покажу задержку и необходимость вызова .appyCSS() и .layout().
Если вы вызываете applyCSS()
и layout()
, вы полностью лишаете смысла использование этих элементов управления, потому что вы обходите дизайн производительности кода макета. Это обходные пути: вам будет гораздо лучше исправить любую проблему, из-за которой вы используете эти обходные пути, чем избегать использования предполагаемого API, чтобы избежать снижения производительности обходного пути.
Поскольку у вас есть знания по этому вопросу, я учту ваше предложение и проанализирую вопрос дальше. Поэтому, используя CSS, вы рекомендуете следующее: .tree-table-row-cell:selected > *{ -fx-text-fill: white; } ?
Предполагаемый способ сделать это — использовать CSS. Вы можете добиться этого в CSS, используя следующее:
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.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.stage.Stage;
public class SelectionBarColor extends Application {
@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.getStyleClass().add("name-column");
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.getStyleClass().add("age-column");
ageColumn.setCellFactory(ttc -> new TreeTableCell<Person, Number>() {
@Override
public void updateItem(Number item, boolean empty) {
super.updateItem(item, empty);
if (item != null && item.intValue() != -1) {
setText(item.toString());
setGraphic(null);
}else {
setText("");
setGraphic(null);
}
}
});
nameColumn.setPrefWidth(150);
addressColumn.setPrefWidth(200);
ageColumn.setPrefWidth(100);
// Adicionar colunas ao TreeTableView
treeTableView.getColumns().addAll(nameColumn, addressColumn, ageColumn);
// Criar raiz e adicionar itens
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);
Scene scene = new Scene(treeTableView, 500, 300);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("JavaFX TreeTableView SelectionBar");
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;
}
}
}
(обратите внимание, что для столбца имени нет фабрики ячеек и что фабрика ячеек для столбца возраста не меняет цвет текста, но код добавляет классы стиля CSS к двум столбцам).
Таблица стилей
.name-column.tree-table-cell {
-fx-mid-text-color: orange;
}
.age-column.tree-table-cell {
-fx-mid-text-color: blue;
}
CSS по умолчанию, modena, использует функцию цветовой лестницы в качестве цвета текста по умолчанию для ячеек в древовидной таблице. Функция определена в модене как
-fx-text-background-color: ladder(
-fx-background,
-fx-light-text-color 45%,
-fx-dark-text-color 46%,
-fx-dark-text-color 59%,
-fx-mid-text-color 60%
);
Эта функция определяет -fx-text-background-color
как зависящий от -fx-background
, устанавливая для него значение -fx-light-text-color
, когда интенсивность -fx-background
меньше 45 % (т. е. фон темный), до -fx-dark-text-color
, когда интенсивность -fx-background
находится между 46 % и 59 % (фон средний) и -fx-mid-text-color
, когда интенсивность -fx-background
превышает 60 % (фон светлый). Значения искомых цветов -fx-light-text-color
, -fx-mid-text-color
и -fx-dark-text-color
определяются как белый, #333
и черный соответственно. Эффект заключается в выборе цвета текста, контрастирующего с фоном.
Фон по умолчанию — «очень светло-серый» (он на 26,4% светлее, чем #ececec
), поэтому в качестве заливки текста выбирается -fx-mid-text-color
. Когда строка выбрана, для фона устанавливается значение #0096c9
, интенсивность которого составляет менее 45 %, поэтому для заливки текста устанавливается значение -fx-light-text-color
(белый).
Заменяя в столбце только искомый цвет -fx-mid-text-color
, вы заменяете цвет текста для фона по умолчанию, но оставляете цвет текста для выбранного фона неизменным. При желании вы можете переопределить -fx-light-text-color
, чтобы создать другой вид для этих столбцов при выборе строки.
Кроме того, обратите внимание, что классы стилей, примененные к столбцам таблицы, распространяются на ячейки в столбце. Класс стиля также применяется к заголовку столбца. Селектор .name.tree-table-cell { }
выбирает элементы как с классом стиля name
, так и с классом стиля tree-table-cell
; то есть он выбирает ячейки в столбце. Если вы используете селектор .name { }
, он также окрасит текст в заголовке столбца, что может быть желательно, а может и нет.
.name-column {
-fx-mid-text-color: orange;
}
.age-column {
-fx-mid-text-color: blue;
}
Если вы действительно хотите сделать это без использования CSS, это возможно, но код станет более сложным. Кроме того, вы не получаете должного разделения стиля и логики.
Это можно сделать, позволив пользовательским ячейкам наблюдать за выбранным состоянием строки, в которой они содержатся. JavaFX 19 и более поздние версии имеют метод flatMap()
, который позволяет легко наблюдать «свойство свойства». Ячейки должны обновлять текстовую заливку при каждом вызове метода updateItem()
и при каждом изменении статуса выбора строки, в которой они содержатся. Одна из возможных реализаций выглядит так:
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.getStyleClass().add("name-column");
nameColumn.setCellFactory(ttc -> new TreeTableCell<Person, String>() {
{
tableRowProperty().flatMap(TreeTableRow::selectedProperty).addListener((obs, wasSelected, isNowSelected) -> updateTextFill());
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item);
}else {
setText("");
setGraphic(null);
}
updateTextFill();
}
private void updateTextFill() {
setTextFill(getTableRow().isSelected() ? Color.WHITE : Color.ORANGE);
}
});
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.getStyleClass().add("age-column");
ageColumn.setCellFactory(ttc -> new TreeTableCell<Person, Number>() {
{
tableRowProperty().flatMap(TreeTableRow::selectedProperty).addListener((obs, wasSelected, isNowSelected) -> updateTextFill());
}
@Override
public void updateItem(Number item, boolean empty) {
super.updateItem(item, empty);
if (item != null && item.intValue() != -1) {
setText(item.toString());
setGraphic(null);
}else {
setText("");
setGraphic(null);
}
updateTextFill();
}
private void updateTextFill() {
setTextFill(getTableRow().isSelected() ? Color.WHITE: Color.BLUE);
}
});
nameColumn.setPrefWidth(150);
addressColumn.setPrefWidth(200);
ageColumn.setPrefWidth(100);
// Adicionar colunas ao TreeTableView
treeTableView.getColumns().addAll(nameColumn, addressColumn, ageColumn);
// Criar raiz e adicionar itens
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);
Scene scene = new Scene(treeTableView, 500, 300);
// scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("JavaFX TreeTableView SelectionBar");
primaryStage.show();
}
«Без использования CSS» Почему? Самый простой способ сделать это — с помощью CSS, и именно для этого предназначен API.