From 88d7ade182c94ef343e7c9ea5d667354e57488d3 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sun, 28 Jun 2026 13:11:32 +0800 Subject: [PATCH 1/5] Perf: Optimized list loading of FontComboBox --- .../hmcl/ui/construct/FontComboBox.java | 62 ++++++++++++++++--- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java index 64ffda3317e..81f6ee46d1b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java @@ -18,22 +18,30 @@ package org.jackhuang.hmcl.ui.construct; import static javafx.collections.FXCollections.emptyObservableList; -import static javafx.collections.FXCollections.observableList; import static javafx.collections.FXCollections.singletonObservableList; +import java.util.List; + import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.util.javafx.BindingMapping; import com.jfoenix.controls.JFXComboBox; import com.jfoenix.controls.JFXListCell; +import javafx.application.Platform; import javafx.beans.binding.Bindings; +import javafx.collections.FXCollections; import javafx.scene.text.Font; public final class FontComboBox extends JFXComboBox { + private static final List ALLFONTS = Font.getFamilies(); + private static final List COMMON_FONTS = ALLFONTS.subList(0, Math.min(10, ALLFONTS.size())); + private boolean loaded = false; + private Thread loadingThread = null; + public FontComboBox() { setMinWidth(260); @@ -54,12 +62,52 @@ public void updateItem(String item, boolean empty) { itemsProperty().bind(BindingMapping.of(valueProperty()) .map(value -> value == null ? emptyObservableList() : singletonObservableList(value))); + setOnHiding(event -> { + if (loadingThread != null && loadingThread.isAlive()) { + loadingThread.interrupt(); + loadingThread = null; + loaded = false; + } + }); + FXUtils.onClicked(this, () -> { - if (loaded) - return; + if (loaded) return; + itemsProperty().unbind(); - setItems(observableList(Font.getFamilies())); - loaded = true; - }); + + var currentItems = FXCollections.observableArrayList(COMMON_FONTS); + setItems(currentItems); + show(); + + loadingThread = new Thread(() -> { + + List remainingFonts = ALLFONTS.stream() + .filter(f -> !COMMON_FONTS.contains(f)) + .toList(); + + int batchSize = 30; + for (int i = 0; i < remainingFonts.size(); i += batchSize) { + + if (Thread.currentThread().isInterrupted()) return; + + int start = i; + int end = Math.min(start + batchSize, remainingFonts.size()); + List batch = remainingFonts.subList(start, end); + + Platform.runLater(() -> currentItems.addAll(batch)); + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + } + + loaded = true; + }); + + loadingThread.start(); + }); } -} +} \ No newline at end of file From 1176fded93c879f91cb04a58ed75f37d58b19476 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sun, 28 Jun 2026 13:21:02 +0800 Subject: [PATCH 2/5] Style: EOF --- .../main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java index 81f6ee46d1b..833fd56f8c5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java @@ -110,4 +110,4 @@ public void updateItem(String item, boolean empty) { loadingThread.start(); }); } -} \ No newline at end of file +} From c88f5e1482e894f88ad345354f3f1689ed1924a5 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sun, 28 Jun 2026 13:44:45 +0800 Subject: [PATCH 3/5] Refactor: Init for list, volatile, daemon for thread --- .../hmcl/ui/construct/FontComboBox.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java index 833fd56f8c5..60925d998f6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java @@ -34,14 +34,13 @@ import javafx.scene.text.Font; public final class FontComboBox extends JFXComboBox { - - private static final List ALLFONTS = Font.getFamilies(); - private static final List COMMON_FONTS = ALLFONTS.subList(0, Math.min(10, ALLFONTS.size())); - - private boolean loaded = false; + private static List allFonts; + private static List headFonts; private Thread loadingThread = null; + private volatile boolean loaded = false; + public FontComboBox() { setMinWidth(260); @@ -71,18 +70,23 @@ public void updateItem(String item, boolean empty) { }); FXUtils.onClicked(this, () -> { - if (loaded) return; + if (loaded || (loadingThread != null && loadingThread.isAlive())) return; itemsProperty().unbind(); - var currentItems = FXCollections.observableArrayList(COMMON_FONTS); + allFonts = Font.getFamilies(); + headFonts = allFonts.subList(0, Math.min(10, allFonts.size())); + + var currentItems = FXCollections.observableArrayList(headFonts); setItems(currentItems); show(); loadingThread = new Thread(() -> { - - List remainingFonts = ALLFONTS.stream() - .filter(f -> !COMMON_FONTS.contains(f)) + + itemsProperty().unbind(); + + List remainingFonts = allFonts.stream() + .filter(f -> !headFonts.contains(f)) .toList(); int batchSize = 30; @@ -107,6 +111,7 @@ public void updateItem(String item, boolean empty) { loaded = true; }); + loadingThread.setDaemon(true); loadingThread.start(); }); } From d4374cdd985645e0f0c11959e3a2242324d1de41 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sun, 28 Jun 2026 13:53:20 +0800 Subject: [PATCH 4/5] Refactor: Safety for list and thread, sublist for head --- .../jackhuang/hmcl/ui/construct/FontComboBox.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java index 60925d998f6..3289cea6f39 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java @@ -34,9 +34,6 @@ import javafx.scene.text.Font; public final class FontComboBox extends JFXComboBox { - private static List allFonts; - private static List headFonts; - private Thread loadingThread = null; private volatile boolean loaded = false; @@ -74,8 +71,8 @@ public void updateItem(String item, boolean empty) { itemsProperty().unbind(); - allFonts = Font.getFamilies(); - headFonts = allFonts.subList(0, Math.min(10, allFonts.size())); + List allFonts = Font.getFamilies(); + List headFonts = allFonts.subList(0, Math.min(10, allFonts.size())); var currentItems = FXCollections.observableArrayList(headFonts); setItems(currentItems); @@ -83,11 +80,7 @@ public void updateItem(String item, boolean empty) { loadingThread = new Thread(() -> { - itemsProperty().unbind(); - - List remainingFonts = allFonts.stream() - .filter(f -> !headFonts.contains(f)) - .toList(); + List remainingFonts = allFonts.subList(Math.min(10, allFonts.size()), allFonts.size()); int batchSize = 30; for (int i = 0; i < remainingFonts.size(); i += batchSize) { From 062dccd7d538ffb8a4e0f692338946ed760aa7a4 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sun, 28 Jun 2026 14:01:04 +0800 Subject: [PATCH 5/5] Refactor: Non-variable, thread safety, memory leak --- .../hmcl/ui/construct/FontComboBox.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java index 3289cea6f39..e897f99606d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FontComboBox.java @@ -36,7 +36,7 @@ public final class FontComboBox extends JFXComboBox { private Thread loadingThread = null; - private volatile boolean loaded = false; + private boolean loaded = false; public FontComboBox() { setMinWidth(260); @@ -71,17 +71,16 @@ public void updateItem(String item, boolean empty) { itemsProperty().unbind(); - List allFonts = Font.getFamilies(); - List headFonts = allFonts.subList(0, Math.min(10, allFonts.size())); + List allFonts = List.copyOf(Font.getFamilies()); + int limit = Math.min(10, allFonts.size()); + List headFonts = allFonts.subList(0, limit); + List remainingFonts = List.copyOf(allFonts.subList(limit, allFonts.size())); var currentItems = FXCollections.observableArrayList(headFonts); setItems(currentItems); show(); loadingThread = new Thread(() -> { - - List remainingFonts = allFonts.subList(Math.min(10, allFonts.size()), allFonts.size()); - int batchSize = 30; for (int i = 0; i < remainingFonts.size(); i += batchSize) { @@ -101,7 +100,10 @@ public void updateItem(String item, boolean empty) { } } - loaded = true; + Platform.runLater(() -> { + loaded = true; + loadingThread = null; + }); }); loadingThread.setDaemon(true);