Цвет текста панели TreeTableView SelectionBar

Древетаблевиев. Полоса выбора имеет шаблон, а в 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;
        }
    }
}

«Без использования CSS» Почему? Самый простой способ сделать это — с помощью CSS, и именно для этого предназначен API.

James_D 09.04.2024 14:58

Ну, у меня есть случай, когда мне постоянно нужно вызывать applyCSS() и Layout(), чтобы перерисовать что-то, а обновление applyCSS() в любом случае занимает больше времени, если нет возможности, я все равно приму предложение с использованием CSS

tretonis 09.04.2024 15:07

«У меня есть случай, когда мне постоянно нужно вызывать applyCSS() и Layout(), чтобы перерисовать что-то». Тогда у вас все неправильно настроено. Нет необходимости делать это с помощью виртуализированного управления.

James_D 09.04.2024 15:09

Что такое виртуализированное управление?

tretonis 09.04.2024 15:11

Виртуализированные элементы управления — это элементы управления, которые создают ячейки для отображения элементов и повторно используют ячейки «на лету» (поэтому они могут поддерживать очень большое количество элементов без необходимости большого количества ячеек из соображений производительности). ListView, TreeView, TableView и TreeTableView — это виртуализированные элементы управления.

James_D 09.04.2024 15:13

Верно, я знаю об этой концепции, просто не знал названия. Просто эти виртуальные элементы управления часто находятся на уровне ниже, где выше находится множество других элементов управления CSS. В будущем я опубликую вопрос по этому поводу и покажу задержку и необходимость вызова .appyCSS() и .layout().

tretonis 09.04.2024 15:23

Если вы вызываете applyCSS() и layout(), вы полностью лишаете смысла использование этих элементов управления, потому что вы обходите дизайн производительности кода макета. Это обходные пути: вам будет гораздо лучше исправить любую проблему, из-за которой вы используете эти обходные пути, чем избегать использования предполагаемого API, чтобы избежать снижения производительности обходного пути.

James_D 09.04.2024 15:31

Поскольку у вас есть знания по этому вопросу, я учту ваше предложение и проанализирую вопрос дальше. Поэтому, используя CSS, вы рекомендуете следующее: .tree-table-row-cell:selected > *{ -fx-text-fill: white; } ?

tretonis 09.04.2024 15:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предполагаемый способ сделать это — использовать 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.

Если вы действительно хотите сделать это без использования 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();
    }

Другие вопросы по теме