javaFX - alandrade21/docsCompartilhados GitHub Wiki
Nesta página:
- Maven
- Estrutura JavaFX e Ciclo de Vida
- Passagem de Parâmetros para a Aplicação
- JavaFX com Spring Boot
- Problemas Debugando JavaFX no Eclipse
- Problemas com Autocomplete de CSS do JavaFX
Ao criar um projeto novo, o template org.openjfx.javafx-archetype-fxml
do maven central.
Um projeto javaFX tem as seguintes dependências:
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>19</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>19</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>19</version>
</dependency>
javafx.base
é uma dependência transitiva. Outros pacotes podem ser acrescidos, a depender das necessidades, como javafs.graphics
, ou suporte à 3D.
Ainda é necessário o plugin abaixo:
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>br.eti.alandrade21.myApp/br.eti.alandrade21.myApp.Launcher</mainClass>
</configuration>
</execution>
<execution>
<!-- Configuration for debugging -->
<id>debug</id>
<configuration>
<options>
<option>-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8000</option>
</options>
<mainClass>br.eti.alandrade21.myApp/br.eti.alandrade21.myApp.Launcher</mainClass>
</configuration>
</execution>
</executions>
</plugin>
Essa configuração define qual é a classe com o método main, no formato nome-do-módulo/nome-da-classe
.
No projeto é necessário a definição do module-info.java
. Um exemplo abaixo:
module br.eti.alandrade21.myApp {
requires javafx.controls;
requires javafx.fxml;
requires javafx.web;
requires javafx.graphics;
opens br.eti.alandrade21.myApp to javafx.fxml;
opens br.eti.alandrade21.myApp.controller to javafx.fxml;
exports br.eti.alandrade21.myApp;
}
O primeiro bloco declara quais pacotes do jFX serão utilizados pelo seu sistema.
O javaFX faz uma série de reflections com o seu código. Para permitir esses reflections é necessário as cláusulas open
.
package br.eti.alandrade21.myApp;
import javafx.application.Application;
import javafx.stage.Stage;
import java.Exception;
/**
* JavaFX App
*/
public class Launcher extends Application {
public static void main(String[] args) {
launch();
}
@Override
public void start(Stage stage) throws Exception {
// Disparo da aplicação.
}
}
O método launch()
só retorna qdo todas as janelas são fechadas (javafx.application.Platform.setImplicitExit(true)
, o que vem setado por padrão), ou quando javafx.application.Platform.exit()
é chamado.
Após o disparo do método launch()
, o javaFX chama os seguintes métodos da classe que herda de Applications
:
- O construtor padrão.
- O método init().
- O método start(stage).
- O método stop().
init
e stop
estão vazios na classe Application
.
@Override
public void start(Stage stage) {
// Get application parameters
Parameters p = this.getParameters();
Map<String, String> namedParams = p.getNamed();
List<String> unnamedParams = p.getUnnamed();
List<String> rawParams = p.getRaw();
...
}
Parâmetros nomeados são passados na forma --key=value
. Então na seguinte linha de parâmetros ... Anna Lola --width=200 --heigh=100
:
- Há dois parâmetros não nomeados e dois nomeados.
- A lista de parâmetros raw conteria algo como
[Anna, Lola, --width=200, --height=100]
.
As informações condensadas nesta seção fora retiradas de:
Ao configurar o POM do projeto é necessário inserir um starter adicional ao spring-boot-starter
. Neste exemplo usamos o spring-boot-starter-data-jpa
.
Por segurança, recomenda-se colocar a entrada spring.main.web-application-type=none
no arquivo application.properties
. Caso o módulo web do spring acabe no module path, o projeto não será considerado um projeto web pelo spring.
O spring-boot-maven-plugin
fica configurado da seguinte maneira:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
<executable>true</executable>
</configuration>
</plugin>
Essa configuração faz com que o jar gerado contenha todos os jars das dependências em uso no projeto (com exceção do jar do lombok
).
A entrada <executable>true</executable>
faz com que, ao executar o comando mvn clean package
, o jar gerado seja executável a partir do prompt de comando (com o comando ./meujar.jar).
Para que o projeto seja compilado corretamente, é necessário importar vários módulos do spring, e abrir os módulos do projeto para esses módulos do spring. Abaixo, um exemplo:
module br.eti.alandrade21.meuProjeto {
requires javafx.controls;
requires javafx.fxml;
requires spring.boot.autoconfigure;
requires spring.boot;
requires spring.context;
requires spring.beans;
requires spring.core;
requires javafx.graphics;
opens br.eti.alandrade21.meuProjeto to javafx.fxml, spring.core;
opens br.eti.alandrade21.meuProjeto.pages to spring.beans, spring.core;
exports br.eti.alandrade21.meuProjeto;
}
Num projeto JavaFX com SpringBoot, o ideal é deixar o bootstrap da aplicação por conta do JavaFX, e deixar o JavaFX fazer o bootstrap do Spring.
Assim, na classe que contiver o método main
, ao invés de fazermos SpringApplication.run(AppSpring.class, args);
como de praxe, vamos inicializar o JavaFX com o uso da classe javafx.application.Application;
, conforme mostrado no exemplo abaixo:
package br.eti.alandrade21.meuProjeto;
import javafx.application.Application;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
@EnableAutoConfiguration(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
@SpringBootApplication
public class AppSpring {
public static void main(String[] args) {
Application.launch(AppFX.class, args);
}
}
A anotação @EnableAutoConfiguration
acima foi colocada apenas para fazer com que a aplicação rode sem a necessidade de fazer a configuração do JPA. Feita a configuração, ela pode ser retirada.
A classe AppFX
referenciada acima é a classe que herda de javafx.application.Application
e possui o método start
. O código dessa classe é mostrado abaixo:
package br.eti.alandrade21.meuProjeto;
import java.io.IOException;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import br.eti.alandrade21.meuProjeto.config.StageReadyEvent;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.Stage;
public class AppFX extends Application {
private ConfigurableApplicationContext springContext;
@Override
public void init() throws Exception {
ApplicationContextInitializer<GenericApplicationContext> initializer =
ac -> {
ac.registerBean(Application.class, () -> AppFX.this);
};
this.springContext = new SpringApplicationBuilder()
.sources(AppSpring.class)
.initializers(initializer)
.run(getParameters().getRaw().toArray(new String[0]));
}
@Override
public void start(Stage primaryStage) throws Exception {
this.springContext.publishEvent(new StageReadyEvent(primaryStage));
}
@Override
public void stop() throws Exception {
this.springContext.close();
Platform.exit();
}
}
O método init
faz o bootstrap do spring, criando o contexto do string e registrando os objetos que forem necessários do JavaFX como spring beans. No exemplo acima apenas a própria classe AppFX
é registrada como um spring bean.
Ao iniciar o contexto spring, os parâmetros de disparo da aplicação são passados para o spring.
De forma similar, o método stop
faz o encerramento do contexto spring.
No método start é disparado um evento para avisar ao spring que a parte JavaFX já está pronta, e publicando o primaryStage
criado durante a inicialização do JavaFX. O evento disparado é do tipo StageReadyEvent
, implementado na própria aplicação. Essa classe é mostrada abaixo:
package br.eti.alandrade21.meuProjeto.config;
import org.springframework.context.ApplicationEvent;
import javafx.stage.Stage;
public class StageReadyEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
public StageReadyEvent(Stage source) {
super(source);
}
public Stage getStage() {
return (Stage)getSource();
}
}
O passo final é criar uma classe responsável por interceptar esse evento e criar a primeira janela da aplicação, conforme mostrado abaixo:
package br.eti.alandrade21.meuProjeto.pages;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import br.eti.alandrade21.meuProjeto.PrimaryController;
import br.eti.alandrade21.meuProjeto.config.StageReadyEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
@Component
public class ViewFactory implements ApplicationListener<StageReadyEvent>{
@Autowired
PrimaryController primaryController;
@Override
public void onApplicationEvent(StageReadyEvent event) {
Stage stage = event.getStage();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("primary.fxml"));
fxmlLoader.setController(primaryController);
Parent parent;
try {
parent = fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
return;
}
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
}
}
Debugar JavaFX no linux pode causar o travamento do gnome, deixando o mouse se mexer mas não deixando clicar em nenhum elemento.
Se esse for o caso, vá na configuração de debug e acrescente o argumento de VM -Dsun.awt.disablegrab=true
.
Caso o editor de CSS não reconheça as classes e elementos CSS do JavaFX, será necessário ir às propriedades do projeto no eclipse, na opção Java Build Path
e adicionar um novo jar ao classpath. Esse jar é o org.eclipse.fx.ide.css.jfx8_<número>.jar
, que fica na raiz da pasta de plugins dentro da pasta de instalação do eclipse.