Tutorial JavaFX: estilo CSS

Como estilizar componentes JavaFX usando o bom e velho CSS.

Todas as postagens na série JavaFX:

  1. Tutorial JavaFX: Introdução
  2. Tutorial JavaFX: Olá, mundo!
  3. Tutorial JavaFX: FXML e SceneBuilder
  4. Tutorial JavaFX: layouts básicos
  5. Tutorial JavaFX: layouts avançados
  6. Tutorial JavaFX: estilo CSS
  7. JavaFX Weaver: Integrando aplicativos JavaFX e Spring Boot

Separação de elementos visuais


Em um artigo anterior sobre FXML, aprendemos como o JavaFX fornece uma separação clara de tarefas dividindo o código da interface do usuário em duas. Os componentes e suas propriedades são declarados no arquivo FXML e a lógica de interação é claramente alocada ao controlador.

Além disso, há uma terceira parte, a linguagem FXML, que controla apenas os componentes do seu aplicativo, suas propriedades e como eles são incorporados um ao outro. Ele não define os elementos visuais de um componente, a saber: fontes, cores, planos de fundo, recuos. Em geral, você pode conseguir isso em FXML, mas não deve. Em vez disso, os elementos visuais devem ser claramente definidos nas folhas de estilo CSS.

Assim, seu design se torna independente e pode ser facilmente substituído ou alterado sem afetar o restante do aplicativo. Você pode simplesmente implementar vários temas que podem ser alterados a pedido do usuário.

CSS


Você provavelmente conhece o CSS (Cascading Style Sheets) usado para estilizar páginas HTML na web. Uma abordagem semelhante é implementada no JavaFX, embora o JavaFX use um conjunto de suas próprias propriedades customizadas.

Vejamos um exemplo:

.button { -fx-font-size: 15px; } 

Dois conceitos principais são usados ​​aqui. O primeiro é o seletor de botão. Determina a quais componentes o estilo deve ser aplicado. Neste exemplo, o estilo é aplicado a todos os botões.

A segunda parte são as propriedades reais do estilo, que serão aplicadas a todos os componentes que correspondem ao nosso seletor. Propriedades são tudo dentro de chaves.

Cada propriedade tem um significado específico. No nosso exemplo, existe a propriedade -fx-font-size , que determina o tamanho do texto. No exemplo, o valor é 15px , mas esse valor pode ser qualquer outro.

Para resumir - criamos uma regra que afirma que todos os botões em todos os lugares devem ter texto de 15 pixels.

Seletores


Agora, vamos dar uma olhada em como os seletores funcionam no JavaFX. Isso acontece quase da mesma forma que no CSS comum.

Class


