Обработка Java 3 PAplet в сцене JavaFX как FXNode - PullRequest
0 голосов
/ 08 октября 2018

Я пытаюсь создать программу для визуального анализа фрактальных множеств.Я выбираю Processing 3 в качестве библиотеки чертежей и JavaFX для пользовательского интерфейса.Есть несколько скриншотов текущего состояния:

Мой GUI:

JavaFX Scene Builder

естьКод запуска:

import Graphics.Canvas2D;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import processing.core.PGraphics;

import java.io.IOException;

public class Launcher extends Application {
    private static Stage primaryStage;

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

    @Override
    public void start(Stage primaryStage) {
        Parent root = loadFXML("MainUI.fxml");
        Scene scene = new Scene(root, 500, 400);
        primaryStage.setTitle("Fractal Analyzer");
        primaryStage.setScene(scene);
        primaryStage.show();
        primaryStage.setMaximized(true);

        Launcher.primaryStage = primaryStage;
    }

    @Override
    public void init() {

    }

    @Override
    public void stop() {
        System.exit(0);
    }

    public static Stage getPrimaryStage() {
        return primaryStage;
    }

    public  void setCanvas(Canvas2D canvas){

    }



    private Parent loadFXML(String path) {
        try {
            return FXMLLoader.load(getClass().getResource(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.exit(1);
        return null;
    }
}

Тестирование фрактала PAplet:

Processing PAplet window

Тамкод этого PAplet:

package Fractal;

import processing.core.PApplet;

public class SirpenskiTriangle extends PApplet {

    public static void main(String[] args) {
        PApplet.main("Fractal.SirpenskiTriangle");
    }

    public void settings() {
        size(640, 640);
        smooth();
        if (frame != null) {
            frame.setResizable(true);
        }
    }

    public void draw() {
        drawTriangle(new Position(300, 20), new Position(620, 620), new Position(20, 620), 0);
        noLoop();
        scale(10f);
    }

    public void setup(){}

    public void drawTriangle(Position top, Position right, Position left, int depth) {
        if (depth > 10) return;

        line(top.x, top.y, right.x, right.y);
        line(right.x, right.y, left.x, left.y);
        line(left.x, left.y, top.x, top.y);

        drawTriangle(top, top.middleWith(right), top.middleWith(left), depth + 1);
        drawTriangle(top.middleWith(left), left.middleWith(right), left, depth + 1);
        drawTriangle(top.middleWith(right), right, left.middleWith(right), depth + 1);
    }

    class Position {
        final float x;
        final float y;

        Position(float x, float y) {
            this.x = x;
            this.y = y;
        }

        Position middleWith(Position other) {
            return new Position((x + other.x) / 2, (y + other.y) / 2);
        }
    }
}

Есть ли способ поместить обработку PAplet в сцену JavaFX, например, canvas или что-то подобное?

Надеюсь, это может работать следующим образом,но этот код недействителен: example

Ответы [ 4 ]

0 голосов
/ 17 декабря 2018

Хорошо, так как в прошлый раз я изменил некоторые элементы.Родитель холста теперь является просто панелью вместо AnchorPane.

FXML вам мало чем поможет ... Это просто BorderPane с другой панелью, но все в порядке ...

 <center>
  <VBox prefHeight="200.0" prefWidth="100.0" BorderPane.alignment="CENTER">
     <children>

        <Pane maxHeight="1.7976931348623157E308" VBox.vgrow="ALWAYS" />

     </children>
  </VBox>

Итак, я беру элемент Canvas, создаю Processing и просто добавляю его в панель.

0 голосов
/ 11 ноября 2018

Чтобы все заработало, вам нужно запустить эскиз обработки, а не приложение JavaFX.

Просто выполните

PApplet.main(Launcher.class.getName());

Также большое спасибо за вашу помощь!Я понятия не имел, как мне использовать JavaFX, который поставляется с Processing!

0 голосов
/ 21 ноября 2018

Хорошо, это мой код, который работает!Я скопировал все и изменил имена.Я не проверял этот модифицированный код, поэтому не копируйте и не вставляйте все !!!Хотя необработанный принцип должен определенно работать.

Если у вас все еще есть проблемы или вопросы, просто комментируйте.

Main

public class Main {

    public static void main(String[] args) {

    // Your code starts here, and runs Processing. 
    // This is also, how you normally start Processing sketches.
    PApplet.main(Sketch.class.getName());
    }
}

Эскиз

public class Sketch extends PApplet{

    @Override
    public void settings() {
        size(200, 200, FX2D); // Size doesn't really matter
    }


    @Override
    public void setup() {

    }

    @Override
    public void draw() {

    }


// Processing uses this function to determine, 
// how to display everything, how to open the canvas...
// We override the code, that would normally open a window with the normal Processing stuff,
// to open start new JavaFX application in a new Thread.


// micycle's code
    @Override
    protected PSurface initSurface() {
        g = createPrimaryGraphics();
        PSurface genericSurface = g.createSurface();
        PSurfaceFX fxSurface = (PSurfaceFX) genericSurface;

        fxSurface.sketch = this;

        // Because the JavaFX App is being launched by reflection,
        // we can't pass variables to it via constructor, so
        // we have to access it in static context.

        // Here, we give JavaFX the surface.
        ExampleApp.surface = fxSurface;

        // New thread started, so JavaFX and Processing don't interrupt each other.
        new Thread(new Runnable() {
            public void run() {

                // JavaFX way of launching a new Application
                Application.launch(ExampleApp.class);
            }
        }).start();

    while (fxSurface.stage == null) {
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {

        }
    }

        this.surface = fxSurface;
        return fxSurface;
    }
}

ExampleApp

public class ExampleApp extends Application {

    public Canvas canvas; // The Canvas you will be drawing to 
    public static PSurfaceFX surface; // The Processing surface



    // JavaFX started, this method is being run to set everything up.
    @Override
    public void start(Stage primaryStage) {

        // This sets up the canvas, and the drawing region.
        canvas = (Canvas) surface.getNative();
        surface.fx.context = canvas.getGraphicsContext2D();
        surface.stage = primaryStage;


        // I'm just loading my FXML file. You can do all JavaFX stuff via code, if you want
        try {

            // !!My root Container is a BorderPane!!
            BorderPane root = FXMLLoader.load(getClass().getClassLoader().getResource("application.fxml"));
        } catch(IOException e) {
            e.printStackTrace();
        }

        // Getting the Anchor pane, that is in the center of my BorderPane
        AnchorPane pane = (AnchorPane) root.getCenter();

        // The Anchor pane is being used, so the canvas can fill the parent (Center)
        // Canvases don't have a property to fill it's parent, like most Containers do (Because it isn't a container)
        canvas.widthProperty().bind(pane.widthProperty());
        canvas.heightProperty().bind(pane.heightProperty());

        // Adding the canvas to your App
        root.getChildren().add(canvas);

        // Launching the Stage
        primaryStage.setTitle("Example App");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

}
0 голосов
/ 12 октября 2018

Вам нужно будет загрузить слегка измененный core.jar , чтобы это работало, где я изменил видимость нескольких членов классов PSurfaceFX и PGraphicsFX2D с Protected до Public.Изменения позволяют нам запускать JavaFX из нашего собственного класса ... extends Application, сохраняя при этом доступ к элементам, которые Обработка должна установить во время запуска для работы.

Обработка 3 завершается сбоем в режиме FX2D, когда используется JDKвыше Java 8, поэтому я также сделал рабочую версию для 8+, так как для работы файлов FXML обычно требуется как минимум Java 9.

Это файл FXML, с которым я работаю в этом примере:

enter image description here

С измененным core.jar , добавленным к пути к классам вашего проекта, переопределите initSurface() в вашем классе PApplet с помощью следующего фрагмента.С помощью этого кода мы пропускаем вызов PApplet к initFrame() - здесь обработка создает свой собственный этап JavaFX, который мы не хотим делать.

@Override
protected PSurface initSurface() {
    g = createPrimaryGraphics();
    PSurface genericSurface = g.createSurface();
    PSurfaceFX fxSurface = (PSurfaceFX) genericSurface;

    fxSurface.sketch = this;

    Launcher.surface = fxSurface;

    new Thread(new Runnable() {
        public void run() {
            Application.launch(Launcher.class);
        }
    }).start();

    while (fxSurface.stage == null) {
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
        }
    }

    this.surface = fxSurface;
    return fxSurface;
}

Установите режим рендеринга PApplet на FX2D, напримерИтак:

@Override
public void settings() {
    size(0, 0, FX2D);
}

Поместите следующее или подобное в ваш класс Launcher.В этом примере я вручную нашел узел, в который я хочу добавить объект холста.Есть лучшие, более программные способы сделать это (например, .lookup () с использованием fx: id нужного узла).Я также связал размеры холста с размерами его родителя, поэтому, когда делитель, разделяющий панели Master и View , перетаскивается, холст соответственно изменяет размеры.

public class Launcher extends Application {

    public static PSurfaceFX surface;

    @Override
    public void start(Stage primaryStage) throws Exception {

        Canvas canvas = (Canvas) surface.getNative(); // boilerplate
        GraphicsContext graphicsContext = canvas.getGraphicsContext2D(); // boilerplate
        surface.fx.context = graphicsContext; // boilerplate

        primaryStage.setTitle("FXML/Processing");

        VBox root = FXMLLoader.load(new File("c:/Users/Mike/desktop/test.fxml").toURI().toURL());
        SplitPane pane = (SplitPane) root.getChildren().get(1); // Manually get the item I want to add canvas to
        AnchorPane pane2 = (AnchorPane) pane.getItems().get(0); // Manually get the item I want to add canvas to
        pane2.getChildren().add(canvas); // Manually get the item I want to add canvas to

        canvas.widthProperty().bind(pane2.widthProperty());
        canvas.heightProperty().bind(pane2.heightProperty());

        Scene scene = new Scene(root, 800, 800);
        primaryStage.setScene(scene);
        primaryStage.show();

        surface.stage = primaryStage; // boilerplate
    }
}

Это результат:

enter image description here

...