Como eu faço pra chamar uma Application várias vezes no JavaFX?

29 respostas Resolvido
java
T

Olá, eu sou iniciante no JavaFX, e no meu projeto eu gostaria de fazer algo como o setVisible da JFrame em uma Application do JavaFX. Alguém sabe me explicar como eu faço isso? Eu li que elas só podem ser chamadas uma vez. Tentei várias gambiarras como deixar o stage estático, dentre outras coisas, mas nada funcionou.

29 Respostas

T

Eu encontrei uma solução, mas desde já peço, se alguém achar que ficou meio gambiarra, me de uma solução melhor por favor. Eu não gostei assim, mas está funcionando pelo menos.

A classe da minha janela:

public class GoogleSignIn {

	private static Stage stage = new Stage();
	
	public static void start() throws IOException{
		Pane root = FXMLLoader.load(GoogleSignIn.class.getResource("/fxml/GoogleSignIn.fxml"));
		Scene scene = new Scene(root,818,641);
		stage.setScene(scene);
		stage.setTitle("Conectar-se");
		stage.show();
	}
	
}

E daí das outras classes eu só chamo;

GoogleSignIn.start();
A

Olá, criei uma classe utilitária que faz isso há um tempo, basicamente é um controller customizado, com eventos de show() -> equivalente ao setVisible(true), showModal entre outros.

Exemplo:

O código está aqui:


T

Gostei da sua ideia, é realmente bem útil. Mas sobre a classe TopMsg, onde eu encontro ela?

A

Essa foi é uma classe utilitária pra mostrar alertas, substitua por Alert.

T

O que eu passo como parâmetro do show? Minha janela não tem pai.

A

Passe null.

T

Passando null é retornado isso

LOAD VIEW
java.lang.RuntimeException: O painel principal não foi definido, sobreescreva o método getFXML ou getRootPane!
	at com.tkfentretenimento.meusdados.controller.WindowController.loadView(WindowController.java:153)
	at com.tkfentretenimento.meusdados.controller.WindowController.createShow(WindowController.java:164)
	at com.tkfentretenimento.meusdados.controller.WindowController.show(WindowController.java:158)
	at com.tkfentretenimento.meusdados.view.GoogleSignIn.displayWindow(GoogleSignIn.java:33)
	at com.tkfentreteniment.meusdados.start.Start.main(Start.java:15)
A

Faça conforme o exemplo, a exception é bem clara, e esse erro não ocorre por falta do pai. Basicamente no seu controller vc tem que apontar qual é o fxml que ele vai carregar.

T

Eu tinha uma application que carregava o fxml, então agora eu posso deleta-la e carregar direto no controller com o getFxml?

A

Sim, é isso mesmo. Mas passe todo o caminho do fxml.

T

Eu passei o caminho completo e verifiquei com um print, aparentemente não tem nada errado, e foi retornado esta exceção:

C:/Users/thall/workspace/Meus-Dados/target/classes/fxml/GoogleSignIn.fxml
Location is not set. - false
java.lang.IllegalStateException: Location is not set.
	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2434)
	at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
	at com.tkfentretenimento.meusdados.controller.WindowController.loadView(WindowController.java:130)
	at com.tkfentretenimento.meusdados.controller.WindowController.createShow(WindowController.java:164)
	at com.tkfentretenimento.meusdados.controller.WindowController.show(WindowController.java:158)
	at com.tkfentreteniment.meusdados.start.Start.main(Start.java:15)
A

O caminho começa a partir do /fxml ao que me parece. O que estiver antes disso é desnecessário. Quando falo “caminho” é relativo ao classpath da aplicação.

T

Eu fiz assim:

@Override
public String getFXML() {
    return getClass().getResource("/fxml/GoogleSignIn.fxml").toString().replace("file:/", "");
}
A

Não precisa, só passe a string “/fxml/GoogleSignIn.fxml”. O resto a classe faz

T

Okay, eu coloquei, e não tem mais problemas em localizar o arquivo, porém está sendo lançada agora uma exceção que eu nunca vi antes:

Exception in thread "main" java.lang.ExceptionInInitializerError
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
	at java.lang.reflect.Constructor.newInstance(Unknown Source)
	at java.lang.Class.newInstance(Unknown Source)
	at sun.reflect.misc.ReflectUtil.newInstance(Unknown Source)
	at javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1009)
	at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:746)
	at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
	at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
	at com.tkfentretenimento.meusdados.controller.WindowController.loadView(WindowController.java:130)
	at com.tkfentretenimento.meusdados.controller.WindowController.createShow(WindowController.java:164)
	at com.tkfentretenimento.meusdados.controller.WindowController.show(WindowController.java:158)
	at com.tkfentreteniment.meusdados.start.Start.main(Start.java:15)
Caused by: java.lang.IllegalStateException: Toolkit not initialized
	at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
	at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
	at com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:550)
	at com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:512)
	at javafx.scene.control.Control.<clinit>(Control.java:87)
	... 16 more
A

Vou colocar essas classes em uma biblioteca e disponibilizar no git, quando concluir posto o link aqui.

T

Fico aguardando. Sua biblioteca é realmente útil, poupa várias linhas de código. Mas sobre a exceção, tem ideia do que causou?

A

Não, nunca vi esse erro. Talvez algum erro de implementação. Só da pra saber vendo o código.

T

Claro, aqui está:

import javafx.scene.web.WebView;

