Introdução ao JavaFx

Introdução ao JavaFx

1. Introdução

JavaFX é uma biblioteca para criar aplicativos rich client com Java. It provides an API for designing GUI applications executados em quase todos os dispositivos com suporte a Java.

Neste tutorial, vamos nos concentrar e cobrir alguns de seus principais recursos e funcionalidades.

2. API JavaFX

Nos Java 8, 9 e 10, nenhuma configuração adicional é necessária para começar a trabalhar com a biblioteca JavaFX. O projeto será removido do JDK começando com o JDK 11.

2.1. Arquitetura

JavaFX uses hardware accelerated graphics pipeline for the rendering, known as Prism. Além do mais, para acelerar totalmente o uso de gráficos, ele alavanca o mecanismo de renderização de software ou hardware, usando internamenteDirectXeOpenGL.

JavaFX has a platform dependent Glass windowing toolkit layer to connect to the native operating system. Ele usa a fila de eventos do sistema operacional para agendar o uso do thread. Além disso, ele lida de forma assíncrona com janelas, eventos e timers.

Os mecanismosMediaeWeb habilitam a reprodução de mídia e suporte a HTML / CSS.

Vamos ver como é omain structure de um aplicativo JavaFX:

image

 

Aqui, observamos dois contêineres principais:

  • Stage is the main container and the entry point of the application. Ele representa a janela principal e é passado como um argumento do métodostart().

  • Scene é um contêiner para conter os elementos da IU, como visualizações de imagens, botões, grades, caixas de texto.

OScene pode ser substituído ou alternado para outroScene. Isso representa um gráfico de objetos hierárquicos, conhecido como GráficoScene. Cada elemento nessa hierarquia é chamado de nó. Um único nó possui seu ID, estilo, efeitos, manipuladores de eventos, estado.

Além disso, oScene também contém os contêineres de layout, imagens e mídia.

2.2. Tópicos

No nível do sistema,the JVM creates separate threads for running and rendering the application:

  • Prism thread de renderização - responsável por renderizarScene Graph separadamente.

  • Encadeamento de aplicativo - é o encadeamento principal de qualquer aplicativo JavaFX. Todos os nós e componentes ativos estão anexados a este encadeamento.

2.3. Ciclo da vida

A classejavafx.application.Application tem os seguintes métodos de ciclo de vida:

  • init() – is called after the application instance is created. Neste ponto, a API JavaFX ainda não está pronta, então não podemos criar componentes gráficos aqui.

  • start(Stage stage) - todos os componentes gráficos são criados aqui. Além disso,the main thread for the graphical activities starts here.

  • stop() - é chamado antes do encerramento do aplicativo; por exemplo, quando um usuário fecha a janela principal. É útil substituir esse método para alguma limpeza antes do encerramento do aplicativo.

O métodolaunch() estático inicia o aplicativo JavaFX.

2.4. FXML

JavaFX usa uma linguagem de marcação FXML especial para criar as interfaces de visualização.

Isso fornece uma estrutura baseada em XML para separar a visualização da lógica de negócios. XML é mais adequado aqui, pois é capaz de representar naturalmente uma hierarquiaScene Graph.

Por fim, para carregar o arquivo.fxml, usamos a classeFXMLLoader, que resulta no gráfico do objeto da hierarquia da cena.

3. Começando

Para ser prático, elet’s build a small application that allows searching through a list of people.

Primeiro, vamos adicionar uma classe de modeloPerson - para representar nosso domínio:

public class Person {
    private SimpleIntegerProperty id;
    private SimpleStringProperty name;
    private SimpleBooleanProperty isEmployed;

    // getters, setters
}

Observe como, para encerrar os valoresint, Stringeboolean, estamos usando as classesSimpleIntegerProperty, SimpleStringProperty, SimpleBooleanProperty no pacotejavafx.beans.property.

A seguir, vamos criar a classeMain que estende a classe abstrataApplication:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(
          Main.class.getResource("/SearchController.fxml"));
        AnchorPane page = (AnchorPane) loader.load();
        Scene scene = new Scene(page);

        primaryStage.setTitle("Title goes here");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

Nossa classe principal substitui o métodostart(), que é o ponto de entrada para o programa.

Então, oFXMLLoader carrega a hierarquia do gráfico de objeto deSearchController.fxml paraAnchorPane.

Depois de iniciar um novoScene, nós o definimos comoStage primário. Também definimos o título de nossa janela eshow().

Observe que é útil incluir o métodomain() para poder executar o arquivo JAR sem oJavaFX Launcher.

3.1. FXML View

Vamos agora mergulhar mais fundo no arquivo XMLSearchController.

Para nosso aplicativo de pesquisa, adicionaremos um campo de texto para inserir a palavra-chave e o botão de pesquisa:


    

        
            
                

AnchorPane é o contêiner raiz aqui e o primeiro nó da hierarquia do gráfico. Ao redimensionar a janela, ele reposicionará o filho no seu ponto de ancoragem. The fx: controller attribute wires the Java class with the markup.

Existem alguns outros layouts internos disponíveis:

  • BorderPane - divide o layout em cinco seções: superior, direita, inferior, esquerda, centro

  • HBox – organiza os componentes filhos em um painel horizontal

  • VBox – os nós filhos são organizados em uma coluna vertical

  • GridPane - útil para criar uma grade com linhas e colunas

