Reputation: 7255
Below is the Main.class
and the Controller.class
, i tried to make it as simpler as possible.
The program outputs the below window:
The black is a StackPane
named visualizerStackPane
and inside it is a Canvas
named visualizerCanvas
. What i want to do is the Canvas
inside the StackPane
to be resized accordingly to the StackPane
size substract 4 . But everything fails when you resize the window.
What you have to try...
1)Maximize the window and then normalize it back.
2)Increase the size of the window and slowly decrease it back.
Why this is happening?I have this problem 3 months now and i can't find a solution...
I have also looked JavaFX - Resize Canvas when screen is resized but the problem here seems to be different...
Main.java:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
//Scene
Scene scene = new Scene(new Controller(), 400, 400);
primaryStage.setScene(scene);
//Show
primaryStage.show();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java:
I have modified the Controller class to paint the Canvas and removed the bindings from Initialize
method , it doesn't work it produces the below:
If i don't set the width and height of the Canvas manually it doesn't even get painted...I don't know why .
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
public class Controller extends StackPane {
@FXML
private GridPane container;
@FXML
private GridPane topGridPane;
@FXML
private StackPane visualizerStackPane;
@FXML
private Canvas visualizerCanvas;
@FXML
private VBox topRightVBox;
@FXML
private StackPane mediaFileStackPane;
@FXML
private GridPane bottomGridPane;
// ------------------------------
GraphicsContext gc;
int canvasWidth = 0;
int canvasHeight = 0;
/**
* Constructor
*/
public Controller() {
// ------------------------FXMLLoader ---------------------------------
FXMLLoader loader = new FXMLLoader(getClass().getResource("Controller.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Controller FXML can't be loaded!", ex);
}
}
/**
* Called as soon as FXML FILE has been loaded
*/
@FXML
private void initialize() {
gc = visualizerCanvas.getGraphicsContext2D();
// // VisualizerStackPane inside which visualizerCanvas is
// visualizerCanvas.widthProperty().bind(visualizerStackPane.widthProperty().subtract(4));
// visualizerCanvas.heightProperty().bind(visualizerStackPane.heightProperty().subtract(4));
//
// Add width and height change listeners
visualizerStackPane.widthProperty().addListener((observable, oldValue,
newValue) -> resizeVisualizerCanvas(newValue.doubleValue(), visualizerStackPane.getHeight()));
visualizerStackPane.heightProperty().addListener((observable, oldValue,
newValue) -> resizeVisualizerCanvas(visualizerStackPane.getWidth(), newValue.doubleValue())
);
repaintCanvas();
}
/**
* Repaints the Canvas
*/
public void repaintCanvas() {
//Clear the previous rectangle
gc.clearRect(0, 0, canvasWidth, canvasHeight);
// Draw the
gc.setFill(Color.RED);
gc.fillRect(0, 0, canvasWidth, canvasHeight);
// Draw the Line
gc.setLineWidth(3);
gc.setStroke(Color.WHITE);
gc.strokeLine(0, canvasHeight, canvasWidth, 0);
}
/**
* Resizes the visualizerCanvas to the given values.
*
* @param width
* the width
* @param height
* the height
*/
public void resizeVisualizerCanvas(double width, double height) {
if (width > 0 && height > 0) {
this.canvasWidth = (int) width;
this.canvasHeight = (int) height;
// Print something
System.out.println("Canvas Width is:" + width+" , Canvas Height is:"+height +" Canvas is Resizable: "+visualizerCanvas.isResizable());
// Repaint the Canvas
repaintCanvas();
// ---------------------------Below i have tried several things to
// solve the problem....
// Set the width and height of Canvas
visualizerCanvas.setWidth(width);
visualizerCanvas.setHeight(height);
// Careful with contentBias here
prefWidth(-1);
prefHeight(-1);
// autosize()
// System.out.println("Content Bias is:"+this.getContentBias())
}
}
}
Controller.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<fx:root prefHeight="212.0" prefWidth="456.0" type="StackPane" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding>
<children>
<GridPane fx:id="container">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="50.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="50.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="40.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="60.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<GridPane fx:id="topGridPane" gridLinesVisible="true" GridPane.columnSpan="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="50.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="50.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<StackPane fx:id="visualizerStackPane" style="-fx-border-color: white; -fx-border-width: 1.5; -fx-background-color: rgb(0,0,0,0.95);">
<children>
<Canvas fx:id="visualizerCanvas" />
</children>
</StackPane>
<VBox fx:id="topRightVBox" GridPane.columnIndex="1">
<children>
<StackPane prefHeight="150.0" prefWidth="200.0">
<children>
<Region style="-fx-background-color: rgb(255,255,255,0.7);" />
<Label alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" style="-fx-font-weight: bold;" text="text here" />
</children>
</StackPane>
<StackPane fx:id="mediaFileStackPane" maxWidth="1.7976931348623157E308" />
</children>
</VBox>
</children>
</GridPane>
<GridPane fx:id="bottomGridPane" gridLinesVisible="true" GridPane.columnSpan="2" GridPane.rowIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="20.0" prefWidth="35.0" />
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" percentWidth="60.0" prefWidth="343.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="20.0" prefWidth="52.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<StackPane prefHeight="150.0" prefWidth="200.0" GridPane.columnIndex="2">
<children>
<Region style="-fx-background-color: rgb(255,255,255,0.7);" />
<Label alignment="CENTER" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" style="-fx-font-weight: bold;" text="text here" textAlignment="CENTER" wrapText="true" StackPane.alignment="CENTER" />
</children>
</StackPane>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="5.0" />
</children>
</GridPane>
</children>
</GridPane>
</children>
</fx:root>
Finally:
A big thanks to the person who will manage to solve this problem :).
Upvotes: 2
Views: 2767
Reputation: 7255
After research i have found the solution . Creating a custom Canvas
class and @Overriding
methods from Canvas
:
🌾Very glad from the final answer on this question: How to make canvas Resizable in javaFX?
🌾A link that gave me the idea: http://dlsc.com/2014/04/10/javafx-tip-1-resizable-canvas/
ResizableCavas.java :
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
class ResizableCanvas extends Canvas {
GraphicsContext gc = getGraphicsContext2D();
int canvasWidth = 0;
int canvasHeight = 0;
int halfCanvasHeight = 0;
/**
* Constructor
*/
public ResizableCanvas() {
// if i didn't add the draw to the @Override resize(double width, double
// height) then it must be into the below listeners
// Redraw canvas when size changes.
widthProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Entered WIDTH property");
canvasWidth = (int) widthProperty().get();
});
heightProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Entered HEIGHT property");
canvasHeight = (int) heightProperty().get();
halfCanvasHeight = canvasHeight >> 1;
});
}
/**
* Redraw the Canvas
*/
private void draw() {
System.out.println(" Real Canvas Width is:" + getWidth() + " , Real Canvas Height is:" + getHeight() + "\n");
gc.clearRect(0, 0, canvasWidth, canvasHeight);
gc.setStroke(Color.RED);
gc.strokeLine(0, 0, canvasWidth, canvasHeight);
gc.strokeLine(0, canvasHeight, canvasWidth, 0);
}
@Override
public double minHeight(double width) {
return 1;
}
@Override
public double maxHeight(double width) {
return Double.MAX_VALUE;
}
@Override
public double prefHeight(double width) {
return minHeight(width);
}
@Override
public double minWidth(double height) {
return 1;
}
@Override
public double maxWidth(double height) {
return Double.MAX_VALUE;
}
@Override
public boolean isResizable() {
return true;
}
@Override
public void resize(double width, double height) {
super.setWidth(width);
super.setHeight(height);
draw();
}
}
Controller.java:
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
public class Controller extends StackPane {
@FXML
private GridPane container;
@FXML
private GridPane topGridPane;
@FXML
private StackPane visualizerStackPane;
@FXML
private VBox topRightVBox;
@FXML
private StackPane mediaFileStackPane;
@FXML
private GridPane bottomGridPane;
// ------------------------------
ResizableCanvas visualizerCanvas = new ResizableCanvas();
/**
* Constructor
*/
public Controller() {
// ------------------------FXMLLoader ---------------------------------
FXMLLoader loader = new FXMLLoader(getClass().getResource("Controller.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Controller FXML can't be loaded!", ex);
}
}
/**
* Called as soon as FXML FILE has been loaded
*/
@FXML
private void initialize() {
visualizerStackPane.getChildren().add(visualizerCanvas);
}
}
Upvotes: 1
Reputation: 1192
Remove the binding from your initialize()
method. You are attempting to take control of layout operations yourself, which stop StackPane
doing what it is supposed to do. This will resize the Canvas
appropriately.
You state that when you print the width
and height
of the Canvas
, it returns -1. Instead of doing this, print the width
and height
of the container StackPane
. Since Canvas
is, after all, contained fully within the StackPane
, then the width
and height
will be almost identical, if not identical.
Upvotes: 1