import java.net.URL;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ResourceBundle;

import com.tkfentretenimento.meusdados.model.Constants;
import com.tkfentretenimento.meusdados.model.UserDAO;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.fxml.FXML;

public class Login extends WindowController{

	@FXML private WebView webview;

	@Override
	public void initialize(URL arg0, ResourceBundle arg1) {
		System.out.println(webview.getId());
		webview.getEngine().load("https://accounts.google.com/o/oauth2/auth?response_type=token&redirect_uri=http://localhost/meusdadoscallbacks/googlecallback.html&client_id=282550861704-ruv98no1oe9moimeh917fs31jtoc0mi7.apps.googleusercontent.com&scope="+Constants.SCOPES);
		webview.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
		     public void changed(ObservableValue ov, State oldState, State newState) {
		           if (newState == Worker.State.SUCCEEDED) {
		        	   	System.out.println(webview.getEngine().getLocation());
		                 if(webview.getEngine().getLocation().startsWith("http://localhost/meusdadoscallbacks/googlecallback.html")){
		                	String url = webview.getEngine().getLocation();
		     		    	String accessToken = url.substring(url.indexOf("=")+1, url.indexOf("&"));
		     		    	System.out.println("Acess Token: "+accessToken);
		     		    	try {
								new UserDAO(accessToken);
							} catch (ParseException e) {
								e.printStackTrace();
							} catch (SQLException e) {
								e.printStackTrace();
							}
		                 }
		           }
		     }
		});		
	}
	@Override
    public String getFXML() {
        return "/fxml/GoogleSignIn.fxml";
    }
    @FXML
    void ActionShow() {
        new Login()
                .setTitulo("Conectar-se")
                .show(getWindow()).altura(641).largura(818);
    }
    
    @FXML
    private void Close() {
        getWindow().close();
    }
}
T

Acho que eu descobri outra solução:

public class GoogleSignIn extends Application{

	@Override
	public void start(Stage primaryStage) throws Exception {
		Pane root = FXMLLoader.load(GoogleSignIn.class.getResource("/fxml/GoogleSignIn.fxml"));
		Scene scene = new Scene(root,818,641);
		primaryStage.setScene(scene);
		primaryStage.setTitle("Conectar-se");
		primaryStage.show();
		primaryStage.show();
	}

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

Daí nas outras classes eu chamo:

GoogleSignIn.launch(GoogleSignIn.class);
T

Conseguiu botar teu projeto lá no Git?

A

Já finalizei, mas não coloquei ainda…

A
Solucao aceita

Finalizei a biblioteca e publiquei no git:

T

Eu estou adaptando o meu projeto, porém eu notei que não existe um setFXML, e se eu quiser alterar a cena, é possível?

A

É possível, mas a ideia da lib é uma cena por janela, use:

getWindow().setScene(nova_cena);
T

Aparentemente funcionou, mas acho que eu fiz algo de errado. Eu estou recebendo o seguinte no console:

LOAD VIEW
false

/C:/Users/thall/workspace/Meus-Dados/target/classes/fxml/MainWindow.fxml
 - false
javafx.fxml.LoadException: 
/C:/Users/thall/workspace/Meus-Dados/target/classes/fxml/MainWindow.fxml

	at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
	at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
	at com.tkfentretenimento.meusdados.controller.WindowController.loadView(WindowController.java:130)
	at com.tkfentretenimento.meusdados.controller.WindowController.createShow(WindowController.java:164)
	at com.tkfentretenimento.meusdados.controller.WindowController.show(WindowController.java:158)
	at com.tkfentretenimento.meusdados.model.UserDAO.signInOffline(UserDAO.java:49)
	at com.tkfentretenimento.meusdados.model.UserDAO.isOfflineUser(UserDAO.java:33)
	at com.tkfentreteniment.meusdados.start.Start.<init>(Start.java:34)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
	at java.lang.reflect.Constructor.newInstance(Unknown Source)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:819)
	at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
	at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
	at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
	at com.tkfentretenimento.meusdados.controller.MainWindow.initialize(MainWindow.java:204)
	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
	... 21 more

Eu já conferi, não tem nada de errado no fx:controller e o FXML foi carregado (eu acho). A única coisa que tem nessas linhas das casses da minha aplicação citadas na exceção é isso:

new MainWindow().show(null);
A

Não sei se está usando a minha lib, pois nela não existe método show com parâmetros, de qualquer forma veja seu método initialize tem algo errado nele.

T

Valeu cara, eu realmente não estava utilizando a biblioteca. Eu peguei o .jar e adicionei na aplicação, porém eu não percebi que eu não havia deletado o WindowController antigo da minha src, e também não vi que tu mudou o nome para WindowControllerFx, e eu estendi de WindowController. Agora minha aplicação está funcionando perfeitamente, muito obrigado pela ajuda mesmo. Ah, eu esqueci de explicar porque eu preciso alterar a cena. É que eu tenho uma animação de fade entre elas, ao invés de ter várias telas que mudam com o botão next, eu tenho uma tela que passa uma animação de fade e troca o conteúdo.

A

Entendi, já fiz isso mas de outras formas (sem trocar a cena). Somete tinha um stackpane root e trocava seu conteúdo e jogava uma animação…
Mas blz, que bom que deu certo.

Criado 31 de janeiro de 2017
Ultima resposta 23 de fev. de 2017
Respostas 29
Participantes 2