Browse Source

let the user choose between Mandelbrot and Julia

develop
Manuel Friedli 3 years ago
parent
commit
467d0c95ba

+ 64
- 19
src/main/java/ch/fritteli/fractal/gui/MainController.java View File

@@ -12,6 +12,9 @@ import javafx.fxml.FXML;
12 12
 import javafx.scene.canvas.GraphicsContext;
13 13
 import javafx.scene.control.Button;
14 14
 import javafx.scene.control.ProgressBar;
15
+import javafx.scene.control.RadioButton;
16
+import javafx.scene.control.Toggle;
17
+import javafx.scene.control.ToggleGroup;
15 18
 import javafx.scene.image.Image;
16 19
 import javafx.scene.image.WritableImage;
17 20
 import javafx.scene.text.Text;
@@ -23,10 +26,11 @@ import java.io.File;
23 26
 import java.io.IOException;
24 27
 
25 28
 /**
26
- * The JavaFX controller class for the main window. As of this writing, this is the only controller class of the
27
- * application, aka "god controller". This is likely to change in the future.<br>This controller handles all user
28
- * interaction with the main window, such as clicking buttons or entering text into text fields. It is also responsible
29
- * for starting the computation and handling the user-request to abort a running computation.
29
+ * The JavaFX controller class for the main window. As of this writing, this is the only controller class of
30
+ * the application, aka "god controller". This is likely to change in the future.<br>This controller handles
31
+ * all user interaction with the main window, such as clicking buttons or entering text into text fields. It
32
+ * is also responsible for starting the computation and handling the user-request to abort a running
33
+ * computation.
30 34
  *
31 35
  * @author Manuel Friedli (manuel@fritteli.ch)
32 36
  */
