Измененный фон заголовка javafx titledpane сбрасывается при вводе мыши

Мне нужно изменить фон заголовка TitledPane на основе некоторого входящего значения во время выполнения и сбросить его в противном случае.

Все мои TitledPane созданы на основе CSS, прикрепленного к сцене.

Сменить фон - не проблема. Проблема в том, что когда указатель мыши проходит над заголовком после изменения фона, фон сбрасывается на фон из CSS.


Тестовое приложение для изменения фона заголовка TitledPane:

import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TitledPane;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class TitledPaneApplication extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        final StackPane root = new StackPane();

        final TitledPane titledPane = new TitledPane();
        titledPane.setText("Title");
        root.getChildren().add(titledPane);

        final String titleBackgroundValue = "#00ff11";
        final ToggleButton button = new ToggleButton("Change");
        button.setOnAction(event -> {
            boolean selected = button.isSelected();

            final Node node = titledPane.lookup(".title");
            if (selected) {
                final Color color = Color.valueOf(titleBackgroundValue);
                ((Region) node).setBackground(new Background(new BackgroundFill(color, null, null)));
            } else {
                ((Region) node).setBackground(null);
                titledPane.applyCss();
            }
        });

        button.setSelected(false);
        titledPane.setContent(button);

        final Scene scene = new Scene(root, 400, 400);
        scene.getStylesheets().add(getClass().getResource("light.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.setTitle("TestApplication");
        primaryStage.show();
    }

}

CSS сцены light.css

.root {
    -fx-base: rgb(240, 240, 240);
    -fx-background: rgb(240, 240, 240);
    -fx-border-color: rgb(220, 220, 220);

    /* make controls (buttons, thumb, etc.) slightly lighter */
    -fx-color: derive(-fx-base, 10%);

    /* text fields and table rows background */
    -fx-control-inner-background: rgb(248, 248, 248);
    /* version of -fx-control-inner-background for alternative rows */
    -fx-control-inner-background-alt: derive(-fx-control-inner-background, -2.5%);

    /* text colors depending on background's brightness */
    -fx-light-text-color: rgb(220, 220, 220);
    -fx-mid-text-color: rgb(100, 100, 100);
    -fx-dark-text-color: rgb(20, 20, 20);

    /* A bright blue for highlighting/accenting objects.  For example: selected
     * text; selected items in menus, lists, trees, and tables; progress bars */
    -fx-accent: rgb(0, 80, 100);

    /* color of non-focused yet selected elements */
    -fx-selection-bar-non-focused: rgb(50, 50, 50);

    -fx-font-family: "Roboto"; /* "Segoe UI Semibold", "Roboto", "Monospaced" */
    -fx-font-size: 1em;

    -primary-border-color: rgb(220, 220, 220);
}

/* Fix derived prompt color for text fields */
.text-input {
    -fx-prompt-text-fill: derive(-fx-control-inner-background, -50%);
}

/* Keep prompt invisible when focused (above color fix overrides it) */
.text-input:focused {
    -fx-prompt-text-fill: transparent;
}

/* Fix scroll bar buttons arrows colors */
.scroll-bar > .increment-button > .increment-arrow,
.scroll-bar > .decrement-button > .decrement-arrow {
    -fx-background-color: -fx-mark-highlight-color, rgb(220, 220, 220);
}

.scroll-bar > .increment-button:hover > .increment-arrow,
.scroll-bar > .decrement-button:hover > .decrement-arrow {
    -fx-background-color: -fx-mark-highlight-color, rgb(240, 240, 240);
}

.scroll-bar > .increment-button:pressed > .increment-arrow,
.scroll-bar > .decrement-button:pressed > .decrement-arrow {
    -fx-background-color: -fx-mark-highlight-color, rgb(255, 255, 255);
}

.text-field {
    -fx-font-size: 10pt;
}

.combo-box {
    -fx-font-size: 10pt;
}

/* ScrollPane style. */
.scroll-pane {
    -fx-background-color: transparent;
}

.scroll-pane > .viewport {
    -fx-background-color: transparent;
}

/* TabPane style. */
.tab-pane > .tab-header-area {
    -fx-background-color: transparent;
}

/* TitledPane style. */
.titled-pane {
    -fx-border-width: 1;
    -fx-border-color: -primary-border-color;
    -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.15), 5, 0.0, 0, 1);
}

.titled-pane > .content {
    -fx-border-width: 0;
}

