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

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

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

控制

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

package org.controlsfx.control;import impl.org.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 impl.org.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;
}

翻译自: https://www.javacodegeeks.com/2014/10/new-custom-control-taskprogressview.html

新的自定义控件:TaskProgressView相关推荐

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

    用户控件 自定义控件 我已经编写了一个新的自定义控件,并将其提交到ControlsFX项目. 这是一个高度专业的控件,用于显示后台任务,其当前状态和进度的列表. 这实际上是我为ControlsFX编写 ...

  2. 【问题解决】无法创建新的堆栈防护页面

    [问题发现] 项目中需要几个自定义的控件,菜鸟D定义了一个接口,打算使用多态来统一调用.在完成两个自定义控件后,项目都能正常运行.但是在第三个控件使用的时候就出了问题:将控件拖到界面上以后,不能拖动改 ...

  3. Dorado7功能及技术特点

    简介 Dorado PresentationMiddleware(即Dorado展现中间件,以下简称Dorado)致力于辅助Web应用中表现层的开发过程.Dorado主要可以为您带来如下两方面的使用价 ...

  4. SAP UI5 应用开发教程之三十二 - 如何创建一个自定义 SAP UI5 控件试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  5. android--------Android Studio常见问题以及解决方式

    gradle build的时候出现的问题: Error:Execution failed for task ':app:packageDebug'. Duplicate files copied in ...

  6. ASP.NET 系列_07_编程指南(三)

    ASP.NET 数据源 数据源 github:  https://github.com/ixixii/ASP.NET_03_WebForms 一个 data sourse 控件与数据绑定的控件相互作用 ...

  7. C#winform使用双缓冲解决刷新闪屏的问题

    最近在做一个winform项目,其中一个panel内的全部控件都是动态添加到页面中的,并且这些动态的控件需要做添加.删除等的功能,考虑到界面的美观,在每添加或删除时都要重新加载所有动态控件,但是,有一 ...

  8. Android Studio经验积累之常见问题以及解决方式

    原文出处--Android Studio经验积累 1.获取SHA1: Android Studio中获取sha1证书指纹数据的方法 2.注释模板:android studio中如何设置注释模板 3.A ...

  9. C++学习笔记(第一、二阶段汇总)

    文章目录 cmake 命名空间 匿名命名空间 C与C++混合编程 引用 共用体 inline内联函数 关于多次定义 class类初步了解 inline函数在c++中唯一一个多出来的特性 这个特性的目的 ...

最新文章

  1. 关于Docker目录挂载的总结(转)
  2. 频谱中负频率的物理意义(二)
  3. Spring MVC 中使用 Google kaptcha 验证码
  4. ELK系统之logstash问题:retrying failed action with response code: 429
  5. JAVA 之反射(基础概念) 几个主要常用的重要的方法
  6. 如何更改Visual Studio 2008中类文件引用的默认名称空间?
  7. Matlab看跌期权二叉树,欧式期权二叉树MATLAB程序
  8. 【Linux】生产者消费者编程实现-线程池+信号量
  9. 平面/UI设计师社区交流网站集设|给你的作品多一个展示机会
  10. 下载的代码找不到rt.jar中的类
  11. 用深度学习来解析梦境中出现的物体
  12. day4-软件目录开发规范
  13. 9款非常适合Sketchup的渲染插件以及优点介绍
  14. U盘病毒 System Volume Information.exe删不掉
  15. Mac安装Royal TSX
  16. 理科生学酒店管理好一点还是计算机,酒店管理专业是文科还是理科
  17. 我的世界服务器清垃圾文件,我的世界:五大处理“垃圾”方法,我选择懒人方法,你会如何选?...
  18. 第五章 SQL定义表(一)
  19. jQuery实现BBS发贴操作
  20. TypeScript-多态篇

热门文章

  1. 西瓜显示服务器错误,西瓜云服务器
  2. 项目的包结构 mybatis三剑客
  3. 直方图 帕累托图_如何发现现象背后的关键因素?帕累托图,质量管理的利器...
  4. python找不到指定的文件夹里_Python环球网在Unix中的指定文件路径中找不到*.txt
  5. eclipse如何设置js源文件编码
  6. SQL分组取每组前一(或几)条记录(排名)
  7. wiremock 使用_使用WireMock进行更好的集成测试
  8. webcrypto库下载_使用WebCrypto API的电子签名
  9. java中的jpa_在JPA中处理Java的LocalDateTime
  10. 乡村野生草药_官方野生蝇群流口水分数