我在ImageView
内有AnchorPane
,使用FXML构建。
<fx:root prefHeight="600.0" prefWidth="800.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.LifeMandelbrot">
<children>
<ImageView fx:id="view" fitHeight="600.0" fitWidth="800.0" onMouseClicked="#moveCenter" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<HBox alignment="CENTER" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children>
<Button fx:id="zoomOut" mnemonicParsing="false" onAction="#zoomOut" text="Zoom-" />
<Button fx:id="zoomIn" mnemonicParsing="false" onAction="#zoomIn" text="Zoom+" />
<Button fx:id="defaultView" mnemonicParsing="false" onAction="#defaultView" text="Vue par défaut" />
</children>
</HBox>
</children>
</fx:root>
如您所见,ImageView
符合AnchorPane
使用锚点。
当我点击其中一个按钮时,ImageView
会重新粉刷。
问题:
view.getFitWidth()
始终显示0
,高度相同。
修改
控制器代码如下所示:
package application;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
public class LifeMandelbrot extends AnchorPane implements Initializable {
private static final double DEFAULT_ZOOM = 200.0;
private static final Complex DEFAULT_CENTER = new Complex(0, 0);
private static final double ZOOM_RATIO = 1.2;
@FXML
private Button zoomOut;
@FXML
private Button zoomIn;
@FXML
private Button defaultView;
@FXML
private Button julia;
@FXML
ImageView view;
private double zoom;
private Complex center;
private List<Color> colors;
private int colorStep;
public LifeMandelbrot() {
zoom = DEFAULT_ZOOM;
center = DEFAULT_CENTER;
colors = new ArrayList<Color>();
colors.add(Color.RED);
colors.add(Color.GREEN);
colors.add(Color.BLUE);
colorStep = 20;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
repaint();
view.fitWidthProperty().bind(widthProperty());
view.fitHeightProperty().bind(heightProperty());
}
@FXML
void defaultView(ActionEvent event) {
zoom = DEFAULT_ZOOM;
center = DEFAULT_CENTER;
repaint();
}
@FXML
void julia(ActionEvent event) {
}
@FXML
void zoomIn(ActionEvent event) {
zoom *= ZOOM_RATIO;
repaint();
}
@FXML
void zoomOut(ActionEvent event) {
zoom /= ZOOM_RATIO;
repaint();
}
@FXML
void moveCenter(MouseEvent event) {
center = fractalFromView(event.getX(), event.getY());
repaint();
}
private void repaint() {
WritableImage image = new WritableImage((int) view.getFitWidth(), (int) view.getFitHeight());
PixelWriter pw = image.getPixelWriter();
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
Complex c = fractalFromView(x, y);
int iterations = Fractal.mandelbrot(c);
if (iterations == -1) {
pw.setColor(x, y, new Color(0, 0, 0, 1));
} else {
int colorIndex = iterations / colorStep;
int colorAdd = iterations % colorStep;
Color color1 = colors.get(colorIndex % colors.size());
Color color2 = colors.get((colorIndex + 1) % colors.size());
Color color = color1.interpolate(color2, (double) colorAdd / colorStep);
pw.setColor(x, y, color);
}
}
}
view.setImage(image);
}
private Complex fractalFromView(double x, double y) {
return new Complex((x - view.getFitWidth() / 2) / zoom + center.getReal(),
(y - view.getFitHeight() / 2) / zoom + center.getImaginary());
}
}
从那里加载:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("../lifeMandelbrot.fxml"));
loader.setRoot(new LifeMandelbrot());
AnchorPane root = loader.load();
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("LIFE Is a Fractal Explorer");
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
答案 0 :(得分:1)
您有两个LifeMandelbrot
实例:您通过调用构造函数创建的实例,并明确设置为FXML的动态根;另一个是由FXMLLoader
为您创建的,用作控制器。您创建的在场景图中使用的那个(scene = new Scene(root)
)。创建为控制器的那个永远不会放在场景图中。因此它永远不会经历布局,并且宽度和高度始终为零。
当然,处理程序方法和initialize()
方法在&#34;控制器实例&#34;上调用,而不是&#34;根实例&#34;,因此你绑定fitWidth
并且fitHeight
为零。
你需要
FXMLLoader loader = new FXMLLoader(getClass().getResource("../lifeMandelbrot.fxml"));
LifeMandelbrot root = new LifeMandelbrot();
loader.setRoot(root);
loader.setController(root);
loader.load();
Scene scene = new Scene(root);
然后您需要从FXML的根元素中删除fx:controller
属性。这样控制器和根节点就是同一个实例。
由于您的FXML已经通过使用子节点上的锚窗格设置明确地将其自身绑定到AnchorPane
,因此为此使用标准模式可能更清楚。即
<AnchorPane fx:id="root" fx:controller="application.LifeMandelbrot" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ImageView fx:id="view" onMouseClicked="#moveCenter" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<HBox alignment="CENTER" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<children>
<Button fx:id="zoomOut" mnemonicParsing="false" onAction="#zoomOut" text="Zoom-" />
<Button fx:id="zoomIn" mnemonicParsing="false" onAction="#zoomIn" text="Zoom+" />
<Button fx:id="defaultView" mnemonicParsing="false" onAction="#defaultView" text="Vue par défaut" />
</children>
</HBox>
</children>
</AnchorPane>
在控制器中:
public class LifeMandelbrot implements Initializable {
@FXML
private AnchorPane root ;
// existing code...
@Override
public void initialize(URL location, ResourceBundle resources) {
repaint();
view.fitWidthProperty().bind(root.widthProperty());
view.fitHeightProperty().bind(root.heightProperty());
}
// existing code...
}
然后只是
FXMLLoader loader = new FXMLLoader(getClass().getResource("../lifeMandelbrot.fxml"));
Scene scene = new Scene(loader.load());