Как вызвать функции на этапе в файле контроллера JavaFX

Я использую 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

С панели root в файле fxml:

@FXML
Parent root

Вы можете получить сцену из нее:

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

У вас есть ссылка на ваш этап, вы можете делать то, что хотите.

Ответ 2

Пример решения

Вы можете инициализировать сцену в контроллере, используя технику: Передача параметров JavaFX FXML.

Вот пример программы, которая создает окно утилиты, которое отслеживает координаты x и y экрана при перетаскивании окна утилиты. Содержимое окна утилиты отображается в определенной области fxml.

stagecoords

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 также является хорошим способом, если вы знаете, что корневой компонент контроллера уже добавлен в сцену, которая уже добавлена ​​на сцену (что часто является случай, когда что-то вроде обработчика событий кнопки запускается).

Другой способ сделать это похож на ответ tarrsalah, но использовать ChangeListeners в свойстве сцены для @FXML node и свойства окна измененной сцены. Это позволяет отслеживать изменения сцены и сцены в случае перемещения панели на новую сцену или сцену. В большинстве случаев вам не нужно отслеживать эти изменения, так как большинство панелей просто добавляются в одну сцену, которая остается на одном этапе.

Ответы на дополнительные вопросы и комментарии

Могу ли я получить более простой ответ?

tarrsalah уже предоставил более простой ответ.

Единственная проблема с более простым ответом в этом случае заключается в том, что он может не обеспечить достаточного контекста, необходимого для репликации решения ответа и адаптации его к вашей работе.

Я сделал свой текущий ответ как можно проще, но, к сожалению, даже для самого базового приложения JavaFX FXML требуется довольно много кода и разметки для работы.

Я просто начинаю в java

Не используйте FXML, когда вы начинаете разрабатывать свои первые приложения Java и JavaFX. Вместо этого просто придерживайтесь стандартного Java API в вашем коде JavaFX, для которого есть еще много tutorials, а также отличный Образец ансамбля для ссылки.

Перед началом JavaFX убедитесь, что вы завершили все Учебные тропы Java, освещающие основы. Для начала использования JavaFX требуется только основы Java, вам не нужно вникать в изучение Java Enterprise Edition и забыть о Swing.

Рассмотрите возможность использования SceneBuilder и FXML для более крупных приложений, как только вы написали несколько базовых приложений JavaFX, с ручной кодировкой некоторых макетов в соответствии с Java API и достигли уровня комфорта с использованием основных технологий. В то время вы, скорее всего, обнаружите, что обучение FXML довольно простое. Атрибуты и элементы FXML - это просто отражение API Java.

пожалуйста, объясните другие, чем обычные биты вашего кода.

Я не могу этого сделать, так как не знаю, что для вас необычно.

Если для каждой сложной концепции есть определенные части кода, которые вы не можете понять своими собственными знаниями или исследованиями, создайте новый вопрос StackOverflow.

Ответ 3

Ну, самый простой ответ на этот вопрос...

В своем основном классе создайте экземпляр (объект) вашего класса контроллера:



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

В вашем классе Controller вы должны поместить метод "извлечения" (сеттер):



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

Ответ 4

Эта ветка устарела, но я обнаружил что-то подходящее для нее совершенно случайно. Я думал, что это ошибка кодирования, которая не должна была работать, но это было так. В классе контроллера просто объявляем следующую переменную-член:

@FXML частная стадия этапа;

предоставил мне доступ к этапу контроллера, так же как и доступ к виджету в документе fxml. Я не нашел никакой документации, что это так, но я признаю, что я нооб для JavaFX (хотя старая рука у Swing). Но, похоже, это работает. Может быть, опасно рассчитывать на это?

Ответ 5

С *.FXML файлами и контроллерами и не с Main или Events, используйте это:

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

может быть любым элементом управления или элементом в FXML, в моем случае это AnchorPane:

@FXML  private AnchorPane element;

Ответ 6

Лучший подход - создать новый контроллер и передать stage через конструктор (не использовать fx:controller в файле FXML), в противном случае stage будет null при вызове initialize() (В тот момент времени, когда load() вызывает initialize(), к scene присоединяется stage, поэтому scene stage - null).

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
    }
}