使用javafx更新UI
JavaFx如果在子线程中更新UI,不论是task还是runable都会报错
java.lang.IllegalStateException: Not on FX application thread; currentThread =
这种情况可以使用下面的方法
1,Platform.runLater()
这个办法在当前线程不是javafx的线程中,比如runnable,thread这些的,直接调用即可,runLater()不是线程阻塞型的,在javafx的主线程完全清空或者说空闲的时候,它才会执行,
1
2
3
4
5
6
7
|
Platform.runLater( new Runnable() { @Override public void run() { //更新JavaFX的主线程的代码放在此处 p.cancelProgressBar(); } }); |
但是如果必须先执行这段代码怎么办呢,也有方法
1,future是个工作线程
他允许阻塞当前线程,执行线程中的代码,在拿到返回值后,才会顺序执行
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 定义一个FutureTask,然后 Plateform.runLater() 这个futuretask final FutureTask<String> query = new FutureTask<String>( new Callable<String>() { @Override public String call() throws Exception { // 新建一个窗口(方法中将创建stage) VcodeController vc = new VcodeController(); return vc.show(url4vcode); } }); Platform.runLater(query); // 重点 String vcode = query.get(); // 这样就能获取返回值 System.out.println(vcode); |
2,利用 CountDownLatch,直接阻塞当前的主线程,执行相关代码业务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/** * Runs the specified {@link Runnable} on the * JavaFX application thread and waits for completion. * * @param action the {@link Runnable} to run * @throws NullPointerException if {@code action} is {@code null} */ public static void runAndWait(Runnable action) { if (action == null ) throw new NullPointerException( "action" ); // run synchronously on JavaFX thread if (Platform.isFxApplicationThread()) { action.run(); return ; } // queue on JavaFX thread and wait for completion final CountDownLatch doneLatch = new CountDownLatch( 1 ); Platform.runLater(() -> { try { action.run(); } finally { doneLatch.countDown(); } }); try { doneLatch.await(); } catch (InterruptedException e) { // ignore exception } } |
3.使用task线程的返回值
task是javafx实现的ui线程,他实现了futureTask和worlker线程,所以它既可以当普通线程来使用,也可以重写返回值方法,实现ui界面的刷新
不过要说明的是,task的call方法,仍然是一个普通线程的方法,如果要实现在task中刷新ui界面,要在
scheduled(),succeeded(),running()任意一个方法中执行,就可以了,这样就实现了再task的线程中,刷新界面的功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package com.yz.readismqtest1; import javafx.concurrent.Task; public class deda { public static void main(String[] args) { Task task = new Task() { @Override protected Object call() throws Exception { //执行普通方法 return null ; } @Override protected void scheduled() { //更新JavaFX的主线程的代码放在此处 super .scheduled(); } @Override protected void succeeded() { //更新JavaFX的主线程的代码放在此处 super .succeeded(); } @Override protected void running() { //更新JavaFX的主线程的代码放在此处 super .running(); } }; } } |
JavaFX的并发编程与UI更新
JavaFX并发编程与UI更新
项目需求
根据项目需要,进行设备的并发测试,同时需要在界面上实时展示测试的结果
涉及到的技术
1、使用Observer的方式实现多个对象之间的通信(观察者模式)
2、因为UI只有一个,需要在较短时间内接收并显示大量的数据,所以使用了javafx.concurrent
3、线程池pool,减少对象的资源占用
上述技术的使用参考了大量的网络资源和书籍内容,再次不进行一一列举,感谢各位作者。
核心代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// 1、从线程池中获取对象 ObjectPoolDrawUIService objPool = ObjectPoolDrawUIService.getInstance(); DrawUIService obj = (DrawUIService)objPool.getObject(); // 2、对象的初始化 produceCaseResult是需要更新的数据内容 ,i是行号信息,放在Object[]中进行传递 obj.init( new Object[]{produceCaseResult,i}, new EventHandler<WorkerStateEvent>() { @Override public void handle(WorkerStateEvent t) { Object[] objArray = (Object[])t.getSource().getValue(); testDetailList.set(( int ) objArray[ 1 ], (ProduceCaseResult)objArray[ 0 ]); // 4、因为是在线程中执行,所以 returnObject代码不能跟在obj.restart后面,会导致被很快的restart objPool.returnObject(obj); } }); // 3、执行 obj.restart(); // 因为是从pool中获取,可能已经执行完毕,所以restart 以上代码中需要特别注意,代码 4 的位置,以下代码为javafx.concurrent的核心代码 public class DrawUIService extends Service<Object[]>{ Object[] showData = { null , null }; public void init(Object[] showData, EventHandler<WorkerStateEvent> eventHandler) { this .showData = showData; setOnSucceeded(eventHandler); } @Override protected Task<Object[]> createTask() { return new Task<Object[]>() { @Override protected Object[] call() throws Exception { return showData; } }; } } |
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/qq_41886200/article/details/104050685