【问题标题】:JavaFX can't edit textJavaFX 无法编辑文本
【发布时间】:2015-07-27 17:31:46
【问题描述】:

我有:2 个 FXML 文件和 2 个控制器。每个 FXML 都合并了控制器。这是打开新 FXML 的代码(当真正的 fxml 运行时,它会打开另一个)

try {
            Parent root = FXMLLoader.load(getClass().getResource(
                    "settings.fxml"));
         Stage stage = new Stage();
         stage.setScene(new Scene(root));  
         stage.centerOnScreen();
         stage.show();
        } catch (Exception e) {
            e.printStackTrace();
            Logger.logCrash("ApplicationScene", e);
        }

这是打开的 FXML 文件的控制器

    @FXML
    public TextField destination;
    @FXML
    public TextArea view;
    @FXML
    public TextArea point;


    public void initialize() {
        destination.appendText("LOL");
        view.appendText("LAA");
        point.appendText("LOWKAPF");
    }

如您所见,在通过初始化方法加载根之后,我在所有声明的字段(FXML-ID'S ARE BOUND!)上附加文本。听起来不错,很棒,但我得到了 NullPointerException。

明确指出: - 我已经将 fxml-ids 绑定到它们相应的组件。 - FXML 文件被正确加载(root 被正确加载,否则初始化方法不起作用)

这与静态访问无关。即使没有静态访问,这也不起作用。

    <?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="373.0" prefWidth="518.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="removed">
   <children>
      <TextField fx:id="destination" layoutX="14.0" layoutY="19.0" prefHeight="25.0" prefWidth="464.0" promptText="Destination of the files" text="ie.: C:\" />
      <Text layoutX="14.0" layoutY="57.0" strokeType="OUTSIDE" strokeWidth="0.0" text="moo" wrappingWidth="464.0" />
      <TextArea fx:id="point" layoutX="14.0" layoutY="76.0" prefHeight="42.0" prefWidth="464.0" promptText="HI/>
      <Text layoutX="14.0" layoutY="131.0" strokeType="OUTSIDE" strokeWidth="0.0" text="meow" wrappingWidth="464.0" />
      <TextArea fx:id="view" layoutX="14.0" layoutY="135.0" prefHeight="42.0" prefWidth="464.0" promptText="HI" />
      <Text layoutX="14.0" layoutY="191.0" strokeType="OUTSIDE" strokeWidth="0.0" text="m00" wrappingWidth="464.0" />
      <Button layoutX="220.0" layoutY="269.0" mnemonicParsing="false" onAction="#initialize" text="Default" />
   </children>
</AnchorPane>

哦。好的,所以,我所做的是:

    package com.engine.application.content;

import com.engine.Logger;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Settings extends Application {

    public static void start() {
        Application.launch();
    }
    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource(
                "settings.fxml"));
        Scene scene = new Scene(root);
        setStageProperties(primaryStage, scene);

    }

    /**
     * Sets the properties of the application
     * 
     * @param stage
     *            the stage's properties to set
     * @param scene
     *            the scene's properties to set
     */
    private void setStageProperties(Stage stage, Scene scene) {
        stage.setScene(scene);
        stage.setTitle("Test");
        stage.centerOnScreen();
        stage.setResizable(true);
        stage.show();
        Logger.log("Launcher", "Set stage properties");
    }

}

那我打电话
应用程序.start() 当一个按钮被点击时

这是结果:

Caused by: java.lang.IllegalStateException: Application launch must not be called more than once
    at com.sun.javafx.application.LauncherImpl.launchApplication(Unknown Source)
    at com.sun.javafx.application.LauncherImpl.launchApplication(Unknown Source)
    at javafx.application.Application.launch(Unknown Source)
    at xxx.Settings.start(Settings.java:14)
    at xxx.openMenu(ApplicationScene.java:43)
    ... 56 more

顺便说一句,我不会在其他地方称呼它。

编辑: 这是设置应用程序初始化。

public class Settings extends Application {

public static void main(String[] args) {
    launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource(
            "settings.fxml"));
    Scene scene = new Scene(root);
    setStageProperties(primaryStage, scene);
    System.out.println("YAY");

}

