2016-02-17 2 views
0

У меня есть ImageView внутри AnchorPane, построенный с использованием FXML.Привязка изображения к размеру AnchorPane всегда дает размер 0

<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, то же самое для высоты.


EDIT

Код контроллер выглядит следующим образом:

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()); 
    } 
} 

Loaded оттуда:

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

Это трудно поверить, что возвращает значение 0, если вы явно установите его в 800. Можете ли вы показать код контроллера? –

+0

Это то же самое, мой плохой. Я изменю это. – SteeveDroz

+0

Что такое 'widthProperty()' в контроллере? И, я думаю, где и когда вы пытаетесь получить значение 'fitWdith'? –

ответ

1

У вас есть два экземпляра LifeMandelbrot: один вы создаете с помощью вызывая конструктор и явно задавая динамический корень FXML; другой создан для вас FXMLLoader и используется в качестве контроллера. Тот, который вы создаете, используется на графике сцены (scene = new Scene(root)). Тот, который создается как контроллер, никогда не помещается в граф сцены. Следовательно, он никогда не претерпевает макета и всегда имеет ширину и высоту ноль.

Конечно, методы-обработчики и initialize() методы вызываются на «экземпляр контроллера», а не «корневой инстанции», так что вы свяжете 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); 

, а затем вам нужно удалить атрибут fx:controller из корневого элемента FXML. Таким образом, контроллер и корневой узел являются одним и тем же экземпляром.

Поскольку ваш 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()); 
+0

Большое спасибо! Я все еще новичок в JavaFX и особенно FXML. В конце концов я все пойму. – SteeveDroz

+0

Вторая версия возвращает столько ошибок, что я буду придерживаться первой. – SteeveDroz

+0

Я оставил 'type =" ... "' в корневом элементе FXML, что, очевидно, не имеет смысла, когда у вас нет динамического корня, так что, вероятно, все это было неправильно. (Если у вас нет другого кода в контроллере, если он является подклассом «AnchorPane».) Возможно, вас заинтересует https://github.com/james-d/ZoomingMandelbrot;) –

Смежные вопросы