用户控件 自定义控件

我已经编写了一个新的自定义控件,并将其提交到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. Web.config中注册用户控件和自定义控件

    在ASP.NET 的早先版本里,我们通过在页面的顶部添加 <%@ Register %> 指令来引入和使用自定义服务器控件和用户控件时,象这样: <%@ Register TagPr ...

  2. C#自定义控件VS用户控件

    C#自定义控件VS用户控件 1.C#中自定义控件VS用户控件大比拼 2.为自定义控件(或类)的方法属性添加注解 2.1.Description:在属性窗口中添加属性及属性说明 2.2.Browsabl ...

  3. 学习笔记---母板页、用户控件、第三方控件及视图状态管理

    一.母版页 在制作页面的过程中, 多个页面往往具有相同的页面Header和页面Footer, 多个页面只是在中间部分有变化. 那么我们完全可以避免在每个页面中都写一遍页头和页尾的代码, 这种技术就是母 ...

  4. 第6章 自定义控件和用户控件

    部署 创建 内容和布局 设计期行为 性能 ASP.NET 为创建自己的控件提供了两个模型--用户控件模型和自定义控件模型.这两个模型适合不同的情况.一般而言用户控件适合创建内部,应用程序特定的控件和相 ...

  5. Asp.net 用户控件和自定义控件注册

    在ASPX页中注册用户控件的方法 <%@ Register Src="ListPicker.ascx" TagName="ListPicker"  Tag ...

  6. java 用户控件_C#自定义控件VS用户控件

    C#中自定义控件VS用户控件大比拼 1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Co ...

  7. WPF 用户控件和 WPF自定义控件区别

    WPF 用户控件 将多个现有的控件组合成一个可重用的"组". 由一个XAML文件和一个后台代码文件. 不能使用样式和模板. 继承自UserControl类. WPF自定义控件(扩展 ...

  8. 用户控件和自定义控件

    关 键 词 Server Control 服务器控件 User Control 用户控件,ASP.NET服务器控件的一种(一般后缀名为.ASCX文件) Custom Control 自定义控件,ASP ...

  9. Asp.net 2.0 自定义控件开发专题讲解[为用户控件增加DataSource属性, 能够自动识别不同数据源](示例代码下载)...

    (一).  概要 开发<数据绑定用户控件>, 要实现一个DataSource属性, 并且能够自动识别不同的数据源, 如: ArrayList, DataTable, DataSet, XM ...

最新文章

  1. 视觉SLAM如何基于深度学习闭环检测?
  2. 卸载angular版本
  3. 卷积神经网络Convolution Neural Network (CNN) 原理与实现
  4. wxWidgets:wxMouseCaptureLostEvent类用法
  5. 【2012百度之星/资格赛】J:百度的新大厦
  6. restful web_RESTful Web服务可发现性,第4部分
  7. 使用Maven原型高效创建Eclipse模块
  8. Python使用matplotlib填充图形指定区域
  9. 手机应用软件测试经验总结
  10. Java实现微信公众号自动回复
  11. ModelAndView 详解
  12. android 强制关闭键盘,Android关闭输入软键盘无效的问题
  13. 牛客网数据库SQL实战14—— 从titles表获取按照title进行分组,注意对于重复的emp_no进行忽略。
  14. 告诉我常用的L波段雷达有哪些
  15. Android中从视频中提取音频
  16. 实体服务器搭建vps系统,vps系统和云服务器搭建
  17. 剑网3哪5区人哪个服务器最多,剑网3哪个区服人最多?只有选对了游戏区才能体会到多人的乐趣...
  18. 用word制作电子公章
  19. HGame 2023 Week4 部分Writeup
  20. Cadence Allegro如何生成PCB截面图

热门文章

  1. 欢乐纪中A组赛【2019.8.9】
  2. ssl1202-滑雪【记忆化搜索法】
  3. 线性代数(矩阵、高斯、线性基……)
  4. codeforces1484 B. Restore Modulo(数学)
  5. 分布式之redis复习精讲
  6. 从开发者角度谈Mysql主键
  7. jquery动画与事件案例
  8. js引擎执行代码的基本流程
  9. 交换数组中的两个元素
  10. idea 写html js 热部署