/**
 * Sets the properties of the application
 * 
 * @param stage
 *            the stage's properties to set
 * @param scene
 *            the scene's properties to set
 */
private void setStageProperties(Stage stage, Scene scene) {
    stage.setScene(scene);
    stage.setTitle("Test");
    stage.centerOnScreen();
    stage.setResizable(true);
    ApplicationScene.settingsMenu = stage;
    Logger.log("Launcher", "Set stage properties");
}

}

这是主应用程序 公共类 ApplicationLauncher 扩展应用程序 {

/**
 * The main method
 * 
 * @param args
 *            the arguments given upon start
 */
public static void main(String args[]) {
    launch(args);
}

@Override
public void start(Stage stage) throws Exception {
    Logger.log("Launcher", "Starting up..");
    Parent root = FXMLLoader.load(getClass().getResource(
            "ah.fxml"));
    Directory directory = new Directory();
//  Logger.logError("LOL", "ERROR! LOLOLOL L /n LOL \n LOL LOL");
    Scene scene = new Scene(root);
    directory.createFolder();
    setStageProperties(stage, scene);
    Settings.main(null);
    Logger.log("Launcher", "Application started up!");
}

/**
 * Sets the properties of the application
 * 
 * @param stage
 *            the stage's properties to set
 * @param scene
 *            the scene's properties to set
 */
private void setStageProperties(Stage stage, Scene scene) {
    stage.setScene(scene);
    stage.setTitle("Test");
    stage.centerOnScreen();
    stage.setResizable(true);
    stage.show();
    Logger.log("Launcher", "Set stage properties");
}

}

结果:

Caused by: java.lang.IllegalStateException: Application launch must not be called more than once

别无他法。 (顺便说一句。做 Settings.main(null); 与 Settings.launch(); 相同)

重新思考这个概念后

做到了:

new Settings().start(new Scene());

【问题讨论】:

  • 您不需要静态访问。确保为您的FXML 文档填写了fx:id="something"。 “某事”部分必须正是您的变量名。因此,在您的 FXML 中,您有 fx:id="destination",而在您的控制器中,您有 @FXML public TextField destination;。它们也必须与类型匹配。并且不要忘记让你的 FXML 使用你的控制器作为控制器,否则事情不会被正确初始化。
  • 如果你把字段设为static,那肯定不行。如果更正后仍然无法正常工作,那么您还有其他错误。发布 FXML 文件,否则我们只能猜测这些错误是什么(@SnakeDoc 做出了一些很好的猜测,但您需要显示您的代码才能知道其中哪些(如果有)是问题)。
  • @SnakeDoc FX id 是正确的。
  • 编辑帖子以显示打开窗口的 F​​XML 文件
  • @Sh0ck 请粘贴您的完整控制器以及extends Application 或调用launch() 静态方法的类文件。

标签: java xml javafx fxml


【解决方案1】:

与@SnakeDoc 讨论了很久,我们终于解决了。

对于遇到相同问题的任何人:

new Settings().start(new Scene());

这样做。由于 start 方法基本上完成了所有工作(加载 FXML 等),因此只需要那行代码。

如果您仍然遇到问题,请确保 FXID 与要连接的实例的变量名称相同。

