JAVA chapter17. javaFX. 


17.11 JavaFX 스레드 동시성



17.11.1 Platform.runLater() 메소드




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
 
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
 
<AnchorPane xmlns:fx="http://javafx.com/fxml" prefHeight="100.0" prefWidth="200.0" 
    fx:controller="sec11.exam01_runlater.RootController">
   <children>
      <Label fx:id="lblTime" alignment="CENTER" layoutX="25.0" layoutY="15.0" 
                  prefHeight="35.0" prefWidth="150.0" 
                  style="-fx-background-color: black; -fx-text-fill: yellow; 
                          -fx-font-size: 20; -fx-background-radius: 10;" text="00:00:00" />
      <Button fx:id="btnStart" layoutX="46.0" layoutY="63.0" text="시작" /> // 여기에 onaction 메소드를 넣어서 지정해도됨
      <Button fx:id="btnStop" layoutX="110.0" layoutY="63.0" text="멈춤" />
   </children>
</AnchorPane>
cs

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package sec11.exam01_runlater;
 
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ResourceBundle;
 
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
 
public class RootController implements Initializable { // Controller 클래스를 구현하려면 Initializable 인터페이스를 구현해야함
    @FXML private Label lblTime;
    @FXML private Button btnStart;
    @FXML private Button btnStop;
    
    private boolean stop;
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        btnStart.setOnAction(event->handleBtnStart(event));
        btnStop.setOnAction(event->handleBtnStop(event));
    }
    
    public void handleBtnStart(ActionEvent e) { // 시간이 흘러가는 java Application thread가 해버리면 다른 작업이 안된다
        stop = false; // 계속적으로 무언가를 해야할경우에는 작업자 thread를 만들어서 해야한다
        Thread thread = new Thread() {
            @Override
            public void run() {
                SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
                while(!stop) {
                    String strTime = sdf.format(new Date());
                    Platform.runLater(()->{ // UI 변경 작업
                        lblTime.setText(strTime);
                    });
                    try { Thread.sleep(100); } catch (InterruptedException e) {} // 너무빨리돌면안되니까 1초에 한번씩 쉬는걸로
                }
            };
        };
        thread.setDaemon(true);
        thread.start();
    }
    
    public void handleBtnStop(ActionEvent e) {
        stop = true;
    }
}
cs



17.11.2 Task 클래스







1. cancel() 메소드를 호출 했을 때

2. 일시정지 상태에서 Interrupt()를 호출 했을 때




AppMain.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package sec11.exam02_task;
 
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
 
public class AppMain extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = (Parent)FXMLLoader.load(getClass().getResource("root.fxml"));
        Scene scene = new Scene(root);
        
        primaryStage.setTitle("AppMain");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
 
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
 
<AnchorPane xmlns:fx="http://javafx.com/fxml" prefHeight="129.0" prefWidth="233.0" 
    fx:controller="sec11.exam02_task.RootController">
    <children>
        <ProgressBar fx:id="progressBar" layoutX="17.0" layoutY="23.0" prefWidth="200.0" progress="0.0" />
        <Label fx:id="label" layoutX="18.0" layoutY="57.0" text="진행정도:" />    
        <Label fx:id="lblWorkDone" layoutX="77.0" layoutY="57.0" />
        <Button fx:id="btnStart" layoutX="66.0" layoutY="91.0" text="시작" />
        <Button fx:id="btnStop" layoutX="130.0" layoutY="91.0" text="멈춤" />
    </children>
</AnchorPane>
cs

RootController.java
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package sec11.exam02_task;
 
import java.net.URL;
import java.util.ResourceBundle;
 
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
 
public class RootController implements Initializable {
    @FXML private ProgressBar progressBar;
    @FXML private Label lblWorkDone;
    @FXML private Button btnStart;
    @FXML private Button btnStop;
    
    private Task<Void> task;
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        btnStart.setOnAction(event->handleBtnStart(event));
        btnStop.setOnAction(event->handleBtnStop(event));
    }
    
    public void handleBtnStart(ActionEvent e) {
        task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                for(int i=0; i<=100; i++) {
                    if(isCancelled()) { 
                        updateMessage("취소됨");
                        break
                    }
                    updateProgress(i, 100); // Task의 progress 속성 업데이트
                    updateMessage(String.valueOf(i)); // Task의 message 속성 업데이트
                    try {Thread.sleep(100); } catch(InterruptedException e) {
                        if(isCancelled()) { 
                            updateMessage("취소됨");
                            break
                        }
                    }
                }
                return null;
            }
        };
        
        progressBar.progressProperty().bind(task.progressProperty()); // 속성 바인딩
        lblWorkDone.textProperty().bind(task.messageProperty());
        
        Thread thread = new Thread(task); // 작업 스레드 시작
        thread.setDaemon(true);
        thread.start();
    }
    
    public void handleBtnStop(ActionEvent e) {
        task.cancel();
    }
}
cs




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
 
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
 
<AnchorPane xmlns:fx="http://javafx.com/fxml" prefHeight="129.0" prefWidth="233.0"  
    fx:controller="sec11.exam03_task_callback.RootController">
    <children>
        <ProgressBar fx:id="progressBar" layoutX="17.0" layoutY="23.0" prefWidth="200.0" progress="0.0" />
        <Label layoutX="18.0" layoutY="57.0" text="진행정도:" />    
        <Label fx:id="lblWorkDone" layoutX="77.0" layoutY="57.0" />
        <Label layoutX="118.0" layoutY="57.0" text="작업결과:" />
        <Label fx:id="lblResult" layoutX="175.0" layoutY="57.0" />
        <Button fx:id="btnStart" layoutX="66.0" layoutY="91.0" text="시작" />
        <Button fx:id="btnStop" layoutX="130.0" layoutY="91.0" text="멈춤" />
    </children>
</AnchorPane>
cs



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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package sec11.exam03_task_callback;
 
import java.net.URL;
import java.util.ResourceBundle;
 
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
 
public class RootController implements Initializable {
    @FXML private ProgressBar progressBar;
    @FXML private Label lblWorkDone;
    @FXML private Label lblResult;
    @FXML private Button btnStart;
    @FXML private Button btnStop;
    
    private Task<Integer> task;
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        btnStart.setOnAction(event->handleBtnStart(event));
        btnStop.setOnAction(event->handleBtnStop(event));
    }
    
    public void handleBtnStart(ActionEvent e) {
        task = new Task<Integer>() {
            @Override
            protected Integer call() throws Exception {
                int result = 0;
                for(int i=0; i<=100; i++) {
                    if(isCancelled()) { break; }
                    result += i;
                    updateProgress(i, 100); // Task의 progress와 message 속성을 업데이트
                    updateMessage(String.valueOf(i));
                    try {Thread.sleep(100); } catch(InterruptedException e) {
                        if(isCancelled()) { break; }
                    }
                }
                return result;
            }
            
            @Override
            protected void succeeded() {
                lblResult.setText(String.valueOf(getValue()));
            }
            
            @Override
            protected void cancelled() {
                lblResult.setText("취소됨");
            }
            
            @Override
            protected void failed() {
                lblResult.setText("실패");
            }
        };
        
        progressBar.progressProperty().bind(task.progressProperty()); // 속성 바인딩
        lblWorkDone.textProperty().bind(task.messageProperty()); // 속성 바인딩
        lblResult.setText("");
        
        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }
    
    public void handleBtnStop(ActionEvent e) {
        task.cancel(); // 작업 취소
    }
}
cs


17.11.3 Service 클래스











Posted by 너래쟁이
: