JavaFX开辟了新局面 [英] JavaFX open a new scene

查看:52
本文介绍了JavaFX开辟了新局面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望我的代码能够正常工作,以便当我单击一个按钮时,会打开一个新场景,但是它不起作用,我也不知道为什么.

I want my code to work such that when I click on a Button, a new scene opens, but it doesn't work and I don't know why.

public void start(Stage primaryStage) throws Exception {
    window = primaryStage;

    Parent root = FXMLLoader.load(getClass().getResource("FXML/LoginScene.fxml"));
    scene = new Scene(root,400,400);
    openScene = new OpenScene(writer);
    window.setScene(scene);
    window.show();


}
public static void main(String[] args){
    launch(args);
}
@FXML protected void btnConnect(ActionEvent event) {
    System.out.println("hallo");
    try {
        openScene.start(window);
    } catch (Exception e) {

        e.printStackTrace();
    }
}

GUI成功显示,但是当我按下Button时,它会引发异常.

The GUI successfully shows up, but when I press the Button, it throws an Exception.

public class OpenScene extends Application{
    PrintWriter writer;

    @Override
    public void start(Stage window) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXML/OpenScene.fxml"));
        Scene scene =  new Scene(root, 200 ,200);
        window.setScene(scene);
        window.show();

    }
    public OpenScene(PrintWriter writer){
        this.writer = writer;
    }
}

更新

我尝试将应用程序类与控制器类分开,如下面的James_D的答案所示,但出现以下异常:

I tried to separate the application class from the controller class as in James_D's answer below, but I got the following exception:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1762)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1645)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8216)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3724)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3452)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1728)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2461)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:348)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:273)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:382)
at com.sun.glass.ui.View.handleMouseEvent(View.java:553)
at com.sun.glass.ui.View.notifyMouse(View.java:925)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1759)
... 43 more
Caused by: java.lang.NullPointerException
at MainController.btnConnect(MainController.java:22)
... 53 more

推荐答案

您似乎正在尝试将主应用程序类用作控制器类.这将造成混乱,您应该避免这种情况.这是发生了什么:

It looks like you are trying to use your main application class as the controller class. This is going to be confusing, and you should avoid it. Here is what happens:

启动应用程序时,它将调用launch(...).从Application继承的launch方法将执行许多重要的内务处理",例如启动JavaFX工具包和JavaFX Application Thread.然后,它将创建您的应用程序子类的实例,创建初始的Stage并在该实例中调用start(...).

When you start up the application, it calls launch(...). The launch method, inherited from Application, will do a bunch of important "housekeeping", such as starting the JavaFX toolkit and the JavaFX Application Thread. It then creates an instance of your application subclass, creates an initial Stage and calls the start(...) in that instance.

start(...)方法中,您初始化了几个实例变量(windowopenScene),并加载了一个FXML文件,以显示其内容. FXMLLoader.load(...)方法执行以下操作:

In your start(...) method, you initialized a couple of instance variables (window and openScene), and loaded an FXML file, displaying its contents. The FXMLLoader.load(...) method does the following:

  • 基于文件中的XML元素创建UI元素
  • 在FXML文件中创建由fx:controller属性指定的类的实例
  • 将所有带有@FXML注释的字段注入到控制器实例中
  • 注册FXML文件中指定的所有事件处理程序
  • Creates UI elements based on the XML elements in the file
  • Creates an instance of the class specified by the fx:controller attribute in the FXML file
  • Injects any @FXML-annotated fields into the controller instance
  • Registers any event handlers specified in the FXML file

请注意,如果为应用程序和控制器指定相同的类,则将创建该类的两个实例.一种由launch方法创建,而另一种由FXMLLoader方法创建.请注意,只有launch方法创建的实例才调用start(...)方法.由于您是在start(...)方法中初始化实例变量的,因此这些变量不会在FXMLLoader创建的实例中初始化.因此,在由FXMLLoader创建的实例中(如果需要,可以称为控制器实例"),不会初始化windowopenScene.因此,线

Notice that if you specify the same class for the application and for the controller, two instances of that class will be created. One is created by the launch method, and one is created by the FXMLLoader. Note that only the instance created by the launch method has had the start(...) method invoked. Since you initialize the instance variables in the start(...) method, those variables are not initialized in the instance created by the FXMLLoader. So in the instance created by the FXMLLoader (the "controller instance", if you like), window and openScene are not initialized. Hence the line

    openScene.start(window);

将抛出NullPointerException.

由于应用程序和控制器实际上具有完全不同的角色,因此应将它们分为不同的类.这将使事情变得不那么混乱了.请注意,您始终可以通过调用

Since the application and controller really have completely different roles, you should separate them into different classes. This will make things far less confusing. Note that you can always find the window in which a node is displayed by calling

anyNode.getScene().getWindow();

因此无需缓存Stage实例.

所以:

public class MainApp extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        // change LoginScene.fxml so it now has fx:controller="LoginController"
        Parent root = FXMLLoader.load(getClass().getResource("FXML/LoginScene.fxml"));

        Scene scene = new Scene(root, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

并为控制器使用其他类:

and use a different class for the controller:

public class LoginController {

    private OpenScene openScene ;

    @FXML
    private Button connectButton ; // needs fx:id in fxml file...

    public void initialize() throws Exception {
        PrintWriter writer = ... ;
        openScene = new OpenScene(writer);
    }

    @FXML // handler for connect button:
    private void btnConnect() throws Exception {
        Stage stage = (Stage) connectButton.getScene().getWindow();
        openScene.start(stage);
    }
}

还请注意,您的OpenScene类无需成为Application子类:每个应用程序只需要一个这样的类:

Note also that there is no need for your OpenScene class to be an Application subclass: you only need one such class per application:

public class OpenScene {

    private final PrintWriter writer ;

    public OpenScene(PrintWriter writer) {
        this.writer = writer ;
    }

    // doesn't need to be called "start" any more...    
    public void start(Stage window) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXML/OpenScene.fxml"));
        Scene scene =  new Scene(root, 200 ,200);
        window.setScene(scene);
        window.show();
    }
}   

这篇关于JavaFX开辟了新局面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