更新 ToolbarListPageSkin 以使用 JFXListView 展示节点 (#5221)

This commit is contained in:
Glavo
2026-01-13 21:08:36 +08:00
committed by GitHub
parent 9b9471da49
commit ea407be5f0
9 changed files with 45 additions and 101 deletions

View File

@@ -18,24 +18,26 @@
package org.jackhuang.hmcl.ui; package org.jackhuang.hmcl.ui;
import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXListView;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ListCell;
import javafx.scene.control.SkinBase; import javafx.scene.control.SkinBase;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.ui.construct.ComponentList; import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.ui.construct.SpinnerPane; import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import java.util.List; import java.util.List;
public abstract class ToolbarListPageSkin<T extends ListPageBase<? extends Node>> extends SkinBase<T> { public abstract class ToolbarListPageSkin<E, P extends ListPageBase<E>> extends SkinBase<P> {
public ToolbarListPageSkin(T skinnable) { protected final JFXListView<E> listView;
public ToolbarListPageSkin(P skinnable) {
super(skinnable); super(skinnable);
SpinnerPane spinnerPane = new SpinnerPane(); SpinnerPane spinnerPane = new SpinnerPane();
@@ -58,18 +60,12 @@ public abstract class ToolbarListPageSkin<T extends ListPageBase<? extends Node>
} }
{ {
ScrollPane scrollPane = new ScrollPane(); this.listView = new JFXListView<>();
ComponentList.setVgrow(scrollPane, Priority.ALWAYS); this.listView.setPadding(Insets.EMPTY);
scrollPane.setFitToWidth(true); this.listView.setCellFactory(listView -> createListCell((JFXListView<E>) listView));
ComponentList.setVgrow(listView, Priority.ALWAYS);
VBox content = new VBox(); Bindings.bindContent(this.listView.getItems(), skinnable.itemsProperty());
root.getContent().add(listView);
Bindings.bindContent(content.getChildren(), skinnable.itemsProperty());
scrollPane.setContent(content);
FXUtils.smoothScrolling(scrollPane);
root.getContent().add(scrollPane);
} }
spinnerPane.setContent(root); spinnerPane.setContent(root);
@@ -102,5 +98,21 @@ public abstract class ToolbarListPageSkin<T extends ListPageBase<? extends Node>
return ret; return ret;
} }
protected abstract List<Node> initializeToolbar(T skinnable); protected abstract List<Node> initializeToolbar(P skinnable);
protected ListCell<E> createListCell(JFXListView<E> listView) {
return new ListCell<>() {
@Override
protected void updateItem(E item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item instanceof Node node) {
setGraphic(node);
setText(null);
} else {
setGraphic(null);
setText(null);
}
}
};
}
} }

View File

@@ -1,75 +0,0 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui;
import com.jfoenix.controls.JFXListView;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.SkinBase;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import java.util.List;
// TODO: Replace ToolbarListPageSkin with this class gradually
public abstract class ToolbarListPageSkin2<E, P extends ListPageBase<E>> extends SkinBase<P> {
protected final JFXListView<E> listView;
public ToolbarListPageSkin2(P skinnable) {
super(skinnable);
SpinnerPane spinnerPane = new SpinnerPane();
spinnerPane.loadingProperty().bind(skinnable.loadingProperty());
spinnerPane.failedReasonProperty().bind(skinnable.failedReasonProperty());
spinnerPane.onFailedActionProperty().bind(skinnable.onFailedActionProperty());
spinnerPane.getStyleClass().add("large-spinner-pane");
ComponentList root = new ComponentList();
root.getStyleClass().add("no-padding");
StackPane.setMargin(root, new Insets(10));
List<Node> toolbarButtons = initializeToolbar(skinnable);
if (!toolbarButtons.isEmpty()) {
HBox toolbar = new HBox();
toolbar.setAlignment(Pos.CENTER_LEFT);
toolbar.setPickOnBounds(false);
toolbar.getChildren().setAll(toolbarButtons);
root.getContent().add(toolbar);
}
{
this.listView = new JFXListView<>();
this.listView.setPadding(Insets.EMPTY);
ComponentList.setVgrow(listView, Priority.ALWAYS);
Bindings.bindContent(this.listView.getItems(), skinnable.itemsProperty());
root.getContent().add(listView);
}
spinnerPane.setContent(root);
getChildren().setAll(spinnerPane);
}
protected abstract List<Node> initializeToolbar(P skinnable);
}

