如何在 JavaFX 的控制器文件中调用舞台上的函数

Posted

技术标签:

【中文标题】如何在 JavaFX 的控制器文件中调用舞台上的函数【英文标题】:How to call functions on the stage in JavaFX's controller file 【发布时间】:2013-05-14 05:31:06 【问题描述】:

我使用 javafx 和 fxml,所以我使用 控制器进行真正的编码。我需要在舞台上做一些操作,比如获取它的 x 轴或 y 轴位置。我试过stage.getX()stage.getY,但它们不起作用(舞台名称高亮显示错误)。如何在我的控制器中使用这些功能?我尝试在我的主文件中这样做:

 public int locationX = stage.getX();

public double locationX = stage.getX();

但它不起作用,反而使整个程序出现大错误。 那么如何在我的控制器文件中执行这些功能呢?我是否需要以其他方式导入某些内容或执行上述操作?

error: cannot find symbol
    locationX = stage.getX();
symbol:   variable stage
location: class FXMLController

我知道缺少“舞台”。但是如何在我的控制器中获得“舞台”?

【问题讨论】:

【参考方案1】:

fxml 文件中的 root 窗格:

@FXML
Parent root

您可以通过以下方式获得舞台:

Stage stage = (Stage) root.getScene().getWindow()

你有你的舞台参考,你可以为所欲为。

【讨论】:

每当我尝试这个时,都会出现以下错误:docs.google.com/document/d/… 可能是另一个问题,打开一个新问题并发布DarknessFXMLController 的代码和您的fxml 文件。 @PratikAnand 你得到了NPE,因为在调用load() 时没有stage 附加到scene(其中load() 在内部调用initialize())。 Platform.runLater(...) 中包装getScene() 可以避免NPE 对我来说。【参考方案2】:

示例解决方案

您可以使用以下技术在控制器中初始化阶段:Passing Parameters JavaFX FXML。

这是一个示例程序,它创建一个实用程序窗口,当您拖动实用程序窗口时,它会跟踪屏幕的 x 和 y 坐标。实用程序窗口的内容呈现在 fxml 定义的窗格中。

StageTrackingSample.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.stage.*;

public class StageTrackingSample extends Application 

  @Override public void start(final Stage stage) throws Exception 
    final FXMLLoader loader = new FXMLLoader(
      getClass().getResource(
        "stagetracking.fxml"
      )
    );

    final Parent root = (Parent) loader.load();
    final StageTrackingController controller = loader.getController();
    controller.initData(stage);

    stage.initStyle(StageStyle.UTILITY);
    stage.setResizable(false);
    stage.setScene(new Scene(root));
    stage.show();
  

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

StageTrackingController.java

import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.stage.Stage;

public class StageTrackingController 
  @FXML private Label stageX;
  public void initialize()   
  public void initData(final Stage stage) 
    stageX.textProperty().bind(
      Bindings.format(
        "(%1$.2f, %2$.2f)", 
        stage.xProperty(), 
        stage.yProperty()
      )
    );
  

stagetracking.fxml

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

<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="30" minWidth="100" xmlns:fx="http://javafx.com/fxml" fx:controller="test.StageTrackingController">
  <Label fx:id="stageX" layoutX="0" layoutY="0"/>
</AnchorPane>

替代解决方案

如果您知道控制器的根组件已经添加到已经添加到舞台的场景(通常是触发按钮事件处理程序之类的情况)。

另一种方法类似于 tarrsalah 的答案,但在 @FXML 节点的场景属性和已更改场景的窗口属性上使用 ChangeListeners。这使您可以跟踪对场景和舞台的更改,以防窗格移动到新的场景或舞台。大多数情况下,您不需要跟踪这些更改,因为大多数窗格只是添加到单个场景中,并停留在一个阶段。

其他问题和评论的答案

我能得到一个更简单的答案吗?

tarrsalah 已经提供了一个更简单的答案。

在这种情况下,简单答案的唯一问题是它可能无法提供足够的上下文来复制答案的解决方案并使其适应您的工作。

我尽可能简单地回答了当前的问题,但不幸的是,即使是最基本的 JavaFX FXML 应用程序也需要相当多的代码和标记才能工作。

我只是一个java初学者

当您刚开始开发初始 Java 和 JavaFX 应用程序时,不要使用 FXML。相反,只需在您的 JavaFX 代码中坚持使用标准的 Java API,还有更多的 tutorials 以及优秀的 Ensemble Sample 可供参考。

