上次使用JavaFX开发了一个视频转码工具,当用户点击“启动”按钮开始转码的时候,会禁用启动按钮,防止多次启动转码。

这种处理方式对用户来说可能并是很友好,其实可以在启动转码的时弹出一个loading界面,告诉用户正在进行视频转码。

~ JavaFX桌面应用开发系列文章传送门 ~

  1. JavaFX桌面应用开发-HelloWorld
  2. JavaFX布局神器-SceneBuilder
  3. JavaFX让UI更美观-CSS样式
  4. JavaFX桌面应用-为什么应用老是“未响应”
  5. JavaFX桌面应用-MVC模式开发,“真香”
  6. JavaFX桌面应用-loading界面 (本文)
  7. JavaFX桌面应用-表格用法
  8. JavaFX桌面应用-视频转码工具

重新改造一下之前的转码程序,使用loading界面提示用户视频正在转码,如下图:

针对这种通用的loading界面,可以使用JavaFX的stage开发一个通用的组件。

这里需要注意的是:

  1. loading界面没有边框的
  2. loading界面背景是透明的
  3. loading附着于主Stage

针对以上三点,可以分别设置loading stage的样式及模式:

// 设置stage无任何装饰
stage.initStyle(StageStyle.UNDECORATED);
// 设置stage背景透明
stage.initStyle(StageStyle.TRANSPARENT);
// 设置stage的模式
stage.initModality(Modality.APPLICATION_MODAL);

loading界面由两部分组成,分别是loading动画(ProgressIndicator)和提示信息(Label),如下图:

所以可以采用VBox来布局(这里直接采用Java代码布局,不采用fxml):

// message
Label adLbl = new Label(ad);
adLbl.setTextFill(Color.BLUE); // progress
ProgressIndicator indicator = new ProgressIndicator();
indicator.setProgress(-1);
indicator.progressProperty().bind(work.progressProperty()); // pack
VBox vBox = new VBox();
vBox.setSpacing(10);
vBox.setBackground(Background.EMPTY);
vBox.getChildren().addAll(indicator, adLbl);

对于loading界面的宽度可以通过信息来计算,而loading界面的位置则设置为主stage的中心。

stage.setWidth(ad.length() * 8 + 10);
stage.setHeight(100); // show center of parent
double x = parent.getX() + (parent.getWidth() - stage.getWidth()) / 2;
double y = parent.getY() + (parent.getHeight() - stage.getHeight()) / 2;
stage.setX(x);
stage.setY(y);

完整的loading界面代码如下:

/**
* @author itqn
*/
public class ProgressStage { private Stage stage;
private Task<?> work; private ProgressStage() {
} /**
* 创建
*
* @param parent
* @param work
* @param ad
* @return
*/
public static ProgressStage of(Stage parent, Task<?> work, String ad) {
ProgressStage ps = new ProgressStage();
ps.work = Objects.requireNonNull(work);
ps.initUI(parent, ad);
return ps;
} /**
* 显示
*/
public void show() {
new Thread(work).start();
stage.show();
} private void initUI(Stage parent, String ad) {
stage = new Stage();
stage.initOwner(parent);
// style
stage.initStyle(StageStyle.UNDECORATED);
stage.initStyle(StageStyle.TRANSPARENT);
stage.initModality(Modality.APPLICATION_MODAL); // message
Label adLbl = new Label(ad);
adLbl.setTextFill(Color.BLUE); // progress
ProgressIndicator indicator = new ProgressIndicator();
indicator.setProgress(-1);
indicator.progressProperty().bind(work.progressProperty()); // pack
VBox vBox = new VBox();
vBox.setSpacing(10);
vBox.setBackground(Background.EMPTY);
vBox.getChildren().addAll(indicator, adLbl); // scene
Scene scene = new Scene(vBox);
scene.setFill(null);
stage.setScene(scene);
stage.setWidth(ad.length() * 8 + 10);
stage.setHeight(100); // show center of parent
double x = parent.getX() + (parent.getWidth() - stage.getWidth()) / 2;
double y = parent.getY() + (parent.getHeight() - stage.getHeight()) / 2;
stage.setX(x);
stage.setY(y); // close if work finish
work.setOnSucceeded(e -> stage.close());
}
}

