Как отдельно ссылаться на каждый большой палец RangeSlider (ControlsFX)

Я пытаюсь привязать метку, которая будет отображаться над нижним и верхним большим пальцем Ползунок диапазона.

Позиция метки всегда должна оставаться выше соответствующего большого пальца, независимо от того, куда пользователь перемещает ее. Вот так:

введите здесь описание изображения

введите здесь описание изображения

Мой подход состоит в том, чтобы прикрепить слушателей к каждому большому пальцу, чтобы я мог установить метку, чтобы иметь соответствующие координаты X/Y каждый раз, когда пользователь скользит. Но когда я запускаю следующий код, я не могу получить ссылку на большие пальцы отдельных лиц с помощью селекторов css.

Я следил за этой публикацией, но в ней используется только один большой палец, и поэтому на нее легко ссылаться. Как правильно использовать селекторы CSS в моем контексте или какой подход лучше, если мой несовершенен?

Контроллер

public class SliderDemoController implements Initializable {
    @FXML
    private RangeSlider range;
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        Pane thumb = (Pane) range.lookup(".range-slider .low-thumb");
        System.out.println(thumb); // <-- Prints null
    }
}

Главная

public class SliderDemoMain extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage initStage) throws IOException {
        FXMLLoader loader = new FXMLLoader(Drag.class.getClassLoader().getResource("sliderdemo.fxml"));
        Parent root = loader.load();
        Scene scene = new Scene(root);
        Stage primaryStage = new Stage();
        primaryStage.setTitle("Slider Demo");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

styleMain.css

.range-slider .range-bar {
    -fx-background-color: grey;
}

.range-slider .low-thumb {
     //....
}
.range-slider .high-thumb {
    //....
}

Верхняя строка слайдердемо.fxml

<HBox fx:id="menuBar" maxHeight="-Infinity" minHeight="-Infinity" prefHeight="79.0" stylesheets="@styleMain.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.propertydrop.SliderDemoController">

person Nova    schedule 06.01.2017    source источник


Ответы (1)


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

Этого трудно добиться в контроллере, потому что метод initialize() обычно вызывается до того, как корневой узел из FXML будет добавлен в сцену. Вы можете взломать это, наблюдая за sceneProperty() узла и отвечая, когда он установлен на что-то ненулевое. (Да, это немного хак...):

public class SliderDemoController implements Initializable {
    @FXML
    private RangeSlider range;
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        ChangeListener<Scene> initializer = new ChangeListener<Scene>() {
            @Override
            public void changed(ObservableValue<? extends Scene> obs, Scene oldScene, Scene newScene)  {
                if (newScene != null) {
                    range.applyCss();
                    range.getParent().layout();
                    Pane thumb = (Pane) range.lookup(".range-slider .low-thumb");
                    System.out.println(thumb); // <-- No longer null
                    range.sceneProperty().removeListener(this);
                }
            }
        };
        range.sceneProperty().addListener(initializer);
    }
}

В зависимости от ваших конкретных требований, вы можете обойтись чем-то менее уродливым, например, выполнить поиск в обработчике событий или в прослушивателе свойств ползунка highValue или lowValue.

person James_D    schedule 06.01.2017
comment
Лично я не считаю это взломом. Могу только сказать, что это необходимо, потому что API не предоставляет быстрого доступа из коробки. Просто радуйтесь, что есть даже решение для этого :) - person Jai; 06.01.2017
comment
@Jai Это взлом :). Правильный для API способ сделать то, что вы пытаетесь сделать, — это создать новый скин для RangeSlider, содержащий метки, которые вы хотите отобразить. Однако, поскольку (в настоящее время) класс скинов не является общедоступным, это потребует повторного изобретения колеса и большой работы. - person James_D; 06.01.2017
comment
@James_D, пока этот хак надежен в коммерческом контексте, меня устраивает эстетика. Вы ответили на мой вопрос, спасибо. Выполнение поиска внутри range.lowValueProperty().addListener действительно достаточно. +1 - person Nova; 06.01.2017