为什么JavaFx应用程序必须从它自己的类中启动?

时间:2016-09-28 13:17:08

标签: java javafx

我尝试了以下代码,并被迫启动名为Viewer的JavaFx应用程序而不直接调用方法launch

这是JavaFx类:

package Freelance;

public class Viewer extends Application
{
    private WebEngine myWebEngine;

    public void start(Stage stage)
    {
        stage.setTitle("Browser");

        WebView myBrowser = new WebView();
        myWebEngine = myBrowser.getEngine();
        myWebEngine.getLoadWorker().exceptionProperty().addListener(new ChangeListener<Throwable>()
        {
            @Override
            public void changed(ObservableValue<? extends Throwable> observableValue, Throwable oldException,
                    Throwable exception)
            {
                System.out.println("WebView encountered an exception loading a page: " + exception);
            }
        });
        myBrowser.setPrefSize(1600, 900);

        BorderPane root = new BorderPane();
        root.setCenter(myBrowser);
        stage.setScene(new Scene(root));
        stage.show();
        myWebEngine.load("http://www.google.com/");

    }

    public static void run()
    {
        launch("");
    }

}

现在当我尝试从一个单独的类中启动它时:

package Freelance;

public class Test
{

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

}

我收到以下错误:

Exception in thread "main" java.lang.RuntimeException: Error: class Freelance.Test is not a subclass of javafx.application.Application
    at javafx.application.Application.launch(Application.java:254)
    at Freelance.Test.main(Test.java:8)

但是,如果我像这样改变Test类:

package Freelance;

public class Test
{

    public static void main(String[] args)
    {
        Viewer.run(); // Changed from using "launch()" to "run()"
    }

}

然后它可以正常工作并启动。

所以我很好奇为什么会发生这种情况,或者我是以不正确的格式编写代码。

谢谢。

3 个答案:

答案 0 :(得分:7)

由于launch是一个静态方法,因此在编译之后,不能通过检查堆栈以外的方式确定应用程序类

Application.launch("");

在字节码中与

结尾相同
Viewer.launch("");

只有在堆栈中的某个地方找到Application类时,检查堆栈才有效。这就是为什么需要从launch类调用Application

但是有另一种选择:
您可以将Application课程传递给the overloaded version of the launch method

Application.launch(Viewer.class, "");

答案 1 :(得分:4)

It doesn't必须从Application子类中启动。

你可以做到

package Freelance;

import javafx.application.Application ;

public class Test
{

    public static void main(String[] args)
    {
        Application.launch(Viewer.class, args);
    }

}

答案 2 :(得分:1)

当您查看javafx.application.Apllication launch(String... args)的实施时,您会发现以下代码:

public static void launch(String... args) {
    // Figure out the right class to call
    StackTraceElement[] cause = Thread.currentThread().getStackTrace();

    boolean foundThisMethod = false;
    String callingClassName = null;
    for (StackTraceElement se : cause) {
        // Skip entries until we get to the entry for this class
        String className = se.getClassName();
        String methodName = se.getMethodName();
        if (foundThisMethod) {
            callingClassName = className;
            break;
        } else if (Application.class.getName().equals(className)
                && "launch".equals(methodName)) {

            foundThisMethod = true;
        }
    }

    if (callingClassName == null) {
        throw new RuntimeException("Error: unable to determine Application class");
    }

    try {
        Class theClass = Class.forName(callingClassName, false,
                           Thread.currentThread().getContextClassLoader());
        if (Application.class.isAssignableFrom(theClass)) {
            Class<? extends Application> appClass = theClass;
            LauncherImpl.launchApplication(appClass, args);
        } else {
            throw new RuntimeException("Error: " + theClass
                    + " is not a subclass of javafx.application.Application");
        }
    } catch (RuntimeException ex) {
        throw ex;
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

如您所见,foreach循环遍历堆栈跟踪。这意味着:您需要在提供launch(String... args)方法的类中调用start()方法。

fabianJames_D的答案提供了有关如何在另一个类中启动JavaFX Applications表单的示例。