确保在开始 JavaFX 之前,您已完成所有 Java Tutorial Trails Covering the Basics。开始使用 JavaFX 只需要 Java 的基础知识,您不需要分支到学习 Java 企业版并且可以忘记 Swing。

一旦您编写了一些基本的 JavaFX 应用程序、根据 Java API 对一些布局进行手动编码并对核心技术达到一定程度的熟悉程度,就可以考虑将 SceneBuilder 和 FXML 用于大型应用程序。那时您可能会发现学习 FXML 非常简单。 FXML 属性和元素只是 Java API 的反映。

请解释您的代码中不寻常的部分

我真的不能这样做,因为我不知道你有什么不寻常的地方。

如果您通过自己的知识或研究无法理解代码的某些特定部分,请create a new *** question 处理每个困难的概念。

【讨论】:

我能得到一个更简单的答案吗?我只是 java 的初学者,请解释一下你的代码中不寻常的部分。 更新了解决 Pratik 评论的答案。 谢谢。我已经练习了 1/2 个月的基本 java,稍后 1/2 的摇摆,最后来到了 fx。我曾经在简单的 javafx(non-fxml) 程序中编写代码。我几乎所有的 fxml 应用程序都在使用 scenebuilder。【参考方案3】:

嗯,最简单的答案...

在您的 Main 类中创建 Controller 类的实例(对象):



    FXMLLoader loader = new FXMLLoader(getClass().getResource("Example.fxml"));
    MyController controller = loader.getController();
    controller.setStage(this.stage);

在您的 Controller 类中,您应该放置一个“提取”方法(setter):



    private Stage primaryStage;

    public void setStage(Stage stage) 
         this.primaryStage = stage;
    

然后你可以添加一个全屏按钮;)



    @FXML
    private Button btnFullScreen = new Button();

    public void setFullscreen(ActionEvent event)       
         if(primaryStage.isFullScreen())
              primaryStage.setFullScreen(false);
          else 
              primaryStage.setFullScreen(true);
         
    

【讨论】:

你可以减少你的全屏设置代码:primaryStage.setFullScreen(!primaryStage.isFullScreen()) 另一种使用阶段的方法是使用 StageHelper.getStages().get(index)【参考方案4】:

这个帖子很旧,但我偶然发现了一些与它相关的东西。我认为是一个不应该起作用的编码错误,但它确实起作用了。在控制器类中,只需声明如下成员变量:

@FXML private Stage 舞台;

让我可以访问控制器中的舞台,就像我可以访问 fxml 文档中的小部件一样。我还没有找到任何文档证明是这种情况,但我承认我对 JavaFX 不熟悉(虽然是 Swing 的老手)。但它似乎工作。不过,指望它可能很危险?

【讨论】:

【参考方案5】:

使用 *.FXML 文件和控制器,不使用 Main 或 Events,使用这个:

@FXML private Stage stage;
stage = (Stage) elemen.getScene().getWindow();

元素,可以是 FXML 中的任何控件或元素,在我的例子中是 AnchorPane:

@FXML  private AnchorPane element;

【讨论】:

【参考方案6】:

最好的方法是创建一个新的控制器并通过构造函数传递stage(不要在FXML文件上使用fx:controller),否则当initialize()被调用时stage将是null (此时,当load() 调用initialize() 时,没有stage 附加到scene,因此scenestagenull

public class AppEntryPoint extends Application

    private FXMLLoader loader;

    @Override
    public void init() throws Exception
    
        loader = new FXMLLoader(getClass().getResource("path-to-fxml-file"));
    

    @Override
    public void start(Stage initStage) throws Exception
    
        MyController controller = new MyController(initStage);
        loader.setController(controller);
        Scene scene = loader.load();
        initStage.setScene(scene);
        initStage.show();
    

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

public class MyController

    private Stage stage;

    @FXML private URL location;
    @FXML private ResourceBundle resources;

    public MyController(Stage stage)
    
        this.stage = stage;
    

    @FXML
    private void initialize()
    
        // You have access to the stage right here
    

【讨论】:

以上是关于如何在 JavaFX 的控制器文件中调用舞台上的函数的主要内容,如果未能解决你的问题,请参考以下文章

如何在javafx中制作透明的场景和舞台?

JavaFX:整个框架的菜单栏宽度

JavaFX 8:舞台插图(窗户装饰厚度)?

父级舞台上的中心舞台

JavaFX:如何在初始化期间从控制器获取阶段?

在 JavaFX 的舞台上设置图标