新的自定义控件:TaskProgressView

我已经编写了一个新的自定义控件,并将其提交到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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js笔记(三)ES5、ES5新增的数组的方法、字符串的方法、字符编码、对象的序列化和反序列化、bind

数组方法、字符串方法总结 大目录小目录一、ES5严格模式1. 严格模式&#xff1b;2. 严格模式的行为变更&#xff1b;二、ES5新增的数组的方法1. 判断是否为数组&#xff1a;Array.isArray()&#xff1b;2. 判断数组中是否存在某个值&#xff1a;indexOf(data, start)、lastInd…

SVG入门

1、简介 使用xml描述的矢量文件。 2、兼容性 https://caniuse.com/#searchsvg 3、使用方式 &#xff08;1&#xff09;浏览器直接打开 &#xff08;2&#xff09;html中使用img引用 <p><img src"simple.svg" width"50" height"50"…

js 值和引用

1、概述 简单值&#xff08;基本类型&#xff09;通过值复制的方式来赋值/传递。 复合值&#xff08;对象&#xff09;通过引用复制的方式来赋值/传递。 <!DOCTYPE html><html lang"zh"><head><meta charset"UTF-8" /><title…

js笔记(六)事件、正则

数组方法、字符串方法总结 大标题小节一、事件1.1 事件&#xff1b;1.2 事件对象&#xff1b;1.3 键盘事件的keyCode&#xff1b;1.4 关于鼠标的尺寸&#xff1b;1.5 事件冒泡&#xff1b;1.6 事件的默认行为&#xff1b;1.7 事件监听&#xff1b;1.8 事件委托&#xff08;事件…

神州泰岳2050万元收买并增资奇点国际

网易科技讯 3月7日消息&#xff0c;神州泰岳来日诰日颁布发表关照公告&#xff0c;将经由股权让渡体例共付出1450万元股权让渡款获得奇点国际100%股权&#xff0c;同时神州泰岳与邵起明分别出资600万元、200万元对奇点国际举行增资。本次增资后&#xff0c;奇点国际注册资金增进…

拯救你丢失的精度——BigInteger和BigDecimal类(入门)

第三阶段 JAVA常见对象的学习 BigInteger和BigDecimal类 BigInteger类 (一) 构造方法&#xff1a; //针对超过整数范围的运算(整数最大值&#xff1a;2147483647) BigInteger(String val) (二) 常用方法&#xff1a; //加 public BigInteger add(BigInteger val) //减 public…

vue笔记(四)注册组件,路由,vuex

官网 一、项目中的组件注册 二、路由 三、vuex 一、项目中的组件注册 1. 全局 import Loading from /components/loading;//封装的loading组件 Vue.component(Loading,Loading);2. 局部 <loading/>important loading from ./components/loadingcomponents:{loading}二…

#102030:在30天内运行20 10K,庆祝Java 20年

1995年5月23日是技术史上的重要时刻。 业界似乎并没有意识到当天发布的语言会在未来几年内完全改变技术的格局。 Java将在今年的同一天庆祝20岁生日。 Java 20年&#xff0c;哇&#xff01; 回顾20年前的存储器时代&#xff0c;思考一下Java的发明时间/方式。 万维网专用于精…

vue笔记(一)基本使用、数据检测

vue 官网 Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。 一、基本使用 二、数据检测 一、Vue的思想 MVC【参考 nd的博客园】&#xff1a; 名称描述M&#xff08;…

js笔记(二)数组、对象、this

大标题小节一、数组1. 数组的创建、赋值、分类&#xff1b;2. 数组的简单操作&#xff08;根据索引增、查、改&#xff09;&#xff1b;3. 声明式和构造函数创建的数组的区别&#xff1b;4.数组的方法&#xff1a;push()、unshift()、splice()、pop()、shift()、slice()、sort(…

js笔记(四)内置对象Math和Date()、浏览器对象模型BOM

大标题小标题备注一、内置对象Math、Date()1. Math 数学对象;2. Date() 日期对象;常用的数学对象&#xff1a;Math.PI、abs(n)、round(n)、random()、floor(n)、ceil(n)、pow(x,y)、sqrt(n)、min(3,4,5,6)、max()、sin(弧度)、cos()、tan()&#xff1b;获取日期&#xff1a;get…

ListView展示SIM信息

首先看一下程序运行后的图片&#xff1a; 在开始写代码之前&#xff0c;看展示下程序的结构&#xff1a; 下面开始代码, 第一步&#xff0c;主程序代码&#xff1a; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundl…

js笔记(五)文档对象模型DOM

大标题小节一、DOM选择器1. id 选择器&#xff1a;getElementById("id名")&#xff1b;2. class 选择器&#xff1a;getElementByClassName("class名")&#xff1b;3. 标签选择器&#xff1a;getElementsByTagName("标签名")&#xff1b;4. name…

Flot画实时曲线

源代码&#xff1a; <head> <meta http-equiv"Content-Type" content"text/html; charsetutf-8" /> <title>深海的小鱼编制-PLOT</title> <script language"javascript" type"text/javascript" src"…

RHQ指标的WildFly子系统

对于RHQ-Metrics&#xff0c;我已经开始为WildFly 8编写一个子系统&#xff0c;该子系统能够在WildFly内收集指标&#xff0c;然后以固定的时间间隔&#xff08;当前为每分钟&#xff09;将其发送到RHQ-Metrics服务器。 下一张图是该发件人连续运行1.5天时结果的可视化效果的G…

Linux下实现客户端和服务器端的通信

首先&#xff0c;可以将代码复制下来放到U盘里&#xff0c;然后挂载到Linux上 挂载步骤 找到设备->USB->你U盘的名字 挂载成功 访问U盘把代码拷贝到home文件夹下&#xff0c;就可以直接进行编译。 client.c #include <stdio.h> #include <unistd.h>#include…

js笔记(八)ES6

大标题补充描述一、 ES6 中新增的声明方式&#xff1a;let、constvar、let、const之间的区别二、 ES6 字符串扩展1. 子串的识别&#xff1a;includes()、startsWith()、endsWith()&#xff1b;2. 重复字符串&#xff1a;repeat()&#xff1b;3. 字符串补全&#xff1a;padStart…

webpack css打包为一个css

1、安装 npm install extract-text-webpack-plugin --save-dev 2、项目目录&#xff1a; index文件夹下的index.css&#xff1a; body{background-color: #ccc;}.flex-div{display: flex;} index文件夹下的index2.css&#xff1a; p{text-indent: 2em;} index文件夹下的index-l…

javascript深入理解js闭包

闭包&#xff08;closure&#xff09;是Javascript语言的一个难点&#xff0c;也是它的特色&#xff0c;很多高级应用都要依靠闭包实现。 一、变量的作用域 要理解闭包&#xff0c;首先必须理解Javascript特殊的变量作用域。 变量的作用域无非就是两种&#xff1a;全局变量和局…

Codeforces Round #568 (Div. 2) G2. Playlist for Polycarp (hard version)

因为不会打公式&#xff0c;随意就先将就一下&#xff1f; #include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<vector> using namespace std; typedef long long LL; const int N55; const int MOD1e97; int…