.titled-pane .title .arrow-button {
    visibility: false;
}

.titled-pane > .title {
    -fx-background-color: -primary-border-color;
    -fx-background-insets: 0;
    -fx-background-radius: 0 0 0 0;
    -fx-padding: 0.2em 0.2em 0.2em 0.2em;
}

.titled-pane > .title .text {
    -fx-font-size: 10pt;
}

Где определяется -primary-border-color?

Zephyr 31.10.2018 15:30

Прости за это. Я добавил его в пример CSS.

DJViking 31.10.2018 16:32

Очень странно. Я пробовал много способов исправить это, и я не могу изолировать свойство, которое срабатывает при наведении курсора ...

Zephyr 31.10.2018 18:09
3
3
1 209
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Установка встроенного стиля CSS имеет приоритет над стилями в файле css. Так что применение фона через setStyle поможет.

button.setOnAction(event -> {
            final Node node = titledPane.lookup(".title");
            if (button.isSelected()) {
                node.setStyle("-fx-background-color:#00ff11;");
            } else {
                node.setStyle(null);
            }
        });

ОБНОВИТЬ: Однако немного подробнее о реальной проблеме. Чтобы понять это, вам нужно сначала узнать, как внутренний фон .title определяется и как задается стиль при наведении курсора.

Внутри Modena.css ниже представлены стили для фона .title:

.titled-pane > .title {
    -fx-background-color:
        linear-gradient(to bottom,
            derive(-fx-color,-15%) 95%,
            derive(-fx-color,-25%) 100%
        ),
        -fx-inner-border, -fx-body-color;
    -fx-background-insets: 0, 1, 2;
    -fx-background-radius: 3 3 0 0, 2 2 0 0, 1 1 0 0;
    -fx-padding: 0.3333em 0.75em 0.3333em 0.75em; /* 4 9 4 9 */
}

.titled-pane > .title:hover {
    -fx-color: -fx-hover-base;
}

Если вы заметили, что фактический фон является производным от -fx-color, -fx-inner-border и -fx-body-color. Однако -fx-inner-border и -fx-body-color действительно снова получены только из -fx-color.

-fx-inner-border: linear-gradient(to bottom,
                ladder(
                    -fx-color,
                    derive(-fx-color,30%) 0%,
                    derive(-fx-color,20%) 40%,
                    derive(-fx-color,25%) 60%,
                    derive(-fx-color,55%) 80%,
                    derive(-fx-color,55%) 90%,
                    derive(-fx-color,75%) 100%
                ),
                ladder(
                    -fx-color,
                    derive(-fx-color,20%) 0%,
                    derive(-fx-color,10%) 20%,
                    derive(-fx-color,5%) 40%,
                    derive(-fx-color,-2%) 60%,
                    derive(-fx-color,-5%) 100%
                ));

-fx-body-color: linear-gradient(to bottom,
            ladder(
                -fx-color,
                derive(-fx-color,8%) 75%,
                derive(-fx-color,10%) 80%
            ),
            derive(-fx-color,-8%));

В псевдосостоянии: hover цвет -fx-color изменяется на -fx-hover-base, и соответственно обновляется фон. В этом твоя проблема. Вы программно устанавливаете только фон по умолчанию. При наведении указателя мыши на .title он все еще выбирает внутренний стиль файла CSS (поскольку вы не определили свой собственный для наведения).

Если нам удастся обновить атрибут -fx-color, он позаботится о соответствующих обновлениях css для разных псевдосостояний.

Более правильный подход к вашим требованиям будет таким, как показано ниже: таким образом вы все равно можете получить красивые градиентные функции заголовка, которые определены внутри.

button.setOnAction(event -> {
            final Node node = titledPane.lookup(".title");
            if (button.isSelected()) {
                node.setStyle("-fx-color:#00ff11;");
            } else {
                node.setStyle(null);
            }
        });

// In css file  
.titled-pane > .title {
    -fx-color: -primary-border-color;
    -fx-background-insets: 0;
    -fx-background-radius: 0 0 0 0;
    -fx-padding: 0.2em 0.2em 0.2em 0.2em;
}

Кажется, это помогает. Он не сбрасывается при наведении курсора. Хотя хотелось бы узнать, почему мой программный подход не сработал.

DJViking 31.10.2018 23:50

@DJViking Обновил мой ответ для объяснения.

Sai Dandem 01.11.2018 00:20

Спасибо за объяснение.

DJViking 01.11.2018 00:45

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