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

я использую javafx вместе С FXML-файл, поэтому я использую для реального кодирования. Мне нужно сделать несколько операций на сцене, например, получить положение оси x или y. Я пробовал stage.getX() & stage.getY, но они не работают (сценическое имя high-lited как ошибка). Как использовать такие функции в контроллере? Я попытался сделать это в своем основном файле:

 public int locationX = stage.getX();

и

public double locationX = stage.getX();

но это не работает, вместо этого делает вся программа-одна большая ошибка.
Так как же мне получить, чтобы сделать такие функции в моем файле контроллера? Нужно ли мне что-то импортировать или сделать что-то подобное выше другим способом?

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


Я знаю, что "сцена" отсутствует. Но как это сделать?--6-->получить "сцену" в моем контроллере?

6 ответов


из своего root на :

@FXML
Parent root

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

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

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


Образец Решения

вы можете инициализировать этап в контроллере, используя технику из:передача параметров 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 в свойстве scene узла @FXML и свойстве window измененной сцены. Это позволяет отслеживать изменения сцены и этапа в случае перемещения панели на новую сцену или этап. Большую часть времени вам не нужно отслеживать эти изменения, хотя, поскольку большинство панелей просто добавляются в одну сцену, которая остается на одной сцене.

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

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

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

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

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

Я простой новичок в java

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

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

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

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

Я не могу, так как не знаю, что для вас непривычно.

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


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

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



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

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



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


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

этап@частная этап FXML-файл;

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


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

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

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

@FXML  private AnchorPane element;

лучший подход-создать новый контроллер и передать stage через конструктор (не используйте fx:controller в файле FXML), в противном случае stage будет null, когда initialize() вызывается (в тот момент времени, когда load() вызывает initialize(), нет stage присоединен к scene, отсюда scene ' s 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
    }
}