mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-01-30 14:39:56 +08:00
Use JFXListView in place of custom components to accelerate rendering
This commit is contained in:
parent
056a4eead2
commit
0813211c20
@ -17,14 +17,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui.construct;
|
package org.jackhuang.hmcl.ui.construct;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXListView;
|
||||||
import com.jfoenix.controls.JFXProgressBar;
|
import com.jfoenix.controls.JFXProgressBar;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.ReadOnlyIntegerProperty;
|
import javafx.beans.property.ReadOnlyIntegerProperty;
|
||||||
import javafx.beans.property.ReadOnlyIntegerWrapper;
|
import javafx.beans.property.ReadOnlyIntegerWrapper;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.ListCell;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import org.jackhuang.hmcl.download.forge.ForgeInstallTask;
|
import org.jackhuang.hmcl.download.forge.ForgeInstallTask;
|
||||||
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
||||||
import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask;
|
import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask;
|
||||||
@ -42,15 +45,16 @@ import java.util.Map;
|
|||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public final class TaskListPane extends StackPane {
|
public final class TaskListPane extends StackPane {
|
||||||
private final AdvancedListBox listBox = new AdvancedListBox();
|
private final JFXListView<Task> listBox = new JFXListView<>();
|
||||||
private final Map<Task, ProgressListNode> nodes = new HashMap<>();
|
private final Map<Task, ProgressListNode> nodes = new HashMap<>();
|
||||||
private final ReadOnlyIntegerWrapper finishedTasks = new ReadOnlyIntegerWrapper();
|
private final ReadOnlyIntegerWrapper finishedTasks = new ReadOnlyIntegerWrapper();
|
||||||
private final ReadOnlyIntegerWrapper totTasks = new ReadOnlyIntegerWrapper();
|
private final ReadOnlyIntegerWrapper totTasks = new ReadOnlyIntegerWrapper();
|
||||||
|
|
||||||
public TaskListPane() {
|
public TaskListPane() {
|
||||||
listBox.setSpacing(0);
|
|
||||||
|
|
||||||
getChildren().setAll(listBox);
|
getChildren().setAll(listBox);
|
||||||
|
|
||||||
|
listBox.setPadding(Insets.EMPTY);
|
||||||
|
listBox.setCellFactory(listView -> new ProgressListNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyIntegerProperty finishedTasksProperty() {
|
public ReadOnlyIntegerProperty finishedTasksProperty() {
|
||||||
@ -66,7 +70,7 @@ public final class TaskListPane extends StackPane {
|
|||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
listBox.clear();
|
listBox.getItems().clear();
|
||||||
finishedTasks.set(0);
|
finishedTasks.set(0);
|
||||||
totTasks.set(0);
|
totTasks.set(0);
|
||||||
});
|
});
|
||||||
@ -108,66 +112,66 @@ public final class TaskListPane extends StackPane {
|
|||||||
task.setName(i18n("modpack.scan"));
|
task.setName(i18n("modpack.scan"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressListNode node = new ProgressListNode(task);
|
Platform.runLater(() -> listBox.getItems().add(task));
|
||||||
nodes.put(task, node);
|
|
||||||
Platform.runLater(() -> listBox.add(node));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFinished(Task task) {
|
public void onFinished(Task task) {
|
||||||
ProgressListNode node = nodes.remove(task);
|
|
||||||
if (node == null)
|
|
||||||
return;
|
|
||||||
node.unbind();
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
listBox.remove(node);
|
if (listBox.getItems().remove(task))
|
||||||
finishedTasks.set(finishedTasks.getValue() + 1);
|
finishedTasks.set(finishedTasks.getValue() + 1);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed(Task task, Throwable throwable) {
|
|
||||||
ProgressListNode node = nodes.remove(task);
|
|
||||||
if (node == null)
|
|
||||||
return;
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
node.setThrowable(throwable);
|
|
||||||
finishedTasks.set(finishedTasks.getValue() + 1);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ProgressListNode extends VBox {
|
private static class ProgressListNode extends ListCell<Task> {
|
||||||
|
private final BorderPane borderPane = new BorderPane();
|
||||||
private final JFXProgressBar bar = new JFXProgressBar();
|
private final JFXProgressBar bar = new JFXProgressBar();
|
||||||
private final Label title = new Label();
|
private final Label title = new Label();
|
||||||
private final Label state = new Label();
|
private final Label state = new Label();
|
||||||
|
|
||||||
public ProgressListNode(Task task) {
|
{
|
||||||
bar.progressProperty().bind(task.progressProperty());
|
|
||||||
title.setText(task.getName());
|
|
||||||
state.textProperty().bind(task.messageProperty());
|
|
||||||
|
|
||||||
BorderPane borderPane = new BorderPane();
|
|
||||||
borderPane.setLeft(title);
|
borderPane.setLeft(title);
|
||||||
borderPane.setRight(state);
|
borderPane.setRight(state);
|
||||||
getChildren().addAll(borderPane, bar);
|
borderPane.setBottom(bar);
|
||||||
|
borderPane.setMinWidth(0);
|
||||||
|
borderPane.setPrefWidth(1);
|
||||||
|
|
||||||
|
setPadding(Insets.EMPTY);
|
||||||
|
|
||||||
bar.minWidthProperty().bind(widthProperty());
|
bar.minWidthProperty().bind(widthProperty());
|
||||||
bar.prefWidthProperty().bind(widthProperty());
|
bar.prefWidthProperty().bind(widthProperty());
|
||||||
bar.maxWidthProperty().bind(widthProperty());
|
bar.maxWidthProperty().bind(widthProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unbind() {
|
@Override
|
||||||
bar.progressProperty().unbind();
|
protected void updateItem(Task item, boolean empty) {
|
||||||
state.textProperty().unbind();
|
boolean wasEmpty = isEmpty();
|
||||||
}
|
Task oldTask = getItem();
|
||||||
|
|
||||||
public void setThrowable(Throwable throwable) {
|
if (!wasEmpty && oldTask != null) {
|
||||||
unbind();
|
bar.progressProperty().unbind();
|
||||||
state.setText(throwable.getLocalizedMessage());
|
state.textProperty().unbind();
|
||||||
bar.setProgress(0);
|
}
|
||||||
|
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (empty || item == null) {
|
||||||
|
setGraphic(null);
|
||||||
|
} else {
|
||||||
|
setGraphic(borderPane);
|
||||||
|
bar.visibleProperty().bind(Bindings.createBooleanBinding(() -> item.progressProperty().get() != -1, item.progressProperty()));
|
||||||
|
bar.progressProperty().bind(item.progressProperty());
|
||||||
|
state.textProperty().bind(Bindings.createObjectBinding(() -> {
|
||||||
|
if (item.getState() == Task.TaskState.FAILED) {
|
||||||
|
return item.getLastException().getLocalizedMessage();
|
||||||
|
} else {
|
||||||
|
return item.messageProperty().get();
|
||||||
|
}
|
||||||
|
}, item.messageProperty(), item.stateProperty()));
|
||||||
|
title.setText(item.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.task;
|
package org.jackhuang.hmcl.task;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
import javafx.beans.property.*;
|
||||||
import javafx.beans.property.ReadOnlyDoubleWrapper;
|
|
||||||
import javafx.beans.property.ReadOnlyStringProperty;
|
|
||||||
import javafx.beans.property.ReadOnlyStringWrapper;
|
|
||||||
import org.jackhuang.hmcl.event.EventManager;
|
import org.jackhuang.hmcl.event.EventManager;
|
||||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||||
import org.jackhuang.hmcl.util.InvocationDispatcher;
|
import org.jackhuang.hmcl.util.InvocationDispatcher;
|
||||||
@ -58,14 +55,18 @@ public abstract class Task {
|
|||||||
this.significance = significance;
|
this.significance = significance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskState state = TaskState.READY;
|
private ReadOnlyObjectWrapper<TaskState> state = new ReadOnlyObjectWrapper<>(this, "state", TaskState.READY);
|
||||||
|
|
||||||
public TaskState getState() {
|
public TaskState getState() {
|
||||||
return state;
|
return state.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setState(TaskState state) {
|
void setState(TaskState state) {
|
||||||
this.state = state;
|
this.state.setValue(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadOnlyObjectProperty<TaskState> stateProperty() {
|
||||||
|
return state.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Throwable lastException = null;
|
private Throwable lastException = null;
|
||||||
|
@ -211,6 +211,7 @@ public final class TaskExecutor {
|
|||||||
task.onDone().fireEvent(new TaskEvent(this, task, false));
|
task.onDone().fireEvent(new TaskEvent(this, task, false));
|
||||||
taskListeners.forEach(it -> it.onFinished(task));
|
taskListeners.forEach(it -> it.onFinished(task));
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
task.setLastException(e);
|
||||||
if (task.getSignificance().shouldLog()) {
|
if (task.getSignificance().shouldLog()) {
|
||||||
Logging.LOG.log(Level.FINE, "Task aborted: " + task.getName());
|
Logging.LOG.log(Level.FINE, "Task aborted: " + task.getName());
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ public abstract class TaskListener implements EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onFailed(Task task, Throwable throwable) {
|
public void onFailed(Task task, Throwable throwable) {
|
||||||
|
onFinished(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onStop(boolean success, TaskExecutor executor) {
|
public void onStop(boolean success, TaskExecutor executor) {
|
||||||
|
Loading…
Reference in New Issue
Block a user