700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 用户控件 自定义控件_新的自定义控件:TaskProgressView

用户控件 自定义控件_新的自定义控件:TaskProgressView

时间:2019-10-28 16:27:44

相关推荐

用户控件 自定义控件_新的自定义控件:TaskProgressView

用户控件 自定义控件

我已经编写了一个新的自定义控件,并将其提交到ControlsFX项目。 这是一个高度专业的控件,用于显示后台任务,其当前状态和进度的列表。 这实际上是我为ControlsFX编写的第一个控件,只是出于乐趣的考虑,这意味着我自己没有用例(但是肯定会有一个用例)。 下面的屏幕截图显示了正在使用的控件。

如果您已经熟悉javafx.concurrent.Task类,您将很快掌握该控件显示其title,message和progress属性的值。 但它还会显示一个图标,但TaskAPI并未涵盖。 我添加了一个可选的图形工厂(回调),它将为每个任务调用以查找图形节点,该图形节点将放置在代表该任务的列表视图单元格的左侧。

可以在此处找到显示控件正在运行的视频:

控制

由于此控件非常简单,因此我认为有必要为其发布完整的源代码,以便其他人可以学习使用。 下面的清单显示了控件本身的代码。 正如预期的那样,它扩展了Control类,并为受监视的任务提供了一个可观察的列表,为图形工厂(回调)提供了一个对象属性。

package org.controlsfx.control;import .controlsfx.skin.TaskProgressViewSkin;import javafx.beans.property.ObjectProperty;import javafx.beans.property.SimpleObjectProperty;import javafx.collections.FXCollections;import javafx.collections.ListChangeListener;import javafx.collections.ObservableList;import javafx.concurrent.Task;import javafx.concurrent.WorkerStateEvent;import javafx.event.EventHandler;import javafx.scene.Node;import javafx.scene.control.Control;import javafx.scene.control.Skin;import javafx.util.Callback;/*** The task progress view is used to visualize the progress of long running* tasks. These tasks are created via the {@link Task} class. This view* manages a list of such tasks and displays each one of them with their* name, progress, and update messages.<p>* An optional graphic factory can be set to place a graphic in each row.* This allows the user to more easily distinguish between different types* of tasks.** <h3>Screenshots</h3>* The picture below shows the default appearance of the task progress view* control:* <center><img src="task-monitor.png" /></center>** <h3>Code Sample</h3>** <pre>* TaskProgressView<MyTask> view = new TaskProgressView<>();* view.setGraphicFactory(task -> return new ImageView("db-access.png"));* view.getTasks().add(new MyTask());* </pre>*/public class TaskProgressView<T extends Task<?>> extends Control {/*** Constructs a new task progress view.*/public TaskProgressView() {getStyleClass().add("task-progress-view");EventHandler<WorkerStateEvent> taskHandler = evt -> {if (evt.getEventType().equals(WorkerStateEvent.WORKER_STATE_SUCCEEDED)|| evt.getEventType().equals(WorkerStateEvent.WORKER_STATE_CANCELLED)|| evt.getEventType().equals(WorkerStateEvent.WORKER_STATE_FAILED)) {getTasks().remove(evt.getSource());}};getTasks().addListener(new ListChangeListener<Task<?>>() {@Overridepublic void onChanged(Change<? extends Task<?>> c) {while (c.next()) {if (c.wasAdded()) {for (Task<?> task : c.getAddedSubList()) {task.addEventHandler(WorkerStateEvent.ANY,taskHandler);}} else if (c.wasRemoved()) {for (Task<?> task : c.getAddedSubList()) {task.removeEventHandler(WorkerStateEvent.ANY,taskHandler);}}}}});}@Overrideprotected Skin<?> createDefaultSkin() {return new TaskProgressViewSkin<>(this);}private final ObservableList<T> tasks = FXCollections.observableArrayList();/*** Returns the list of tasks currently monitored by this view.** @return the monitored tasks*/public final ObservableList<T> getTasks() {return tasks;}private ObjectProperty<Callback<T, Node>> graphicFactory;/*** Returns the property used to store an optional callback for creating* custom graphics for each task.** @return the graphic factory property*/public final ObjectProperty<Callback<T, Node>> graphicFactoryProperty() {if (graphicFactory == null) {graphicFactory = new SimpleObjectProperty<Callback<T, Node>>(this, "graphicFactory");}return graphicFactory;}/*** Returns the value of {@link #graphicFactoryProperty()}.** @return the optional graphic factory*/public final Callback<T, Node> getGraphicFactory() {return graphicFactory == null ? null : graphicFactory.get();}/*** Sets the value of {@link #graphicFactoryProperty()}.** @param factory an optional graphic factory*/public final void setGraphicFactory(Callback<T, Node> factory) {graphicFactoryProperty().set(factory);}

皮肤

如您所料,皮肤将使用带有自定义单元工厂的ListView来显示任务。

package .controlsfx.skin;import javafx.beans.binding.Bindings;import javafx.concurrent.Task;import javafx.geometry.Insets;import javafx.geometry.Pos;import javafx.scene.Node;import javafx.scene.control.Button;import javafx.scene.control.ContentDisplay;import javafx.scene.control.Label;import javafx.scene.control.ListCell;import javafx.scene.control.ListView;import javafx.scene.control.ProgressBar;import javafx.scene.control.SkinBase;import javafx.scene.control.Tooltip;import javafx.scene.layout.BorderPane;import javafx.scene.layout.VBox;import javafx.util.Callback;import org.controlsfx.control.TaskProgressView;import com.sun.javafx.css.StyleManager;public class TaskProgressViewSkin<T extends Task<?>> extendsSkinBase<TaskProgressView<T>> {static {StyleManager.getInstance().addUserAgentStylesheet(TaskProgressView.class.getResource("taskprogressview.css").toExternalForm()); //$NON-NLS-1$}public TaskProgressViewSkin(TaskProgressView<T> monitor) {super(monitor);BorderPane borderPane = new BorderPane();borderPane.getStyleClass().add("box");// list viewListView<T> listView = new ListView<>();listView.setPrefSize(500, 400);listView.setPlaceholder(new Label("No tasks running"));listView.setCellFactory(param -> new TaskCell());listView.setFocusTraversable(false);Bindings.bindContent(listView.getItems(), monitor.getTasks());borderPane.setCenter(listView);getChildren().add(listView);}class TaskCell extends ListCell<T> {private ProgressBar progressBar;private Label titleText;private Label messageText;private Button cancelButton;private T task;private BorderPane borderPane;public TaskCell() {titleText = new Label();titleText.getStyleClass().add("task-title");messageText = new Label();messageText.getStyleClass().add("task-message");progressBar = new ProgressBar();progressBar.setMaxWidth(Double.MAX_VALUE);progressBar.setMaxHeight(8);progressBar.getStyleClass().add("task-progress-bar");cancelButton = new Button("Cancel");cancelButton.getStyleClass().add("task-cancel-button");cancelButton.setTooltip(new Tooltip("Cancel Task"));cancelButton.setOnAction(evt -> {if (task != null) {task.cancel();}});VBox vbox = new VBox();vbox.setSpacing(4);vbox.getChildren().add(titleText);vbox.getChildren().add(progressBar);vbox.getChildren().add(messageText);BorderPane.setAlignment(cancelButton, Pos.CENTER);BorderPane.setMargin(cancelButton, new Insets(0, 0, 0, 4));borderPane = new BorderPane();borderPane.setCenter(vbox);borderPane.setRight(cancelButton);setContentDisplay(ContentDisplay.GRAPHIC_ONLY);}@Overridepublic void updateIndex(int index) {super.updateIndex(index);/** I have no idea why this is necessary but it won't work without* it. Shouldn't the updateItem method be enough?*/if (index == -1) {setGraphic(null);getStyleClass().setAll("task-list-cell-empty");}}@Overrideprotected void updateItem(T task, boolean empty) {super.updateItem(task, empty);this.task = task;if (empty || task == null) {getStyleClass().setAll("task-list-cell-empty");setGraphic(null);} else if (task != null) {getStyleClass().setAll("task-list-cell");progressBar.progressProperty().bind(task.progressProperty());titleText.textProperty().bind(task.titleProperty());messageText.textProperty().bind(task.messageProperty());cancelButton.disableProperty().bind(Bindings.not(task.runningProperty()));Callback<T, Node> factory = getSkinnable().getGraphicFactory();if (factory != null) {Node graphic = factory.call(task);if (graphic != null) {BorderPane.setAlignment(graphic, Pos.CENTER);BorderPane.setMargin(graphic, new Insets(0, 4, 0, 0));borderPane.setLeft(graphic);}} else {/** Really needed. The application might have used a graphic* factory before and then disabled it. In this case the border* pane might still have an old graphic in the left position.*/borderPane.setLeft(null);}setGraphic(borderPane);}}}}

CSS

下面的样式表确保我们为任务标题使用粗体字体,更小/更细的进度条(无圆角),并在底部位置列出具有淡入/淡出分隔线的单元格。

.task-progress-view {-fx-background-color: white;}.task-progress-view > * > .label {-fx-text-fill: gray;-fx-font-size: 18.0;-fx-alignment: center;-fx-padding: 10.0 0.0 5.0 0.0;}.task-progress-view > * > .list-view {-fx-border-color: transparent;-fx-background-color: transparent;}.task-title {-fx-font-weight: bold;}.task-progress-bar .bar {-fx-padding: 6px;-fx-background-radius: 0;-fx-border-radius: 0;}.task-progress-bar .track {-fx-background-radius: 0;}.task-message {}.task-list-cell {-fx-background-color: transparent;-fx-padding: 4 10 8 10;-fx-border-color: transparent transparent linear-gradient(from 0.0% 0.0% to 100.0% 100.0%, transparent, rgba(0.0,0.0,0.0,0.2), transparent) transparent;}.task-list-cell-empty {-fx-background-color: transparent;-fx-border-color: transparent;}.task-cancel-button {-fx-base: red;-fx-font-size: .75em;-fx-font-weight: bold;-fx-padding: 4px;-fx-border-radius: 0;-fx-background-radius: 0;}

翻译自: //10/new-custom-control-taskprogressview.html

用户控件 自定义控件

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。