loading动画跟Task任务的进度绑定,当Task完成的时候,关闭loading界面。

这样loading界面组件就完成了。

接下来,改造之前的视频转码工具代码,将视频转码的代码改为继承Task,而不是Thread,这里Task不需要返回任何信息,所以泛型采用Void即可,然后重写call方法,将耗时的业务代码放在call中执行。

public class VideoConvertWork extends Task<Void> {

    private String ffmpeg;
private List<TableColumnModel> modelList;
private Consumer<String> consumer; public VideoConvertWork(String ffmpeg, List<TableColumnModel> modelList, Consumer<String> consumer) {
this.ffmpeg = ffmpeg;
this.modelList = modelList;
this.consumer = consumer;
} @Override
protected Void call() throws Exception {
while (true) {
Optional<TableColumnModel> opt = modelList.stream().filter(i -> !VideoConvertHolder.has(i.getId())).findFirst();
if (opt.isPresent()) {
try {
VideoConvertHolder.add(opt.get().getId());
convert(opt.get());
} catch (Exception e) {
e.printStackTrace();
Platform.runLater(() -> opt.get().setMessage(e.getMessage()));
}
} else {
break;
}
}
return null;
}
}

调整“启动”按钮的事件处理:

public void executeConvertHandler(ActionEvent actionEvent) {
if (model.getTableList().isEmpty()) {
new Alert(Alert.AlertType.INFORMATION, "没有转码任务,请选择视频进行转码。").show();
return;
}
if (ffmpeg == null) {
new Alert(Alert.AlertType.ERROR, "FFmpeg.exe Not Found.").show();
return;
}
// ((Button) actionEvent.getSource()).setDisable(true);
// new VideoConvertExecutor(ffmpeg, model.getTableList(), s -> Platform.runLater(() -> model.setInfo(s))).start();
ProgressStage.of(
App.stage,
new VideoConvertWork(ffmpeg, model.getTableList(), s -> Platform.runLater(() -> model.setInfo(s))),
"视频转码中..."
).show();
}

loading界面作为通用的组件可以在任何耗时的业务场景下使用,只要将耗时的业务放在Task的call方法中执行即可。

=========================================================

关注 公众号 “HiIT青年” 发送 “视频转码工具” 获取转码工具安装包。



关注公众号,阅读更多文章。

JavaFX桌面应用-loading界面的更多相关文章

  1. JavaFX桌面应用-MVC模式开发,“真香”

    使用mvc模块开发JavaFX桌面应用在JavaFX系列文章第一篇 JavaFX桌面应用开发-HelloWorld 已经提到过,这里单独整理使用mvc模式开发开发的流程. ~ JavaFX桌面应用开发 ...

  2. JavaFX桌面应用开发系列文章

    ~ JavaFX桌面应用开发系列文章汇总篇 ~ JavaFX桌面应用开发-HelloWorld JavaFX布局神器-SceneBuilder JavaFX让UI更美观-CSS样式 JavaFX桌面应 ...

  3. JavaFX桌面应用-视频转码工具(支持爱奇艺qsv转mp4)

    最近由于需要将在爱奇艺下载的视频(qsv)转化了mp4,用JavaFX开发一个视频转码工具,算是JavaFX开发的第一个应用吧. 支持qsv转码mp4,理论上支持各种格式,仅测试了flv,qsv格式. ...

  4. JavaFX桌面应用-SpringBoot + JavaFX

    SpringBoot对于Java程序员来说可以是一个福音,它让程序员在开发的时候,大大简化了各种spring的xml配置. 那么在JavaFX项目使用SpringBoot会是怎么样的体验呢? 这次使用 ...

  5. JavaFX桌面应用-构建程序框架

    看到JavaFX应用很多人都会说JavaFX应用太丑了,确实JavaFX比起Qt.MFC.Delphi这些界面确实丑了一点,但也不是没有可以美化的空间. 跟网页一样,单纯HTML不加任何CSS的时候也 ...

  6. JavaFX桌面应用开发-HelloWorld

    JavaFX是一个强大的图形和多媒体处理工具包集合,它允许开发者来设计.创建.测试.调试和部署富客户端程序,并且和Java一样跨平台. JavaFX比Swing好用很多,它允许开发使用FXML来设计和 ...

  7. JavaFX桌面应用-为什么应用老是“未响应”

    日常使用软件的过程中,偶尔会遇到软件突然卡住,再点击几次就变成"未响应"的情况. 在JavaFX应用中同样也会出现这种情况,在开发过程中应该尽量避免这种情况的出现. >> ...

  8. SILVERLIGHT 应急卫生模拟演练项目之loading界面实现

    第一次在博客园写文章 俺是菜鸟 有不足之处还请大佬们多多指教 第一次也不知道该写啥 俺就拿自己最近做的一个项目 来细说吧 俺们公司是做医疗卫生方面的  其中有一块涉及到应急卫生模拟演练方面 这块分到我 ...

  9. 青瓷引擎使用心得——修改引擎的loading界面

    一. 修改引擎的Loading界面之使用进度条显示1. 双击打开引擎包中的lib/qc-loading-debug.js,如下图所示: 2. 只需要修改qici.init函数即可改变loading界面 ...

