好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

使用javafx更新UI的方法

使用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

查看更多关于使用javafx更新UI的方法的详细内容...

  阅读:52次