Em nosso exemplo, dentro do painel horizontalHBox, usamosLabel para colocar o texto,TextField para a entrada eButton. Comfx: id marcamos os elementos para que possamos usá-los posteriormente no código Java.

Então, para mapeá-los para os campos Java - usamos a anotação@FXML:

public class SearchController {

    @FXML
    private TextField searchField;
    @FXML
    private Button searchButton;

    @FXML
    private void initialize() {
        // search panel
        searchButton.setText("Search");
        searchButton.setOnAction(event -> loadData());
        searchButton.setStyle("-fx-background-color: #457ecd; -fx-text-fill: #ffffff;");
    }
}

After populating the @FXML annotated fields, initialize() will be called automatically. Aqui, podemos realizar outras ações sobre os componentes da IU - como registrar ouvintes de eventos, adicionar estilo ou alterar a propriedade do texto.

Por fim, toda essa lógica descrita aqui produzirá a seguinte janela:

image

4. Binding API

Agora que os aspectos visuais foram tratados, vamos começar a olhar para os dados de ligação.

A API de ligação fornece algumas interfaces que notificam objetos quando ocorre uma alteração de valor de outro objeto.

Podemos vincular um valor usando o métodobind() ou adicionando ouvintes.

A ligação unidirecional fornece uma ligação apenas para uma direção:

searchLabel.textProperty().bind(searchField.textProperty());

Aqui, qualquer alteração no campo de pesquisa atualizará o valor do texto do rótulo.

Por comparação, a ligação bidirecional sincroniza os valores de duas propriedades nas duas direções.

A forma alternativa de vincular os campos éChangeListeners:

searchField.textProperty().addListener((observable, oldValue, newValue) -> {
    searchLabel.setText(newValue);
});

A interfaceObservable permite observar o valor do objeto para alterações.

Para exemplificar isso, a implementação mais comumente usada é a interfacejavafx.collections.ObservableList<T>:

ObservableList masterData = FXCollections.observableArrayList();

Aqui, qualquer alteração de modelo, como inserção, atualização ou remoção dos elementos, notificará os controles da interface do usuário imediatamente.

5. Concorrência

Working with the UI components in a scene graph isn’t thread-safe, as it’s accessed only from the Application thread. O pacotejavafx.concurrent está aqui para ajudar com multithreading.

Vamos ver como podemos realizar a pesquisa de dados no thread de segundo plano:

Task> task = new Task>() {
    @Override
    protected ObservableList call() throws Exception {
        updateMessage("Loading data");
        return FXCollections.observableArrayList(masterData
          .stream()
          .filter(value -> value.getName().toLowerCase().contains(searchText))
          .collect(Collectors.toList()));
    }
};

Aqui, criamos um objetojavafx.concurrent.Task de tarefa única e substituímos o métodocall().

The call() method runs entirely on the background thread and returns the result to the Application thread. Isso significa que qualquer manipulação dos componentes da IU dentro deste método lançará uma exceção de tempo de execução.

No entanto,updateProgress(), updateMessage() pode ser chamado para atualizar itens de thread do aplicativo. Quando o estado da tarefa muda para o estado SUCCEEDED, o manipulador de eventosonSucceeded() é chamado a partir do thread do aplicativo:

task.setOnSucceeded(event -> {
    masterData = task.getValue();
    // update other UI components
});

OTask éRunnable, então, para iniciá-lo, precisamos apenas iniciar um novoThread com o parâmetrotask:

Thread th = new Thread(task);
th.setDaemon(true);
th.start();

O sinalizadorsetDaemon(true) indica que o encadeamento será encerrado após o término do trabalho.

6. Manipulação de eventos

Podemos descrever um evento como uma ação que pode ser interessante para o aplicativo.

Por exemplo, as ações do usuário, como cliques do mouse, pressionamentos de tecla, redimensionamento de janela, são tratadas ou notificadas pela classejavafx.event.Event ou qualquer uma de suas subclasses.

Além disso, distinguimos três tipos de eventos:

  • InputEvent - todos os tipos de ações de tecla e mouse comoKEY_PRESSED, KEY_TYPED, KEY_RELEASED ouMOUSE_PRESSES, MOUSE_RELEASED

  • ActionEvent - representa uma variedade de ações como disparar umButton ou terminar umKeyFrame

  • WindowEvent -WINDOW_SHOWING, WINDOW_SHOWN

Para demonstrar, o fragmento de código abaixo captura o evento de pressionar a teclaEnter sobresearchField:

searchField.setOnKeyPressed(event -> {
    if (event.getCode().equals(KeyCode.ENTER)) {
        //search and load some data
    }
});

7. Estilo

Podemos alterar a IU do aplicativo JavaFX aplicando um design personalizado a ele.

Por padrão, o JavaFX usamodena.css como um recurso CSS para todo o aplicativo. Isso é uma parte dejfxrt.jar.

Para substituir o estilo padrão, podemos adicionar uma folha de estilo à cena:

scene.getStylesheets().add("/search.css");

Também podemos usar o estilo embutido; por exemplo, para definir uma propriedade de estilo para um nó específico:

searchButton.setStyle("-fx-background-color: slateblue; -fx-text-fill: white;");

8. Conclusão

Esta breve descrição abrange os conceitos básicos da API JavaFX. Examinamos a estrutura interna e introduzimos os principais recursos de sua arquitetura, ciclo de vida e componentes.

Como resultado, aprendemos e agora podemos criar um aplicativo GUI simples.

E, como sempre, o código-fonte completo do tutorial está disponívelover on GitHub.