JavaFX Verwendung einer ResizableCanvas-Klasse in fxml-Datei

732E772E

Mitglied
Ich möchte, dass das, was ich auf einer Canvas zeichne, sich entsprechend verändert, wenn ich das GUI-Fenster - und damit auch die Canvas - in seiner Größe verändere (z. B.: wenn ich etwas in der Mitte der Canvas zeichne, dann soll es auch in der Mitte bleiben, wenn ich das GUI-Fenster vergrößere/verkleinere). Dafür habe ich ein Beispielprogramm gefunden, dass die GUI-Erstellung in einer einzigen java-Datei erledigt. Das ist der Quellcode:

Java:
package javafxapplication5;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class Main extends Application {
   
  class ResizableCanvas extends Canvas {
  public ResizableCanvas() {
  // Redraw canvas when size changes.
  widthProperty().addListener(evt -> draw());
  heightProperty().addListener(evt -> draw());
  }
  private void draw() {
  double width = getWidth();
  double height = getHeight();
  GraphicsContext gc = getGraphicsContext2D();
  gc.clearRect(0, 0, width, height);
  gc.setStroke(Color.RED);
  gc.strokeLine(0, 0, width, height);
  gc.strokeLine(0, height, width, 0);
  }
  @Override
  public boolean isResizable() {
  return true;
  }
  @Override
  public double prefWidth(double height) {
  return getWidth();
  }
  @Override
  public double prefHeight(double width) {
  return getHeight();
  }
  }

  @Override
  public void start(Stage stage) throws Exception {
  ResizableCanvas canvas = new ResizableCanvas();
  StackPane stackPane = new StackPane();
  stackPane.getChildren().add(canvas);
  // Bind canvas size to stack pane size.
  canvas.widthProperty().bind(
  stackPane.widthProperty());
  canvas.heightProperty().bind(
  stackPane.heightProperty());
  stage.setScene(new Scene(stackPane));
  stage.setTitle("Tip 1: Resizable Canvas");
  stage.show();
  }

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

Nun möchte ich die Funktionsweise der ResizableCanvas-Klasse für ein komplexeres GUI übernehmen und mein GUI mit dem NetBeans-Scene Builder erstellen. Ich muss also noch eine fxml-Datei und eine Controller-Klasse ertellen. Die ResizableCanvas-Klasse habe ich aus Main-Klasse entfernt und in eine extra Klasse, die ResizableCanvas-Klasse, gepackt. Meine fxml-Datei für ein sehr simples GUI sieht so aus:

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

<?import javafx.scene.canvas.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafxapplication5.ResizableCanvas?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
  <children>
    <ResizableCanvas height="400.0" width="600.0" />
  </children>
</AnchorPane>

So, nun zu meiner eigentlichen Frage: Das Programm als Ganzes ist noch nicht ausführbar, da ich Main.start noch modifizieren muss, aber bevor ich dazu übergehe, zeigt mir NetBeans in der fxml-Datei an, wenn ich mit dem Mauszeiger über die Zeile "<ResizableCanvas height="400.0" width="600.0" />" fahre, dass...

Code:
Instances of javafxapplication5.ResizableCanvas cannot be created by FXML loader.

Kann mir von euch jemand sagen, wie ich meine ResizableCanvas-Klasse in fxml nutzbar machen kann? Müsste ich evtl. etwas an meine custom Canvas-Klasse ändern? Vielen Dank im Voraus für eure Hilfe!
 
Hi, dzim! Danke erstmal für deine Antwort. Die von dir genannte Internetadresse ist diejenige, von der ich mein obiges Beispiel mit der inneren ResizableCanvas-Klasse herhabe. Ich habe sie aus der Main-Klasse herausgenommen und in eine eigenständige Klasse extrahiert. Die Main-Klasse JavaFXApplication5 ist noch nicht lauffähig; da war ich noch am Rumprobieren, wollte aber erstmal das Problem mit der Verwendung der ResizableCanvas-Klasse in der fxml-Datei lösen. Okay, hier also der Quellcode:

JavaFXApplication5.java
Java:
package javafxapplication5;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import static javafx.application.Application.launch;

public class JavaFXApplication5 extends Application {
   
  @Override
  public void start(Stage stage) throws Exception {
  //ResizableCanvas canvas = new ResizableCanvas();
  //StackPane stackPane = new StackPane();
  //stackPane.getChildren().add(canvas);
  // Bind canvas size to stack pane size.
  canvas.widthProperty().bind(stackPane.widthProperty());
  canvas.heightProperty().bind(stackPane.heightProperty());
  stage.setScene(new Scene(stackPane));
  stage.setTitle("Tip 1: Resizable Canvas");
  stage.show();
  }
  public static void main(String[] args) {
  launch(args);
  }
}

ResizableCanvas.java
Java:
package javafxapplication5;

import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;

class ResizableCanvas extends Canvas {
  public ResizableCanvas() {
  // Redraw canvas when size changes.
  widthProperty().addListener(evt -> draw());
  heightProperty().addListener(evt -> draw());
  }
  private void draw() {
  double width = getWidth();
  double height = getHeight();
  GraphicsContext gc = getGraphicsContext2D();
  gc.clearRect(0, 0, width, height);
  gc.setStroke(Color.RED);
  gc.strokeLine(0, 0, width, height);
  gc.strokeLine(0, height, width, 0);
  }
  @Override
  public boolean isResizable() {
  return true;
  }
  @Override
  public double prefWidth(double height) {
  return getWidth();
  }
  @Override
  public double prefHeight(double width) {
  return getHeight();
  }
}

Controller.java
Java:
package javafxapplication5;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;

public class Controller {
     @FXML private ResizableCanvas canvas;

     @FXML
     public void initialize(URL url, ResourceBundle rb) {
  //
  }
}

FXML.fxml
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.canvas.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafxapplication5.ResizableCanvas?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
  <children>
  <ResizableCanvas height="400.0" width="600.0" />
  </children>
</AnchorPane>

Bin nach wie vor sehr dankbar für jede Hilfe!
 
Ich habe es gerade mal probiert: Was geht? Dass ich es per FXML einbinden kann (ich habe es an der entsprechenden Stelle nur noch mal in ein Pane gewrappt - StackPane oder VBox...).

Aber: Wenn ich das so einbinde, dann haut es mit den Grössen des Canvas irgendwie nicht hin...
Bei mir wird das Canvas dann stets grösser, nie kleiner.

Sorry, aber zu mehr als den kleinen Test hier, habe ich leider keine Zeit.
 

Neue Themen


Zurück
Oben