Uma classe em CSS representa vários elementos semelhantes. Por exemplo, botões ou caixas de seleção. O seletor, que deve ser aplicado a todos os elementos da mesma classe, começa com um ponto ".", Seguido imediatamente pelo nome da classe. Uma convenção de nomenclatura de classe é separar palavras individuais com o caractere "-". O seletor a seguir se aplica a todos os elementos com a classe label .

 .label { // Some properties } 

Classes incorporadas


A boa notícia é que todos os componentes internos do JavaFX (como Label ou Button) já possuem uma classe predefinida. Se você deseja personalizar o estilo de todos os rótulos no seu aplicativo, não é necessário adicionar nenhuma classe personalizada para cada um deles. Cada etiqueta tem uma classe de etiqueta por padrão.

É fácil determinar o nome da classe do componente:

  • Pegue o nome da classe de componente Java - por exemplo. Etiqueta
  • Coloque o nome em minúsculas
  • Se consistir em várias palavras, separe-as com o símbolo "-"

Alguns exemplos:

  • Etiqueta → Etiqueta
  • Caixa de seleção → caixa de seleção

Ao usar classes como seletores, adicione ".". Isso significa que o seletor para a classe label é .label .

Classes personalizadas


Se as classes internas não forem suficientes, você poderá adicionar suas próprias classes aos seus componentes. Você pode usar várias classes separadas por vírgula:

 <Label styleClass="my-label,other-class">I am a simple label</Label> 

Ou em Java:

 Label label = new Label("I am a simple label"); label.getStyleClass().addAll("my-label", "other-class"); 

A adição de classes dessa maneira não remove a classe de componente por padrão (nesse caso, rótulo ).

Há uma classe especial chamada raiz . É o componente raiz da sua cena. Você pode usá-lo para estilizar tudo dentro da sua cena (por exemplo, defina uma fonte global). É semelhante ao uso do seletor de tags de corpo em HTML.

ID


Outra maneira de selecionar componentes no CSS é usar um identificador de componente (ID). É um identificador exclusivo para um componente. Diferentemente das classes que podem ser atribuídas a vários componentes, o identificador deve ser exclusivo na cena.

Enquanto o símbolo "." É usado para indicar a classe. na frente do nome em seus seletores, os identificadores são marcados com o símbolo "#".

 #my-component { ... } 

No FXML, você pode usar fx: id para definir o identificador CSS de um componente.

 <Label fx:id="foo">I am a simple label</Label> 

No entanto, há uma ressalva. O mesmo identificador é usado para se referir ao objeto componente declarado no seu controlador com o mesmo nome. Como o identificador e o nome do campo no controlador devem corresponder, fx: id deve levar em consideração a restrição de nomenclatura Java para nomes de campos. Embora a convenção de nomenclatura CSS defina palavras individuais separadas por um caractere "-", é um caractere inválido para nomes de campos Java. Portanto, para fx: id com poucas palavras, você precisa usar uma convenção de nomenclatura diferente, como CamelCase, ou usar sublinhado.

 <!-- 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> 

Em Java, você pode simplesmente chamar o método setId () do seu componente.

 Label label = new Label("I am a simple label"); label.setId("foo"); 

Propriedades


Embora o CSS usado no JavaFX seja muito semelhante ao CSS original da web, há uma grande diferença. Os nomes das propriedades são diferentes e existem muitas novas propriedades específicas do JavaFX. Eles têm o prefixo -fx- .

Aqui estão alguns exemplos:

  • -fx-background-color : cor de fundo
  • -fx-text-fill : cor do texto
  • -fx-font-size : tamanho do texto

Você pode encontrar uma lista de todas as propriedades no guia oficial de design .

Pseudo-classes


Além das classes usuais que marcam componentes específicos, existem as chamadas pseudo-classes que indicam o estado de um componente. Pode ser, por exemplo, uma classe para marcar que o componente tem foco ou o cursor do mouse está nele.

Existem muitas pseudo-classes embutidas. Vamos olhar para o botão. Existem várias pseudo-classes que você pode usar, por exemplo:

  • pairar : passe o mouse sobre o botão
  • focado : o botão tem foco
  • desabilitado : o botão está desabilitado
  • pressionado : botão pressionado

As pseudo-classes começam com o caractere ":" (por exemplo :: hover ) nos seletores de CSS. Obviamente, você precisa especificar a qual componente sua pseudo-classe pertence - por exemplo, button: hover . O exemplo a seguir mostra um seletor que se aplica a todos os botões que têm foco:

 .button:focused { -fx-background-color: red; } 

Diferentemente do CSS, que possui apenas pseudo-classes básicas para estados como foco e foco , o JavaFX possui pseudo-classes específicas de componentes que se relacionam a diferentes estados ou propriedades de componentes.

Por exemplo:

  • As barras de rolagem têm pseudo-classes horizontais e verticais
  • Elementos (células) têm pseudo-classes ímpares e pares
  • O TitledPane expandiu e reduziu as pseudo-classes.

Pseudo-classes personalizadas


Além das pseudo-classes integradas, você pode definir e usar suas próprias pseudo-classes.

Vamos criar nosso próprio rótulo (herdado da classe Label). Ele terá uma nova propriedade lógica chamada brilhante . Nesse caso, queremos que nosso rótulo tenha uma pseudo classe brilhante .

Como a tag possui uma pseudo classe brilhante , podemos definir o plano de fundo da tag gold :

 .shiny-label:shiny { -fx-background-color: gold; } 

Agora crie a própria classe.

 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); } } 

Existem várias partes importantes aqui:

  1. Temos a propriedade booleana BooleanProperty em vez da booleana usual. Isso significa que o objeto brilhante é observável e podemos rastrear (ouvir) alterações em seu valor.
  2. Registramos um ouvinte que será chamado toda vez que o valor do objeto brilhante mudar usando shiny.addListener () .
  3. Quando o valor brilhante muda, adicionamos / removemos a pseudo- classe brilhante, dependendo do valor atual de pseudoClassStateChanged (PseudoClass.getPseudoClass ("shiny"), shiny.get ()) .
  4. Adicionamos uma classe personalizada para todos os rótulos de rótulo brilhante , em vez de ter apenas a classe de rótulo herdada do pai. Assim, só podemos selecionar tags brilhantes .

Folha de estilos padrão


