Skip to content

Commit 6276578

Browse files
committed
remove AWT dependency, use some reactive binding
1 parent 6755ed7 commit 6276578

2 files changed

Lines changed: 47 additions & 58 deletions

File tree

src/main/java/com.babai.maptracker/MapTrackerUIFX.java

Lines changed: 38 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@
2121
*
2222
*/
2323

24-
import java.awt.Dimension;
25-
import java.awt.Graphics2D;
26-
import java.awt.Toolkit;
27-
import java.awt.image.BufferedImage;
2824
import java.io.File;
2925
import java.io.IOException;
3026
import java.io.PrintWriter;
@@ -40,14 +36,19 @@
4036

4137
import javafx.application.Application;
4238
import javafx.application.Platform;
39+
import javafx.beans.property.DoubleProperty;
40+
import javafx.beans.property.SimpleDoubleProperty;
4341
import javafx.embed.swing.SwingFXUtils;
4442
import javafx.embed.swing.SwingNode;
4543
import javafx.geometry.Insets;
4644
import javafx.geometry.Orientation;
4745
import javafx.geometry.Pos;
46+
import javafx.geometry.Rectangle2D;
4847
import javafx.scene.Cursor;
4948
import javafx.scene.ImageCursor;
5049
import javafx.scene.Scene;
50+
import javafx.scene.canvas.Canvas;
51+
import javafx.scene.canvas.GraphicsContext;
5152
import javafx.scene.control.Button;
5253
import javafx.scene.control.ComboBox;
5354
import javafx.scene.control.Label;
@@ -59,6 +60,7 @@
5960
import javafx.scene.control.SplitPane;
6061
import javafx.scene.control.TextArea;
6162
import javafx.scene.control.TextField;
63+
import javafx.scene.image.Image;
6264
import javafx.scene.image.ImageView;
6365
import javafx.scene.input.KeyCombination;
6466
import javafx.scene.layout.ColumnConstraints;
@@ -70,15 +72,16 @@
7072
import javafx.scene.transform.Transform;
7173
import javafx.stage.DirectoryChooser;
7274
import javafx.stage.FileChooser;
75+
import javafx.stage.Screen;
7376
import javafx.stage.Stage;
7477

7578
import map.*;
7679