@@ -96,6 +100,21 @@ public class MainController {
96 100
      */
97 101
     @FXML
98 102
     private FractalCanvas renderArea;
103
+    /**
104
+     * Toggle group for switching between Mandelbrot and Julia
105
+     */
106
+    @FXML
107
+    private ToggleGroup typeToggleGroup;
108
+    /**
109
+     * Radiobutton for choosing the type Mandelbrot
110
+     */
111
+    @FXML
112
+    private RadioButton typeMandelbrot;
113
+    /**
114
+     * Radiobutton for choosing the type Julia
115
+     */
116
+    @FXML
117
+    private RadioButton typeJulia;
99 118
     /**
100 119
      * The background service that does the computation and deliver the result
101 120
      */
@@ -111,8 +130,8 @@ public class MainController {
111 130
 
112 131
     /**
113 132
      * Called by the JavaFX platform after wiring the dependencies. Used to initialize the controller and its
114
-     * components. It also triggers an initial computation of the default area so that upon showing the application
115
-     * window for the first time, there's already an image showing.
133
+     * components. It also triggers an initial computation of the default area so that upon showing the
134
+     * application window for the first time, there's already an image showing.
116 135
      */
117 136
     public void initialize() {
118 137
         this.initConstraints();
@@ -132,6 +151,7 @@ public class MainController {
132 151
         this.width.set(800);
133 152
         this.height.set(600);
134 153
         this.iterations.set(100);
154
+        this.typeToggleGroup.selectToggle(this.typeMandelbrot);
135 155
     }
136 156
 
137 157
     private void initConstraints() {
@@ -141,13 +161,17 @@ public class MainController {
141 161
     }
142 162
 
143 163
     private void initValidationBindings() {
144
-        final BooleanBinding allValidBinding = this.minRe.validProperty().and(this.maxRe.validProperty()).and(this
145
-                .minIm.validProperty()).and(this.maxIm.validProperty()).and(this.width.validProperty()).and(this
146
-                .height.validProperty()).and(this.iterations.validProperty());
164
+        final BooleanBinding allValidBinding = this.minRe.validProperty()
165
+                .and(this.maxRe.validProperty())
166
+                .and(this.minIm.validProperty())
167
+                .and(this.maxIm.validProperty())
168
+                .and(this.width.validProperty())
169
+                .and(this.height.validProperty())
170
+                .and(this.iterations.validProperty());
147 171
         // FIXME strange behavior: if i set a breakpoint here and run in debug mode, it works. in normal mode,
148
-        // it doesn't. WEIRD?! somehow, this thread-workaround achieves he same result.
149
-        allValidBinding.addListener((observable, oldValue, newValue) -> MainController.this.startButton.setDisable
150
-                (!newValue));
172
+        // it doesn't. WEIRD?! somehow, this thread-workaround achieves the same result.
173
+        allValidBinding.addListener(
174
+                (observable, oldValue, newValue) -> MainController.this.startButton.setDisable(!newValue));
151 175
         final Thread WORKAROUND = new Thread(() -> {
152 176
             allValidBinding.get();
153 177
             try {
@@ -165,8 +189,9 @@ public class MainController {
165 189
         final double maxRe = this.maxRe.get();
166 190
         final double minIm = this.minIm.get();
167 191
         final double maxIm = this.maxIm.get();
192
+        final FractalType fractalType = this.getSelectedFractalType();
168 193
         this.service = new FractalService(minRe, maxRe, minIm, maxIm, this.width.get(), this.height.get(),
169
-                this.iterations.get(), FractalType.MANDELBROT);
194
+                this.iterations.get(), fractalType);
170 195
         this.service.setOnSucceeded(event -> {
171 196
             this.enableStartButton();
172 197
             final Image image = this.service.getValue();
@@ -174,7 +199,8 @@ public class MainController {
174 199
             gc.clearRect(0, 0, this.renderArea.getWidth(), this.renderArea.getHeight());
175 200
             this.renderArea.setWidth(this.width.get());
176 201
             this.renderArea.setHeight(this.height.get());
177
-            this.renderArea.setComplexBounds(this.minRe.get(), this.maxRe.get(), this.minIm.get(), this.maxIm.get());
202
+            this.renderArea.setComplexBounds(this.minRe.get(), this.maxRe.get(), this.minIm.get(),
203
+                    this.maxIm.get());
178 204
             gc.drawImage(image, 0, 0);
179 205
             this.progressBar.progressProperty().unbind();
180 206
             this.progressBar.setProgress(0);
@@ -229,14 +255,28 @@ public class MainController {
229 255
         final int width = this.width.get();
230 256
         final int height = this.height.get();
231 257
         final int iterations = this.iterations.get();
232
-        this.service.setValues(minRe, maxRe, minIm, maxIm, width, height, iterations, FractalType.MANDELBROT);
258
+        final FractalType fractalType = this.getSelectedFractalType();
259
+        this.service.setValues(minRe, maxRe, minIm, maxIm, width, height, iterations, fractalType);
233 260
         this.service.start();
234 261
         this.hideStartButton();
235 262
     }
236 263
 
264
+    private FractalType getSelectedFractalType() {
265
+        final Toggle selectedTaskType = this.typeToggleGroup.getSelectedToggle();
266
+        final FractalType fractalType;
267
+        if (this.typeMandelbrot.equals(selectedTaskType)) {
268
+            fractalType = FractalType.MANDELBROT;
269
+        } else if (this.typeJulia.equals(selectedTaskType)) {
270
+            fractalType = FractalType.JULIA;
271
+        } else {
272
+            fractalType = null;
273
+        }
274
+        return fractalType;
275
+    }
276
+
237 277
     /**
238
-     * Handler method that is called when the "Cancel" button is clicked (during an ongoing computation, as otherwise
239
-     * the cancel button is hidden and can't be clicked).
278
+     * Handler method that is called when the "Cancel" button is clicked (during an ongoing computation, as
279
+     * otherwise the cancel button is hidden and can't be clicked).
240 280
      *
241 281
      * @param actionEvent The button clicked event. Ignored, as it is not used.
242 282
      */
@@ -266,8 +306,8 @@ public class MainController {
266 306
     }
267 307
 
268 308
     /**
269
-     * Handler method that is called when the "Export" button is clicked. This method shows a file chooser dialog and
270
-     * saves the current image to the selected file.
309
+     * Handler method that is called when the "Export" button is clicked. This method shows a file chooser
310
+     * dialog and saves the current image to the selected file.
271 311
      *
272 312
      * @param actionEvent The button clicked event. Ignored, as it is not used.
273 313
      */
@@ -296,4 +336,9 @@ public class MainController {
296 336
         }
297 337
         return this.saveDialog;
298 338
     }
339
+
340
+    @FXML
341
+    public void typeChanged(final ActionEvent actionEvent) {
342
+        this.startButtonClicked(actionEvent);
343
+    }
299 344
 }

+ 27
- 9
src/main/resources/main.fxml View File

@@ -1,10 +1,18 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2
-<?import javafx.scene.control.*?>
3
-<?import javafx.scene.layout.*?>
4
-<?import javafx.scene.text.Text?>
5
-<?import ch.fritteli.javafx.text.DoubleTextField?>
6
-<?import ch.fritteli.javafx.text.ConstrainedIntegerTextField?>
7 2
 <?import ch.fritteli.fractal.gui.FractalCanvas?>
3
+<?import ch.fritteli.javafx.text.ConstrainedIntegerTextField?>
4
+<?import ch.fritteli.javafx.text.DoubleTextField?>
5
+<?import javafx.scene.control.Button?>
6
+<?import javafx.scene.control.Label?>
7
+<?import javafx.scene.control.ProgressBar?>
8
+<?import javafx.scene.control.RadioButton?>
9
+<?import javafx.scene.control.ScrollPane?>
10
+<?import javafx.scene.control.ToggleGroup?>
11
+<?import javafx.scene.control.ToolBar?>
12
+<?import javafx.scene.layout.GridPane?>
13
+<?import javafx.scene.layout.HBox?>
14
+<?import javafx.scene.layout.VBox?>
15
+<?import javafx.scene.text.Text?>
8 16
 <VBox fx:controller="ch.fritteli.fractal.gui.MainController"
9 17
       xmlns:fx="http://javafx.com/fxml" alignment="TOP_LEFT" stylesheets="style.css">
10 18
     <ToolBar>
@@ -25,20 +33,30 @@
25 33
             <Label text="Width" GridPane.columnIndex="4" GridPane.rowIndex="1" prefWidth="50"/>
26 34
             <ConstrainedIntegerTextField fx:id="width" GridPane.columnIndex="5" GridPane.rowIndex="1"/>
27 35
             <Label text="Height" GridPane.columnIndex="4" GridPane.rowIndex="2"/>
28
-            <ConstrainedIntegerTextField fx:id="height" GridPane.columnIndex="5" GridPane.rowIndex="2" prefWidth="50"/>
36
+            <ConstrainedIntegerTextField fx:id="height" GridPane.columnIndex="5" GridPane.rowIndex="2"
37
+                                         prefWidth="50"/>
29 38
             <Label text="Iterations" GridPane.columnIndex="6" GridPane.rowIndex="0"/>
30 39
             <ConstrainedIntegerTextField fx:id="iterations" GridPane.columnIndex="6" GridPane.rowIndex="1"/>
31 40
 
32
-            <Button fx:id="startButton" text="Start!" GridPane.columnIndex="6" GridPane.rowIndex="2"
41
+            <fx:define>
42
+                <ToggleGroup fx:id="typeToggleGroup"/>
43
+            </fx:define>
44
+            <HBox GridPane.columnIndex="6" GridPane.rowIndex="2">
45
+                <RadioButton fx:id="typeMandelbrot" toggleGroup="$typeToggleGroup" text="Mandelbrot"
46
+                             visible="true" disable="false" onAction="#typeChanged"/>
47
+                <RadioButton fx:id="typeJulia" toggleGroup="$typeToggleGroup" text="Julia" visible="true"
48
+                             disable="false" onAction="#typeChanged"/>
49
+            </HBox>
50
+            <Button fx:id="startButton" text="Start!" GridPane.columnIndex="7" GridPane.rowIndex="2"
33 51
                     onAction="#startButtonClicked" visible="true" disable="true"/>
34
-            <Button fx:id="cancelButton" text="Stop" GridPane.columnIndex="6" GridPane.rowIndex="2"
52
+            <Button fx:id="cancelButton" text="Stop" GridPane.columnIndex="7" GridPane.rowIndex="2"
35 53
                     onAction="#cancelButtonClicked" visible="false" disable="true"/>
36 54
             <Button text="Export image" GridPane.columnIndex="7"
37 55
                     GridPane.rowIndex="1" onAction="#export"/>
38 56
         </GridPane>
39 57
     </ToolBar>
40 58
     <HBox>
41
-    <ProgressBar fx:id="progressBar" progress="0.0f"/>
59
+        <ProgressBar fx:id="progressBar" progress="0.0f"/>
42 60
         <Text fx:id="coordinateOutput"/>
43 61
         <Text fx:id="status"/>
44 62
     </HBox>

Loading…
Cancel
Save