用户控件 自定义控件_新的自定义控件: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/339390.shtml

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

相关文章

C/C++码农到工程师进化之路

今晚课题长按图片【识别图中的二维码】

java菜鸟到cto 图_从菜鸟到入门,掌握 Log4j

1 简介Log4j(log for java)是Apache的一个开源项目&#xff0c;通过使用Log4j&#xff0c;我们可以控制日志信息输送的目的地是控制台、文件、GUI组件&#xff0c;甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等&#xff1b;我们也可以控制每一条日志的输出格式&a…

Java中的复合设计模式

当我们必须使用对象的树状分层结构时&#xff0c;复合设计模式非常有用。 它使我们能够统一对待单个对象和对象的组成。 它属于结构设计模式的范畴&#xff0c;因为它将对象组合成树形结构以表示部分整个层次结构。 UML表示形式&#xff1a; 复合模式的UML表示形式如下&#…

腾讯官方游戏《陆战之王 3D坦克大战》

今晚课题长按图片【识别图中的二维码】

hazelcast入门教程_Hazelcast入门指南第4部分

hazelcast入门教程这是我的Hazelcast系列的第四部分。 如果一个人没有看到其他三个人&#xff0c;我建议一个人去看第1 部分 &#xff0c; 第2 部分和第3部分 。 记录中 日志记录是任何应用程序的重要功能&#xff0c;我的示例也是如此。 System.out.println可以用作告诉用户控…

《地下城与勇士歼灭贝内尔》回合格斗

今晚课题长按图片【识别图中的二维码】

java继承执行子类输出顺序_JAVA继承顺序

当使用继承这个特性时&#xff0c;程序是如何执行的&#xff1b;继承的初始化顺序1.初始化父类再初始子类2.先执行初始化对象中属性&#xff0c;再执行构造方法中的初始化当使用继承这个特性时&#xff0c;程序是如何执行的呢&#xff0c;也就是说我们需要关注继承的初始化顺序…

空字符串字符串不为空_当字符串为空但不为空时

空字符串字符串不为空介绍 我团队中的一名初级程序员遇到了一个有趣的错误。 我已经不止一次看到它的症状。 这篇文章是寻找什么以及如何在将来防止它。 我还将探讨该问题的不同解决方案。 病征 有问题的代码看起来做得不错。&#xff1a; if(trouble ! null && !tro…

网络通信协议-TCP/IP模型实战

今晚课题长按图片【识别图中的二维码】

java家具网站需求分析_基于jsp的家具销售-JavaEE实现家具销售 - java项目源码

基于jspservletpojomysql实现一个javaee/javaweb的家具销售, 该项目可用各类java课程设计大作业中, 家具销售的系统架构分为前后台两部分, 最终实现在线上进行家具销售各项功能,实现了诸如用户管理, 登录注册, 权限管理等功能, 并实现对各类家具销售相关的实体进行管理。该家具…

hazelcast入门教程_Hazelcast入门指南第2部分

hazelcast入门教程本文是我开始使用Hazelcast &#xff08;分布式内存数据库&#xff09;的系列文章的继续。 如果尚未阅读第一篇文章&#xff0c;请单击此处 。 分布式馆藏 Hazelcast具有许多可用于存储数据的分布式集合。 以下是它们的列表&#xff1a; 清单 我设置 队列…

C/C++深入剖析指针机制与内存动态管理

今晚课题【长按识别图中二维码】

jedis watch Java_jedis操作redis的几种常见方式总结

Redis是一个著名的key-value存储系统&#xff0c;也是nosql中的最常见的一种&#xff0c;这篇文章主要给大家总结了关于在java中jedis操作redis的几种常见方式&#xff0c;文中给出了详细的示例代码供大家参考学习&#xff0c;需要的朋友们下面来一起看看吧。前言Redis是一个著…

C/C++打造Windows岁月留声机

今晚课题【长按识别图中二维码】

hazelcast入门教程_Hazelcast入门指南第1部分

hazelcast入门教程介绍 我将在Hazelcast上做一个系列。 我从Twitter了解了该产品。 他们决定跟随我&#xff0c;经过对他们所做工作的研究后&#xff0c;我决定跟随他们。 我在推特上说&#xff0c;Hazelcast将是分布式密码破解者的重要Struts。 这引起了一些兴趣&#xff0c;我…

java演出厅选票_高仿猫眼电影选座(选票)模块-b

上图看效果先&#xff1a;1)画座位图其实不是很难一般数据都会给坐标&#xff0c;将坐标对应座位画出来就可以了&#xff0c;主要是开场动画要设置默认大小&#xff0c;还有座位图的数量也不是固定的&#xff0c;所以在初始化座位图的时侯就默认算出了整个座位图的大小-(instan…

input发送a.jax_Java EE 7 / JAX-RS 2.0 – REST上的CORS

input发送a.jaxJava EE REST应用程序在开箱即用的开发机器上通常可以很好地运行&#xff0c;在该机器上&#xff0c;所有服务器端资源和客户端UI都指向“ localhost”或127.0.0.1。 但是&#xff0c;当涉及跨域部署时&#xff08;当REST客户端不再与托管REST API的服务器位于同…

用C/C++开发《Photoshop》图像处理软件

今晚课题【长按识别图中二维码】

javaone_代理的JavaOne 2014观察

javaone我今年无法参加JavaOne&#xff0c;但很高兴看到一些在线资源涵盖了JavaOne 2014的活动。在本文中&#xff0c;我总结了JavaOne 2014的一些观察结果&#xff0c;并提供了指向提供这些观察结果的参考的链接。提供有关这些观察的更多背景细节。 列出的观察结果没有特别的顺…

java怎么兼容switch_java – Switch语句给出了不兼容类型错误

我正在尝试编译,我收到此错误&#xff1a;enigma/Rotor.java:30: incompatible types found : java.lang.String required: int switch(name){1 error为什么我收到此错误&#xff1f;我如何解决它&#xff1f;它在包中,我似乎无法弄明白.这是代码&#xff1a;String label;Roto…