【讨论】:

    【解决方案2】:

    这是嵌入在主应用程序控制器中的一些逻辑的示例:

    // somewhere in the declarations for the controller class
    private Parent webViewRoot;
    private Stage webViewStage;
    private Scene webViewScene;
    private Path webViewFXML;
    
    // somewhere in the logic section of the controller class
    public void handleToggleWebView(final ActionEvent event) {
        initWebView();
        if (toggleWebView.isSelected()) {
            webViewStage.show();
        } else {
            webViewStage.close();
        }
    }
    
    private void initWebView() {
        if (webViewFXML == null) {
            webViewFXML = Paths.get(ConfigurationManager.ProdFeature.getHomeDirectory() 
                    + File.separator + "resources" + File.separator + "WebView.fxml");
        }
        if (webViewRoot == null) {
            try {
                final FXMLLoader fxmlloader = new FXMLLoader(webViewFXML.toUri().toURL());
                fxmlloader.setRoot(webViewRoot);
                fxmlloader.setController(WebViewController.getInstance());
                webViewRoot = fxmlloader.load();
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
                final Dialog exceptionDialog = new Dialog.Builder(DialogType.EXCEPTION)
                .setTitle("ERROR").setHeaderText("Failed to load WebView FXML.")
                .setException(e).build();
                exceptionDialog.showAndWait();
                return;
            }
        }
        if (webViewScene == null) {
            webViewScene = new Scene(webViewRoot);
        }
        if (webViewStage == null) {
            webViewStage = new Stage();
            try {
                // add icon
                Path icon = Paths.get(ConfigurationManager.ProdFeature.getHomeDirectory() 
                        + File.separator + "resources" + File.separator + "logo.png");
                webViewStage.getIcons().add(new Image(icon.toUri().toURL().toExternalForm()));
            } catch (Exception e) {
                // ignore
            }
    
            StringBuilder title = new StringBuilder();
            title.append(ConfigurationManager.ProdFeature.getString("prodfeature.program.name"));
            title.append(" WebView | version ");
            title.append(ConfigurationManager.ProdFeature.getString("prodfeature.program.version"));
            webViewStage.setTitle(title.toString());
            webViewStage.setScene(webViewScene);
            webViewStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
                @Override
                public void handle(final WindowEvent we) {
                    we.consume();
                    toggleWebView.setSelected(false);
                    webViewStage.close();
                }
            });
            webViewStage.initOwner(productTitleLabel.getParent().getScene().getWindow());
        }
    }
    

    在本例中,所有这些逻辑都在您的主控制器类中。当按下Button toggleWebView; 按钮时,它会调用handleToggleWebView() 方法(在FXML 中设置为onAction)。如果新窗口尚未构建,则会依次加载新窗口,然后显示或隐藏它。新窗口有它自己的 FXML 文件和它自己的控制器,然后用于处理按钮单击事件等......仅适用于该窗口。

    【讨论】:

    • 所以你希望我首先加载它,然后如果单击按钮隐藏或显示 GUI? @SnakeDoc
    • @Sh0ck 如果这适用于您的应用程序,您可以使用上面的大量代码并稍微调整以适应您的需求。您不一定需要在应用程序启动时加载它,但如果您愿意,可以。上面的代码是附加页面的一种“惰性”加载器..即。在第一次单击按钮之前,它不会在内存中创建页面/加载它。但是在它被点击一次后,它会在内存中保持活动状态,以防用户再次点击该按钮(节省重新加载页面的时间等)。
    • 哦,是的,不,Settings.class 几乎是应用程序正在初始化的类,我为实际的控制器使用单独的类,例如:HospitalLauncher = The initializer / Application, HospitalScene = 控制器
    • 啊,我明白了。在这种情况下,看一下这个更简单的示例:github.com/SnakeDoc/superD/blob/master/src/com/vanomaly/superd/… 您会注意到main() 方法调用静态launch() 方法,该方法启动JavaFX UI 线程和平台,然后自动调用start() 方法。在 start() 方法中,您将执行 FXML 加载并最终在您的舞台上调用 show() 以显示您的 UI。在您的控制器中,您只需使用胶合逻辑来处理按钮点击和其他内容。
    • 刚刚试过。不工作。仍然由以下原因引起:java.lang.IllegalStateException:应用程序启动不能被多次调用。我所做的是;我在主控制器 initializer 中调用 Settings 实例的 launch(),而不是控制器本身。然后,我在 controler 中创建了一个字段,即 Stage 实例,并将 Stage 作为值分配给该字段。然后我检查它是否为空,如果不是,它将执行 show(),如果是,它将再次调用 Settings.launch()。还是没搞定,问题大了,我快崩溃了哈哈
    猜你喜欢
    • 2012-10-05
    • 1970-01-01
    • 2020-03-16
    • 1970-01-01
    • 2018-01-08
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多