- PVSM.RU - https://www.pvsm.ru -
Как стилизовать компоненты JavaFX, используя старый добрый CSS.
Все посты в серии о JavaFX:
В предыдущей статье о FXML [3] мы узнали, как JavaFX обеспечивает четкое разделение задач путем разделения кода пользовательского интерфейса на две части. Компоненты и их свойства объявлены в файле FXML, а логика взаимодействия четко выделена в контроллер.
Кроме этого, есть и третья часть, язык FXML, управляющий только компонентами вашего приложения, их свойствами и тем, как они вложены друг в друга. Он не определяет визуальные элементы компонента, а именно: шрифты, цвета, фоны, отступы. В целом вы можете достичь этого в FXML, но не стоит этого делать. Вместо этого визуальные элементы должны быть четко определены в таблицах стилей CSS.
Таким образом, ваш дизайн становится независимым и может быть легко заменен или изменен без ущерба для остальной части приложения. Вы можете даже просто реализовать несколько тем, которые можно переключать по желанию пользователя.
Вы, вероятно, знакомы с CSS (Cascading Style Sheets — Каскадные таблицы стилей), используемыми для стилизации HTML-страниц в Интернете. Похожий подход реализован в JavaFX, несмотря на то, что JavaFX использует набор своих собственных пользовательских свойств.
Давайте рассмотрим пример:
.button {
-fx-font-size: 15px;
}
Здесь использованы две основные концепции. Первая — это селектор — .button. Он определяет, к каким компонентам должен применяться стиль. В этом примере стиль применяется для всех кнопок.
Вторая часть — это фактические свойства стиля, которые будут применены ко всем компонентам, которые соответствуют нашему селектору. Свойства — это все, что расположено внутри фигурных скобок.
Каждое свойство имеет определенное значение. В нашем примере есть свойство -fx-font-size, которое определяет, насколько большим будет текст. В примере указано значение 15px, но это значение может быть любым другим.
Подводя итог — мы создали правило, которое гласит — все кнопки везде должны иметь текст размером 15 пикселей.
Теперь давайте рассмотрим подробнее, как работают селекторы в JavaFX. Это происходит почти так же, как в обычном CSS.
Класс в CSS представляет несколько похожих элементов. Например, кнопки или флажки. Селектор, который должен применяться ко всем элементам одного класса, начинается с точки ".", сопровождаемый непосредственно именем класса. Соглашение об именовании классов состоит в том, чтобы разделять отдельные слова с помощью символа "-". Следующий селектор применяется ко всем элементам с классом label.
.label {
// Some properties
}
Хорошая новость заключается в том, что все встроенные компоненты JavaFX (такие как Label или Button) уже имеют предопределенный класс. Если вы хотите настроить стиль всех меток в своем приложении, вам не нужно добавлять какие-либо пользовательские классы для каждой из ваших меток. Каждая метка по-умолчанию имеет класс label.
Легко определить имя класса из компонента:
Некоторые примеры:
При использовании таких классов, как селекторы, не забудьте добавить ".". Это означает, что селектором для класса label является .label.
Если встроенных классов недостаточно, вы можете добавить свои собственные классы к своим компонентам. Вы можете использовать несколько классов, разделенных запятой:
<Label styleClass="my-label,other-class">I am a simple label</Label>
Или на Java:
Label label = new Label("I am a simple label");
label.getStyleClass().addAll("my-label", "other-class");
Добавление классов таким способом не удаляет класс компонента по умолчанию (в данном случае label).
Существует один специальный класс, называемый root. Он является корневым компонентом вашей сцены. Вы можете использовать его, чтобы стилизовать все внутри вашей сцены (например, установить глобальный шрифт). Это похоже на использование селектора тегов body в HTML.
Другим способом выбора компонентов в CSS является использование идентификатора компонента (ID). Он является уникальным идентификатором компонента. В отличие от классов, которые могут быть назначены нескольким компонентам, идентификатор должен быть уникальным в сцене.
В то время как, для указания класса используют символ "." перед именем в их селекторах, идентификаторы помечаются символом "#".
#my-component {
...
}
В FXML вы можете использовать fx:id для установки CSS-идентификатора компонента.
<Label fx:id="foo">I am a simple label</Label>
Однако есть одна оговорка. Этот же идентификатор используется для ссылки на объект компонента, объявленный в вашем контроллере [3]с тем же именем. Так как идентификатор и имя поля в контроллере должны совпадать, fx:id должен учитывать ограничение именования Java для имен полей. Хотя соглашение об именах CSS определяет отдельные слова, разделенные символом "-", это недопустимый символ для имен полей Java. Поэтому для fx:id с несколькими словами вам нужно использовать другое соглашение об именах, такое как CamelCase, или использовать подчеркивание.
<!-- This is not valid -->
<Label fx:id="my-label">I am a simple label</Label>
<!-- This is valid -->
<Label fx:id="my_label">I am a simple label</Label>
<Label fx:id="MyLabel">I am a simple label</Label>
В Java вы можете просто вызвать метод setId() вашего компонента.
Label label = new Label("I am a simple label");
label.setId("foo");
Хотя CSS, используемый в JavaFX, очень похож на оригинальный веб-CSS, есть одно большое отличие. Имена свойств различны, и есть много новых свойств, специфичных для JavaFX. Они имеют префикс -fx-.
Вот некоторые примеры:
Вы можете найти список всех свойств в официальном руководстве по дизайну [6].
В дополнение к обычным классам, которые отмечают определенные компоненты, существуют так называемые псевдоклассы, которые обозначают состояние компонента. Это может быть, например, класс для маркировки того, что компонент имеет фокус или на нем находится курсор мыши.
Есть множество встроенных псевдоклассов. Давайте посмотрим на кнопку. Существует несколько псевдоклассов, которые вы можете использовать, например:
Псевдоклассы начинаются с символа ":" (например, :hover) в селекторах CSS. Вам, конечно, нужно указать, к какому компоненту относится ваш псевдокласс — например, button:hover. В следующем примере показан селектор, который применяется ко всем кнопкам, имеющим фокус:
.button:focused {
-fx-background-color: red;
}
В отличие от CSS, который имеет только базовые псевдоклассы для состояний, таких как focus и hover, JavaFX имеет специфичные для компонента псевдоклассы, которые относятся к различным состояниям или свойствам компонентов.
Например:
В дополнение ко встроенным псевдоклассам, вы можете определять и использовать свои собственные псевдоклассы.
Давайте создадим нашу собственную метку (наследуя от класса Label). У него будет новое логическое свойство, называемое shiny. В таком случае, мы хотим, чтобы у нашей метки был псевдокласс shiny.
Поскольку у метки есть псевдокласс shiny, мы можем установить фон метки gold:
.shiny-label:shiny {
-fx-background-color: gold;
}
Теперь создадим сам класс.
public class ShinyLabel extends Label {
private BooleanProperty shiny;
public ShinyLabel() {
getStyleClass().add("shiny-label");
shiny = new SimpleBooleanProperty(false);
shiny.addListener(e -> {
pseudoClassStateChanged(PseudoClass.getPseudoClass("shiny"), shiny.get());
});
}
public boolean isShiny() {
return shiny.get();
}
public void setShiny(boolean shiny) {
this.shiny.set(shiny);
}
}
Здесь есть несколько важных частей:
Даже если вы сами не предоставляете никаких стилей, каждое приложение JavaFX уже имеет некоторые визуальные стили. Существует таблица стилей по умолчанию, которая применяется к каждому приложению. Она называется modena (начиная с JavaFX 8, ранее она называлась caspian).
Эту таблицу стилей можно найти в файле:
jfxrt.jarcomsunjavafxscenecontrolskinmodenamodena.css
Или вы можете найти файл здесь [7]. В том же каталоге есть множество изображений, используемых таблицей стилей.
Эта таблица стилей предоставляет стили по умолчанию, но имеет самый низкий приоритет по сравнению с другими типами таблиц стилей, поэтому вы можете легко ее переопределить.
В дополнение к таблице стилей по умолчанию, упомянутой выше, вы, конечно, можете предоставить свою собственную. Самый высокий уровень, на котором вы можете применить стилизацию — это вся сцена. Вы можете реализовать это в вашем FXML:
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
stylesheets="styles.css"
...
>
...
</BorderPane>
Или в вашем Java коде:
String stylesheet = getClass().getResource("/styles.css").toExternalForm();
scene.getStylesheets().add(stylesheet);
Обратите внимание на вызов toExternalForm(). Scene ожидает получить содержимое таблицы стилей в виде строки, а не файла, поэтому нам нужно предоставить содержимое нашей таблицы стилей в виде строки.
В дополнение к таблице стилей для всей сцены, иногда бывает полезно иметь стили на уровне макета. То есть — для отдельного контейнера, такого как VBox, HBox или GridPane. Общим родителем всех макетов является родительский класс, который определяет методы для обработки таблиц стилей на уровне макета. Эти стили применяются только для компонентов в данном макете, а не для всей сцены. Стиль на уровне макета имеет приоритет над стилем на уровне сцены.
<HBox stylesheets="styles.css">
...
</HBox>
В Java вам нужно загрузить содержимое таблицы стилей самостоятельно, так же как и ранее для сцены:
HBox box = new HBox();
String stylesheet = getClass().getResource("/styles.css").toExternalForm();
box.getStylesheets().add(stylesheet);
Пока что мы рассмотрели только случаи назначения внешней таблицы стилей для всей сцены или макета. Но можно задать индивидуальные свойства стиля на уровне компонента.
Здесь вам не нужно беспокоиться о селекторе, так как все свойства установлены для определенного компонента.
Вы можете указать несколько свойств, разделенных точкой с запятой:
<Label style="-fx-background-color: blue; -fx-text-fill: white">
I'm feeling blue.
</Label>
В Java вы можете использовать метод setStyle():
Label label = new Label("I'm feeling blue.");
label.setStyle("-fx-background-color: blue; -fx-text-fill: white");
Стили на уровне компонента имеют приоритет как над стилями сцены так и над родительскими стилями на уровне макета.
Стилизация на уровне компонентов может быть удобной, но это быстрое и «грязное» решение. Вы отказываетесь от основного преимущества CSS, которое заключается в отделении стилей от компонентов. Теперь вы жестко привязываете свои визуальные элементы непосредственно к компонентам. Вы больше не сможете легко переключать свои таблицы стилей, когда это необходимо, вы не можете менять темы.
Более того, у вас больше нет единого центрального места, где определяется ваш стиль. Когда вам нужно что-то изменить в наборе похожих компонентов, вам нужно изменить каждый из компонентов по отдельности, а не редактировать только одно место во внешней таблице стилей. Поэтому следует избегать встроенных стилей компонентов.
Вы можете обеспечить стилизацию на нескольких уровнях — сцена, родительский, встроенные стили, и также есть таблица стилей модены по умолчанию. Если вы изменяете одно и то же свойство одного и того же компонента на нескольких уровнях, JavaFX имеет настройку приоритета, которая определяет, какие стили следует использовать. Список приоритетов — от высшего к низшему:
Это означает, что если вы установите цвет фона определенной метки как на встроенном, так и на уровне сцены, JavaFX будет использовать значение, установленное во встроенных стилях, поскольку оно имеет более высокий приоритет.
В JavaFX имеется множество свойств CSS, и их описание выходит за рамки этого поста, подробный список см. в официальном справочном руководстве по CSS для JavaFX [6].
Автор: val6852
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/338370
Ссылки в тексте:
[1] Учебник по JavaFX: начало работы: https://habr.com/ru/post/474292/
[2] Учебник по JavaFX: Hello world!: https://habr.com/ru/post/474498/
[3] Учебник по JavaFX: FXML и SceneBuilder: https://habr.com/ru/post/474982/
[4] Учебник по JavaFX: основные макеты: https://habr.com/ru/post/475882/
[5] Учебник по JavaFX: расширенные макеты: https://habr.com/ru/post/477408/
[6] официальном руководстве по дизайну: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html
[7] здесь: https://www.vojtechruzicka.com/0a0496c95957848317c311b088d2b62b/modena.css
[8] Источник: https://habr.com/ru/post/477924/?utm_source=habrahabr&utm_medium=rss&utm_campaign=477924
Нажмите здесь для печати.