随机推荐

  1. 一周一个中间件-ES搜索引擎

    ---toc: truetitle: 一周一个中间件-ES搜索引擎date: 2019-09-19 18:43:36tags: - 中间件 - 搜索引擎--- ## 前言 > 在众多搜索引擎中, ...

  2. phpcms视频模块实现列表页打开内容页直接播放视频

    摘自phpcms论坛 原链接地址:http://bbs.phpcms.cn/thread-557691-1-1.html 之前下载研究过“化蝶自在飞”开发的视频模型,发现功能不错,但唯一的缺憾是,我想 ...

  3. 哇咔咔干货来啦:PowerJob 原理剖析之 Akka Toolkit

    本文适合有 Java 基础知识的人群 作者:HelloGitHub-Salieri HelloGitHub 推出的<讲解开源项目>系列. Akka is a toolkit for bui ...

  4. numpy第三方库

    # 导入numpy 并赋予别名 np import numpy as np # 创建数组的常用的几种方式(列表,元组,range,arange,linspace(创建的是等差数组),zeros(全为 ...

  5. JS中Math.random()的使用和扩展

    Math.random()方法返回大于等于 0 小于 1 的一个随机数.对于某些站点来说,这个方法非常实用,因为可以利用它来随机显示一些名人名言和新闻事件. 在连续整数中取得一个随机数 值 = Mat ...

  6. AT5200 [AGC038C] LCMs 莫比乌斯反演

    LINK:LCMs 随便找了道题练习了一下莫比乌斯反演 式子有两个地方化简错误 导致查了1h的错. 讲一下大致思路 容易发现直接做事\(n^2logn\)的. 观察得到数字集合大小为1e6. 可以设\ ...

  7. luogu P3920 [WC2014]紫荆花之恋

    LINK:紫荆花之恋 每次动态加入一个节点 统计 有多少个节点和当前节点的距离小于他们的权值和. 显然我们不能n^2暴力. 考虑一个简化版的问题 树已经给出 每次求某个节点和其他节点的贡献. 不难想到 ...

  8. LVS-DR实现mysql负载均衡集群

    lvs-dr实现mysql负载均衡集群 环境说明: 服务器的操作系统均为centos7,vip和rip在同一网段,使用lvs-dr模型来实现mysql集群服务 所有服务器均已配置好处VIP外的静态IP ...

  9. 数据量大了一定要分表,分库分表组件Sharding-JDBC入门与项目实战

    最近项目中不少表的数据量越来越大,并且导致了一些数据库的性能问题.因此想借助一些分库分表的中间件,实现自动化分库分表实现.调研下来,发现Sharding-JDBC目前成熟度最高并且应用最广的Java分 ...

  10. MySQL-安装配置篇

    一.MySQL二进制安装包安装 1.环境初始化 1)创建目录mkdir /app/database --安装路径 mkdir /data/3306 --存放数据路径 mkdir /binlog/330 ...