Mesmo se você não fornecer nenhum estilo, cada aplicativo JavaFX já possui alguns estilos visuais. Há uma folha de estilo padrão que se aplica a todos os aplicativos. É chamado modena (desde o JavaFX 8, anteriormente era chamado caspian ).

Esta folha de estilo pode ser encontrada no arquivo:

jfxrt.jar \ com \ sun \ javafx \ cena \ controle \ skin \ modena \ modena.css

Ou você pode encontrar o arquivo aqui . No mesmo diretório, existem muitas imagens usadas pela folha de estilo.

Essa folha de estilo fornece estilos padrão, mas tem a prioridade mais baixa sobre outros tipos de folhas de estilo, para que você possa substituí-la facilmente.

Folha de estilo da cena


Além da folha de estilo padrão mencionada acima, é claro que você pode fornecer sua própria. O nível mais alto no qual você pode aplicar a estilização é toda a cena. Você pode implementar isso no seu FXML:

 <BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" stylesheets="styles.css" ... > ... </BorderPane> 

Ou no seu código Java:

 String stylesheet = getClass().getResource("/styles.css").toExternalForm(); scene.getStylesheets().add(stylesheet); 

Preste atenção na chamada paraExternalForm () . O Scene espera obter o conteúdo da folha de estilo como uma sequência, não como um arquivo, por isso precisamos fornecer o conteúdo da folha de estilo como uma sequência.

Folha de estilo principal


Além da folha de estilo para toda a cena, às vezes é útil ter estilos no nível do layout. Ou seja - para um contêiner separado, como VBox, HBox ou GridPane. O pai comum de todos os layouts é a classe pai, que define métodos para processar folhas de estilo no nível do layout. Esses estilos se aplicam apenas aos componentes desse layout e não à cena inteira. Um estilo no nível do layout tem precedência sobre um estilo no nível da cena.

 <HBox stylesheets="styles.css"> ... </HBox> 

Em Java, você precisa carregar o conteúdo da folha de estilo, como antes para a cena:

 HBox box = new HBox(); String stylesheet = getClass().getResource("/styles.css").toExternalForm(); box.getStylesheets().add(stylesheet); 

Estilos embutidos


Até agora, analisamos apenas os casos em que uma folha de estilo externa foi atribuída a uma cena ou layout inteiro. Mas você pode definir propriedades de estilo individuais no nível do componente.

Aqui você não precisa se preocupar com o seletor, pois todas as propriedades estão definidas para um componente específico.

Você pode especificar várias propriedades separadas por ponto e vírgula:

 <Label style="-fx-background-color: blue; -fx-text-fill: white"> I'm feeling blue. </Label> 

Em Java, você pode usar o método setStyle () :

 Label label = new Label("I'm feeling blue."); label.setStyle("-fx-background-color: blue; -fx-text-fill: white"); 

Os estilos no nível do componente têm precedência sobre os estilos de cena e os estilos pai no nível do layout.

Por que você precisa evitá-los


O estilo no nível do componente pode ser conveniente, mas é uma solução rápida e suja. Você está abandonando a principal vantagem do CSS, que é a separação de estilos de componentes. Agora você liga rigidamente seus elementos visuais diretamente aos componentes. Não é mais possível alternar facilmente suas folhas de estilo quando necessário; não é possível alterar os temas.

Além disso, você não tem mais um único local central onde seu estilo é definido. Quando você precisa alterar algo em um conjunto de componentes semelhantes, é necessário alterar cada um dos componentes separadamente e não editar apenas um local na folha de estilos externa. Portanto, os estilos de componentes em linha devem ser evitados.

Prioridades da folha de estilo


Você pode fornecer estilo em vários níveis - cena, pai, estilos embutidos e também há uma folha de estilo padrão do modem. Se você alterar a mesma propriedade do mesmo componente em vários níveis, o JavaFX possui uma configuração de prioridade que determina quais estilos devem ser usados. Lista de prioridades - da mais alta para a mais baixa:

  1. Estilos embutidos
  2. Estilos principais
  3. Estilos de cena
  4. Estilos padrão

Isso significa que, se você definir a cor de plano de fundo de um determinado rótulo no nível inline e na cena, o JavaFX utilizará o valor definido nos estilos inline, pois possui uma prioridade mais alta.

Leitura adicional


O JavaFX possui muitas propriedades CSS e sua descrição está além do escopo desta publicação; para obter uma lista detalhada, consulte o guia de referência oficial do CSS para JavaFX .

Source: https://habr.com/ru/post/pt477924/


All Articles