7780
public class MapTrackerUIFX extends Application {
7881
static final Properties markerNames = new Properties();
7982

80-
private double scaleFactor = 1.0;
81-
private BufferedImage origBg = null, currentBg = null;
83+
private Image origBg = null;
84+
8285
private Marker currentMarker = null;
8386
private Vector<Marker> markers = new Vector<>();
8487
private Vector<Mark> marks = new Vector<>();
@@ -101,21 +104,24 @@ public static void show(String...args) {
101104
}
102105

103106
public void start(Stage stage) throws Exception {
104-
stage.setTitle("Map Tracker");
105-
Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
107+
stage.setTitle("Map Tracker");
108+
Rectangle2D screenBounds = Screen.getPrimary().getBounds();
106109

107110
// Main Contents: the background image
108-
ImageView img = new ImageView();
111+
Canvas img = new Canvas(screenBounds.getWidth(), screenBounds.getHeight());
112+
DoubleProperty scaleFactor = new SimpleDoubleProperty(1.0);
113+
114+
scaleFactor.addListener(e -> updateView(img, scaleFactor.get()));
109115
img.setOnMouseClicked(e -> {
110116
addMarker((int) e.getX(), (int) e.getY(), currentMarker);
111-
updateView(img);
117+
updateView(img, scaleFactor.get());
112118
});
113119
img.setOnMouseEntered(e -> updateCursor(currentMarker));
114120
img.setOnMouseExited(e -> updateCursor(Cursor.DEFAULT));
115121

116122
ScrollPane scrImg = new ScrollPane();
117123
scrImg.setContent(img);
118-
scrImg.setMinSize(0.5*size.width, 0.70*size.height);
124+
scrImg.setMaxSize(screenBounds.getWidth(), 0.70*screenBounds.getHeight());
119125

120126
// Bottom Pane
121127
GridPane pnlForm = new GridPane();
@@ -175,6 +181,7 @@ public void start(Stage stage) throws Exception {
175181
pnlForm.setPadding(new Insets(10));
176182

177183
SplitPane mainPane = new SplitPane(scrImg, pnlForm);
184+
mainPane.setDividerPosition(0, 0.75);
178185
mainPane.setOrientation(Orientation.VERTICAL);
179186

180187
pnlForm.setStyle("-fx-background-color: lightblue");
@@ -196,18 +203,8 @@ public void start(Stage stage) throws Exception {
196203
jmiOpen.setOnAction(e -> openImage(stage, img));
197204
jmiSave.setOnAction(e -> save(stage));
198205
jmiExit.setOnAction(e -> Platform.exit());
199-
jmiZoomIn.setOnAction(e -> {
200-
if (origBg != null) {
201-
scaleFactor /= 2;
202-
updateView(img);
203-
}
204-
});
205-
jmiZoomOut.setOnAction(e -> {
206-
if (origBg != null) {
207-
scaleFactor *= 2;
208-
updateView(img);
209-
}
210-
});
206+
jmiZoomIn.setOnAction(e -> scaleFactor.set(scaleFactor.get() * 2));
207+
jmiZoomOut.setOnAction(e -> scaleFactor.set(scaleFactor.get() / 2));
211208
jmiUsage.setOnAction(e -> showHelp());
212209

213210
Menu jmFile = new Menu("File", null, jmiOpen, jmiSave, jmiExit);
@@ -218,7 +215,7 @@ public void start(Stage stage) throws Exception {
218215

219216
VBox box = new VBox(5, bar, mainPane);
220217
VBox.setVgrow(mainPane, Priority.ALWAYS);
221-
scene = new Scene(box, size.width, size.height);
218+
scene = new Scene(box, screenBounds.getWidth(), screenBounds.getHeight());
222219
stage.setScene(scene);
223220
stage.centerOnScreen();
224221
stage.show();
@@ -255,7 +252,7 @@ private void updateMarkerList(Stage stage, ComboBox<Marker> cbMarkers) {
255252
}
256253
}
257254

258-
private void openImage(Stage stage, ImageView imgView) {
255+
private void openImage(Stage stage, Canvas imgView) {
259256
Preferences prPref = Preferences.userNodeForPackage(MapTrackerUIFX.class);
260257
FileChooser files = new FileChooser();
261258
files.setInitialDirectory(new File(prPref.get("lastOpenDir", System.getProperty("user.home"))));
@@ -264,9 +261,10 @@ private void openImage(Stage stage, ImageView imgView) {
264261
if (f == null) return;
265262

266263
try {
267-
scaleFactor = 1;
268-
origBg = ImageIO.read(f);
269-
imgView.setImage(SwingFXUtils.toFXImage(origBg, null));
264+
origBg = SwingFXUtils.toFXImage(ImageIO.read(f), null);
265+
imgView.widthProperty().bind(origBg.widthProperty());
266+
imgView.heightProperty().bind(origBg.heightProperty());
267+
updateView(imgView, 1.0);
270268
} catch (IOException ioe) {
271269
ioe.printStackTrace();
272270
} finally {
@@ -280,10 +278,7 @@ private void save(Stage stage) {
280278
files.setInitialDirectory(new File(prPref.get("lastSaveDir", System.getProperty("user.home"))));
281279
File f = files.showSaveDialog(stage);
282280
try (PrintWriter stream = new PrintWriter(f)) {
283-
if (!f.exists()) {
284-
f.createNewFile();
285-
}
286-
281+
if (!f.exists()) f.createNewFile();
287282
write(stream);
288283
} catch (IOException e) {
289284
e.printStackTrace();
@@ -349,38 +344,27 @@ private void addMarker(double x, double y, Marker marker) {
349344
tfCoordY.setText("%d".formatted((int) y));
350345
}
351346

352-
private BufferedImage drawMarkers() {
353-
BufferedImage overlay = new BufferedImage(
354-
(int) (origBg.getWidth()),
355-
(int) (origBg.getHeight()),
356-
BufferedImage.TYPE_INT_ARGB);
357-
Graphics2D g = overlay.createGraphics();
358-
359-
g.drawImage(origBg, 0, 0, overlay.getWidth(), overlay.getHeight(), null);
360-
for (Mark m : marks) {
361-
System.out.println("Drawing: " + m);
362-
g.drawImage(m.marker().img(), (int) m.x(), (int) m.y(), null);
363-
}
364-
365-
g.dispose();
366-
return overlay;
367-
}
368-
369347
private void updateCursor(Marker marker) {
370348
if (marker == null) return;
371-
ImageCursor cursor = new ImageCursor(SwingFXUtils.toFXImage(marker.img(), null));
349+
ImageCursor cursor = new ImageCursor(marker.img());
372350
scene.setCursor(cursor);
373351
}
374352

375353
private void updateCursor(Cursor inbuiltCursor) {
376354
scene.setCursor(inbuiltCursor);
377355
}
378356

379-
private void updateView(ImageView img) {
380-
currentBg = drawMarkers();
357+
private void updateView(Canvas img, double scaleFactor) {
358+
GraphicsContext ctx = img.getGraphicsContext2D();
359+
ctx.clearRect(0, 0, img.getWidth(), img.getHeight());
360+
System.out.println("Drawing Background");
361+
ctx.drawImage(origBg, 0, 0);
362+
for (Mark m : marks) {
363+
System.out.println("Drawing: " + m);
364+
ctx.drawImage(m.marker().img(), m.x(), m.y());
365+
}
381366
img.getTransforms().clear();
382367
img.getTransforms().add(Transform.scale(scaleFactor, scaleFactor));
383-
img.setImage(SwingFXUtils.toFXImage(currentBg, null));
384368
}
385369

386370
// Custom renderer for the Marker combobox that shows both icons and text
@@ -398,7 +382,7 @@ public void updateItem(Marker m, boolean empty) {
398382
setText(m.name());
399383
view.setFitWidth(30);
400384
view.setFitHeight(30);
401-
view.setImage(SwingFXUtils.toFXImage(m.img(), null));
385+
view.setImage(m.img());
402386
setGraphic(view);
403387
}
404388
}

src/main/java/com.babai.maptracker/map/Marker.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,28 @@
2323

2424
package map;
2525

26-
import java.awt.image.BufferedImage;
2726
import java.io.File;
2827
import java.io.FileInputStream;
2928
import java.io.IOException;
3029

3130
import javax.imageio.ImageIO;
3231

33-
public record Marker(String name, String filename, BufferedImage img) {
32+
import javafx.embed.swing.SwingFXUtils;
33+
import javafx.scene.image.Image;
34+
35+
// Note: JavaFX doesn't have webp support, so we need to piggyback ImageIO
36+
// to use it's webp-imageio support bridge.
37+
38+
public record Marker(String name, String filename, Image img) {
3439

3540
public static Marker load(String name, String filename, File imgFile) throws IOException {
3641
var img = ImageIO.read(new FileInputStream(imgFile));
37-
return new Marker(name, filename, img);
42+
return new Marker(name, filename, SwingFXUtils.toFXImage(img, null));
3843
}
3944

4045
public static Marker loadInternal(String name, String filename) throws IOException {
4146
var img = ImageIO.read(Marker.class.getResourceAsStream("/markers/" + filename));
42-
return new Marker(name, filename, img);
47+
return new Marker(name, filename, SwingFXUtils.toFXImage(img, null));
4348
}
4449

4550
@Override

0 commit comments

Comments
 (0)