Barburka
Barburka

Reputation: 465

How to get a reference to the node from other class?

Is there any simple way to get a reference to control of a stage from other class? It seems to be a problem in every GUI based framework except Delphi. If only Controller or Main class were static...

Here is my code:

Controller.java:

package sample;

import javafx.fxml.*;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;

public class Controller {

    @FXML
    private Button algorithms;

    @FXML
    private Button settings;

    @FXML
    private Button run;

    @FXML
    public TextArea console; // I want access that node from class named 'Utils'

    @FXML
    void initialize() { }

    public Controller () { }

    @FXML
    private void onRun() {
        Utility.get().runBench();
    }

    @FXML
    private void onSettings() {
        console.appendText("I am opening settings...");
    }

    @FXML
    private void onAlgorithm() {
        console.appendText("I am opening list of Algorithms...");
    }
}

Utils.java:

package sample;

import sample.Algorithms.BubbleSort;

import java.util.*;


// Singleton
public class Utility {
    private static Utility ourInstance = new Utility();

    public static Utility get() {
        return ourInstance;
    }

    private Utility() {
        listOfAlgorithms.add(new BubbleSort(howManyN));
    }

    List<Algorithm> listOfAlgorithms = new LinkedList<>();
    Long howManyN = 999L;

    public void runBench() {
        for (Algorithm a: listOfAlgorithms) {
            double start = System.nanoTime();
            a.run();
            double end = System.nanoTime();
            double result = end - start;
            System.out.println(
//            console.appendText(  // Accessing like that would be ideal
                    "Algorithm: " + a.getClass().getName() + "\n" +
                    "For N = " + a.getN() + " time is: " + result
            );
        }
    }
}

I heard about FXMLoader, but it is in Main Class, so there is no difference.

Main.java:

package sample;

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


public class Main extends Application {

    final String APP_NAME = "SortAll 2";
    final String RES_PATH = "../resources/scene.fxml";

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

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource(RES_PATH));
        primaryStage.setTitle(APP_NAME);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }
}

Upvotes: 0

Views: 1012

Answers (2)

James_D
James_D

Reputation: 209553

Pass an object to the runBench() method that describes what you want to do with the result. Since you're encapsulating the result as a String, you could use a Consumer<String>:

public void runBench(Consumer<String> onAlgorithmCompletion) {
    for (Algorithm a: listOfAlgorithms) {
        double start = System.nanoTime();
        a.run();
        double end = System.nanoTime();
        double result = end - start;
        onAlgorithmCompletion.accept(
                "Algorithm: " + a.getClass().getName() + "\n" +
                "For N = " + a.getN() + " time is: " + result
        );
    }
}

Then from your controller you can do

@FXML
private void onRun() {
    Utility.get().runBench(console::appendText);
}

This is unrelated to the question you posted, but you almost certainly need to execute your runBench() method in a background thread, since it apparently takes some time to execute. If you do that, you need to ensure that the console is only accessed on the FX Application Thread. The above solution is easy to modify to do this (your runBench(...) method doesn't need to change at all):

private Executor exec = Executors.newCachedThreadPool();

// ...

@FXML
private void onRun() {
    exec.execute(() -> Utility.get().runBench(
        result -> Platform.runLater(console.appendText(result))));
}

Upvotes: 2

Peteef
Peteef

Reputation: 405

Umm, can't you just pass console as a runBench() parameter?

Utility.java:

 public void runBench(TextArea console) {
    for (Algorithm a: listOfAlgorithms) {
        double start = System.nanoTime();
        a.run();
        double end = System.nanoTime();
        double result = end - start;
        System.out.println(
        console.appendText(
                "Algorithm: " + a.getClass().getName() + "\n" +
                "For N = " + a.getN() + " time is: " + result
        );
    }
}

and

Controller.java:

@FXML
private void onRun() {
    Utility.get().runBench(console);
}

Upvotes: 2

Related Questions