View File

@@ -295,7 +295,7 @@ public final class JavaManagementPage extends ListPageBase<JavaManagementPage.Ja
} }
} }
private static final class JavaPageSkin extends ToolbarListPageSkin<JavaManagementPage> { private static final class JavaPageSkin extends ToolbarListPageSkin<JavaItem, JavaManagementPage> {
JavaPageSkin(JavaManagementPage skinnable) { JavaPageSkin(JavaManagementPage skinnable) {
super(skinnable); super(skinnable);

View File

@@ -192,7 +192,7 @@ public final class JavaRestorePage extends ListPageBase<JavaRestorePage.Disabled
} }
} }
private static final class JavaRestorePageSkin extends ToolbarListPageSkin<JavaRestorePage> { private static final class JavaRestorePageSkin extends ToolbarListPageSkin<DisabledJavaItem, JavaRestorePage> {
JavaRestorePageSkin(JavaRestorePage skinnable) { JavaRestorePageSkin(JavaRestorePage skinnable) {
super(skinnable); super(skinnable);
} }

View File

@@ -17,11 +17,13 @@
*/ */
package org.jackhuang.hmcl.ui.versions; package org.jackhuang.hmcl.ui.versions;
import com.jfoenix.controls.JFXListView;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.ListCell;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
@@ -154,17 +156,21 @@ public class GameListPage extends DecoratorAnimatedPage implements DecoratorPage
return new GameListSkin(); return new GameListSkin();
} }
private class GameListSkin extends ToolbarListPageSkin2<GameListItem, GameList> { private class GameListSkin extends ToolbarListPageSkin<GameListItem, GameList> {
public GameListSkin() { public GameListSkin() {
super(GameList.this); super(GameList.this);
this.listView.setCellFactory(listView -> new GameListCell());
} }
@Override @Override
protected List<Node> initializeToolbar(GameList skinnable) { protected List<Node> initializeToolbar(GameList skinnable) {
return Collections.emptyList(); return Collections.emptyList();
} }
@Override
protected ListCell<GameListItem> createListCell(JFXListView<GameListItem> listView) {
return new GameListCell();
}
} }
} }

View File

@@ -165,7 +165,7 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
executor.start(); executor.start();
} }
private class InstallerListPageSkin extends ToolbarListPageSkin<InstallerListPage> { private class InstallerListPageSkin extends ToolbarListPageSkin<InstallerItem, InstallerListPage> {
InstallerListPageSkin() { InstallerListPageSkin() {
super(InstallerListPage.this); super(InstallerListPage.this);

View File

@@ -599,7 +599,7 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
} }
} }
private final class SchematicsPageSkin extends ToolbarListPageSkin<SchematicsPage> { private final class SchematicsPageSkin extends ToolbarListPageSkin<Item, SchematicsPage> {
SchematicsPageSkin() { SchematicsPageSkin() {
super(SchematicsPage.this); super(SchematicsPage.this);
} }

View File

@@ -155,7 +155,7 @@ public final class WorldBackupsPage extends ListPageBase<WorldBackupsPage.Backup
}), i18n("world.backup"), null); }), i18n("world.backup"), null);
} }
private final class WorldBackupsPageSkin extends ToolbarListPageSkin<WorldBackupsPage> { private final class WorldBackupsPageSkin extends ToolbarListPageSkin<BackupInfo, WorldBackupsPage> {
WorldBackupsPageSkin() { WorldBackupsPageSkin() {
super(WorldBackupsPage.this); super(WorldBackupsPage.this);

View File

@@ -21,6 +21,7 @@ import com.jfoenix.controls.JFXCheckBox;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.Skin;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import org.jackhuang.hmcl.game.World; import org.jackhuang.hmcl.game.World;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
@@ -67,7 +68,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
} }
@Override @Override
protected ToolbarListPageSkin<WorldListPage> createDefaultSkin() { protected Skin<WorldListPage> createDefaultSkin() {
return new WorldListPageSkin(); return new WorldListPageSkin();
} }
@@ -161,7 +162,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
this.showAll.set(showAll); this.showAll.set(showAll);
} }
private final class WorldListPageSkin extends ToolbarListPageSkin<WorldListPage> { private final class WorldListPageSkin extends ToolbarListPageSkin<WorldListItem, WorldListPage> {
WorldListPageSkin() { WorldListPageSkin() {
super(WorldListPage.this); super(WorldListPage.this);