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

29 respostas Resolvido
java
Thallysson

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

Thallysson

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();
Andrauss

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:


Thallysson

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

Andrauss

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

Thallysson

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

Andrauss

Passe null.

Thallysson

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)
Andrauss

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.

Thallysson

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

Andrauss

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

Thallysson

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)
Andrauss

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.

Thallysson

Eu fiz assim:

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

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

Thallysson

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
Andrauss

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

Thallysson

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

Andrauss

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

Thallysson

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

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

Conseguiu botar teu projeto lá no Git?

Andrauss

Já finalizei, mas não coloquei ainda…

Andrauss
Solucao aceita

Finalizei a biblioteca e publiquei no git:

Thallysson

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?

Andrauss

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

getWindow().setScene(nova_cena);
Thallysson

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

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.

Thallysson

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.

Andrauss

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