Difference between revisions of "컴퓨터프로그래밍및실습 (2022년)/1128"

From DISLab
Jump to navigation Jump to search
 
(35 intermediate revisions by the same user not shown)
Line 1: Line 1:
== JavaFX 개요 ==
== JavaFX 컨트롤 ==
# AWT
#* Native UI 컴포넌트 사용
#* 운영체제 마다 UI 모양이 다름
# Swing
#* 운영체제가 제공하는 native UI 사용 안 함
#* 운영체제가 새롭게 제공하는 UI 지원의 어려움
# JavaFX
#* Abode의 flash, Microsoft의 silverlight의 대항마
#* JDK 7부터 지원. JDK 8 권장.
#* JDK 11부터는 별도로 설치해야 함.
#* 화면 레이아웃과 스타일, 애플리케이션 로직 분리
#* Java 코드와 분리해서 스타일 시트(CSS)로 외관 작성 → 개발자와 디자이너의 동시 개발 가능
#* Java 코드에서도 레이아웃과 애플리케이션 로직을 분리하고 싶다면 레이아웃은 FXML로 작성, 로직은 Java로 작성
#* JavaFX 애플리케이션 구성 요소
{| class="wikitable" cellpadding="50"
| rowspan="2" align="center" | '''[레이아웃]'''<br/>자바 코드 파일</br>또는 FXML 파일
| align="center" | '''[외관 및 스타일]'''<br/>CSS 파일
| rowspan="2" align="center" | '''[리소스]'''<br/>그림 파일<br/>동영상 파일<br/>...
|-
| align="center" | '''[비즈니스 로직]'''<br/>자바 코드 파일
|}


== JavaFX 애플리케이션 개발 시작 ==
=== 버튼 컨트롤 ===
=== 메인 클래스 ===
* ButtonBase를 상속하는 하위 컨트롤
<syntaxhighlight lang="java">
* Button, CheckBox, RadioButton, ToggleButton, Hyperlink 등
import javafx.application.Application;
* p.896 그림 참조
import javafx.stage.Stage;


public class AppMain extends Application {
* Button
<syntaxhighlight lang="xml">
<Button text="아이콘버튼">
  <graphic>
      <ImageView>
        <Image url="@iamges/history_view.gif"/>
      </ImageView>
  </graphic>
</Button>
</syntaxhighlight>


    @Override
* selected 속성 - CheckBox, RadioButton, ToggleButton : 선택, 미선택 (selected가 true 혹은 false)
    public void start(Stage primaryStage) throws Exception {
<syntaxhighlight lang="xml">
        primaryStage.show();       
<CheckBox text="라벨1" userData="값1"/>
    }
<CheckBox text="라벨2" userData="값2" selected="true"/>
 
    public static void main(String[] args) {
        launch(args);
    }
}
</syntaxhighlight>
</syntaxhighlight>


=== JavaFX 라이프사이클(life cycle) ===
* toggleGroup 속성 - RadioButton, ToggleButton : 하나의 그룹으로 묶이고, 그룹 내에서는 하나만 선택
* 예제 코드
<syntaxhighlight lang="xml">
<syntaxhighlight lang="java">
<fx:deine>
import javafx.application.Application;
  <ToggleGroup fx:=id="groupName"/>
import javafx.stage.Stage;
</fx:define>


public class AppMain extends Application {
<RadioButton text="라벨1" userData="값1" toggleGroup="$groupName" />
    public AppMain() {
<RadioButton text="라벨2" userData="값2" toggleGroup="$groupName" selected="true" />
        System.out.println(Thread.currentThread().getName() + ": AppMain() 호출");
</syntaxhighlight>
    }


    @Override
* ActionEvent 발생 - CheckBox, RadioButton, ToggleButton : 컨트롤을 사용하가 클릭할 경우
    public void init() throws Exception {
<syntaxhighlight lang="xml">
        System.out.println(Thread.currentThread().getName() + ": init() 호출");
<CheckBox ... onAction="#handleChkAction"/>
    }
</syntaxhighlight>


* RadioButton, ToggleButton 그룹 내에서 선택 변경을 감시하고 싶다면
<syntaxhighlight lang="java">
groupName.selectedToggleProperty().addListener(new ChangeListener<Toggle> {
     @Override
     @Override
     public void start(Stage primaryStage) throws Exception {
     public void changed(ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) {
         System.out.println(Thread.currentThread().getName() + ": start() 호출");
         ...
        primaryStage.show();
    }
    @Override
    public void stop() throws Exception {
        System.out.println(Thread.currentThread().getName() + ": stop() 호출");
     }
     }
 
});
    public static void main(String[] args) throws Exception {
        System.out.println(Thread.currentThread().getName() + ": main() 호출");
        launch(args);       
    }
}
</syntaxhighlight>
</syntaxhighlight>


* 실행 결과
*
<syntaxhighlight lang="text">
main: main() 호출
JavaFX Application Thread: AppMain() 호출
JavaFX-Launcher: init() 호출
JavaFX Application Thread: start() 호출
JavaFX Application Thread: stop() 호출 ← 프로그램을 끝내야 실행된다.
</syntaxhighlight>


=== 메일 클래스 실행 매개값 얻기 ===
<syntaxhighlight lang="xml">
<syntaxhighlight lang="text">
<?xml version="1.0" encoding="UTF-8"?>
C:> java AppMain --ip=192.168.0.5 --port=50001
</syntaxhighlight>


* main()에서 launch(args)를 넘겨 받음
<?import javafx.geometry.Insets?>
* init() 메소드에서 아래와 같이 실행할 수 있음
<?import javafx.scene.control.Button?>
<syntaxhighlight lang="java">
<?import javafx.scene.control.RadioButton?>
Parameters params = getParameters();
<?import javafx.scene.control.CheckBox?>
List<String> list = params.getRaw();
<?import javafx.scene.control.Separator?>
Map<String, String> map = params.getNamed();
<?import javafx.scene.control.ToggleGroup?>
</syntaxhighlight>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>


=== 무대(Stage)와 장면(Scene) ===
* 윈도우 : Stage
* Stage에는 하나의 Scene을 가질 수 있음
* Scene은 직접 생성해야 함


[[file:CP2022_ch17.2_AppMain.png|thumb|AppMain 실행화면]]
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="ch17.p897.RootController" prefHeight="150.0" prefWidth="420.0">
<syntaxhighlight lang="java">
  <padding>
import javafx.application.Application;
      <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
import javafx.application.Platform;
  </padding>
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;


public class AppMain extends Application {
  <center>
      <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" spacing="10">
        <children>
            <VBox prefHeight="200.0" prefWidth="100.0" spacing="20.0" alignment="CENTER_LEFT">
              <children>
                  <CheckBox fx:id="chk1" text="안경" onAction="#handleChkAction" />
                  <CheckBox fx:id="chk2" text="모자" onAction="#handleChkAction" />
              </children>
            </VBox>


    @Override
            <ImageView fx:id="checkImageView" fitWidth="200.0" preserveRatio="true">
    public void start(Stage primaryStage) throws Exception {
              <image><Image url="@images/geek.gif" /></image>
        VBox root = new VBox();
            </ImageView>
        root.setPrefWidth(350);
        root.setPrefHeight(150);
        root.setAlignment(Pos.CENTER);
        root.setSpacing(20);


        Label label = new Label();
            <Separator orientation="VERTICAL" prefHeight="200.0" />
        label.setText("Hello, JavaFX");
        label.setFont(new Font(50));


        Button button = new Button();
            <VBox prefHeight="200.0" prefWidth="100.0">
        button.setText("확인");
              <fx:define>
        button.setOnAction(event->Platform.exit());
                  <ToggleGroup fx:id="group" />
              </fx:define>


        root.getChildren().add(label);
              <children>
        root.getChildren().add(button);
                  <RadioButton fx:id="rad1" text="BubbleChart" userData="BubbleChart" toggleGroup="$group"/>
                  <RadioButton fx:id="rad2" text="BarChart" userData="BarChart" toggleGroup="$group" selected="true" />
                  <RadioButton fx:id="rad3" text="AreaChart" userData="AreaChart" toggleGroup="$group"/>
              </children>
            </VBox>


        Scene scene = new Scene(root); // VBox를 루트 컨테이너(root container)로 해서 Scene 생성
            <ImageView fx:id="radioImageView" fitHeight="100.0" preserveRatio="true">
              <image>
                  <Image url="@images/BarChart.png" />
              </image>
            </ImageView>
        </children>
      </HBox>
  </center>


        primaryStage.setTitle("AppMain입니다");
    <bottom>
        primaryStage.setScene(scene); // 윈도우에 장면 설정
      <Button fx:id="btnExit" BorderPane.alignment="CENTER" onAction="#handleBtnExitAction">
        primaryStage.show();       
        <graphic>
    }
            <ImageView>
   
              <Image url="@images/exit.png" />
    public static void main(String[] args) {
            </ImageView>
        launch(args);
        </graphic>
    }
        <BorderPane.margin>
}
            <Insets top="20.0" />
        </BorderPane.margin>
      </Button>
  </bottom>
</BorderPane>
</syntaxhighlight>
</syntaxhighlight>


== JavaFX 레이아웃 ==
=== 프로그램적 레이아웃 ===
[[file:CP_2022_ch17.3.1.AppMain.png | thumb | 프로그램적 레이아웃]]
<syntaxhighlight lang="java">
<syntaxhighlight lang="java">
import javafx.application.Application;
package ch17.p897;
import javafx.collections.ObservableList;
 
import javafx.geometry.Insets;
import java.net.URL;
import javafx.scene.Scene;
import java.util.ResourceBundle;
 
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.HBox;
import javafx.scene.control.Toggle;
import javafx.stage.Stage;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;


public class AppMain extends Application {
public class RootController implements Initializable {
    @FXML private CheckBox chk1;
    @FXML private CheckBox chk2;
    @FXML private ImageView checkImageView;
    @FXML private ToggleGroup group;
    @FXML private ImageView radioImageView;
    @FXML private Button btnExit;


     @Override
     @Override
     public void start(Stage primaryStage) throws Exception {
     public void initialize(URL location, ResourceBundle resources) {
         HBox hbox = new HBox();
         group.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
        hbox.setPadding(new Insets(10));
        hbox.setSpacing(10);


        TextField textField = new TextField();
            @Override
        textField.setPrefWidth(200);
            public void changed(ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) {
                Image image = new Image(getClass().getResource("images/" +
                                        newValue.getUserData().toString() + ".png").toString());
                radioImageView.setImage(image);               
            }
           
        });


        Button button = new Button();
    }
        button.setText("확인");


         ObservableList list = hbox.getChildren();
    // CheckBox 이벤트 처리
         list.add(textField);
    public void handleChkAction(ActionEvent e) {
         list.add(button);
         if (chk1.isSelected() && chk2.isSelected()) {
            checkImageView.setImage(new Image(getClass().getResource("images/geek-glasses-hair.gif").toString()));
         } else if (chk1.isSelected()) {
            checkImageView.setImage(new Image(getClass().getResource("images/geek-glasses.gif").toString()));
         } else if (chk2.isSelected()) {
            checkImageView.setImage(new Image(getClass().getResource("images/geek-hair.gif").toString()));
        } else {
            checkImageView.setImage(new Image(getClass().getResource("images/geek.gif").toString()));
        }
    }


        Scene scene = new Scene(hbox);
    // Button 이벤트 처리
 
    public void handleBtnExitAction(ActionEvent e) {
        primaryStage.setTitle("AppMain");
         Platform.exit();
        primaryStage.setScene(scene);
         primaryStage.show();
     }
     }


    public static void main(String[] args) {
        launch(args);
    }
}
}
</syntaxhighlight>
</syntaxhighlight>


=== FXML 레이아웃 ===
* FXML 파일 (root.fxml)
<syntaxhighlight lang="text">
<?xml version="1.0" encoding="UTF-8"?>


<?import javafx.scene.layout.HBox?>
=== 입력 컨트롤 ===
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>


<HBox xmlns:fx="http://javafx.com/fxml">
    <padding>
        <Insets top="10" right="10" bottom="10" left="10"/>
    </padding>
    <spacing>10</spacing>


    <children>
=== 뷰 컨트롤 ===
        <TextField>
            <prefWidth>200</prefWidth>
        </TextField>


        <Button>
==== ImageView 컨트롤 ====
            <text>확인</text>
        </Button>
    </children>
</HBox>
</syntaxhighlight>


* AppMain 클래스
==== ListView 컨트롤 ====


<syntaxhighlight lang="java">
==== TableView 컨트롤 ====
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 = FXMLLoader.load(getClass().getResource("root.fxml")); // ← FXML 로드
        Scene scene = new Scene(root);


        primaryStage.setTitle("AppMain");
==== Slider 컨트롤 ====
        primaryStage.setScene(scene);
        primaryStage.show();
    }
   
    public static void main(String[] args) {
        launch(args);
    }
}
</syntaxhighlight>


== JavaFX 컨테이너 ==


==== ProgressBar와 ProgressIndicator 컨트롤 ====


== JavaFX 이벤트 처리 ==
=== 차트 컨트롤 ===




== JavaFX 속성 감시와 바인딩 ==


== JavaFX 메뉴바(MenuBar)와 툴바(Toolbar) ==


== JavaFX 컨트롤 ==
=== MenuBar 컨트롤 ===


=== ToolBar 컨트롤 ===


== JavaFX 메뉴바(MenuBar)와 툴바(Toolbar) ==




== JavaFX 다이얼로그(Dialog) ==
== JavaFX 다이얼로그(Dialog) ==


=== FileChooser, DirectoryChooser ===


== JavaFX CSS 스타일 ==
=== Popup ===


=== Custom Dialog ===


== JavaFX 스레드 동시성 ==
=== 컨트롤러에서 primaryStage 사용 ===


==== 메인 클래스에 전달하는 방법 ====


== 화면 이동과 애니메이션 ==
==== 컨테이너 또는 컨트롤로부터 얻는 방법 ====

Latest revision as of 15:57, 22 July 2022

JavaFX 컨트롤

버튼 컨트롤

  • ButtonBase를 상속하는 하위 컨트롤
  • Button, CheckBox, RadioButton, ToggleButton, Hyperlink 등
  • p.896 그림 참조
  • Button
<Button text="아이콘버튼">
   <graphic>
      <ImageView>
         <Image url="@iamges/history_view.gif"/>
      </ImageView>
   </graphic>
</Button>
  • selected 속성 - CheckBox, RadioButton, ToggleButton : 선택, 미선택 (selected가 true 혹은 false)
<CheckBox text="라벨1" userData="값1"/>
<CheckBox text="라벨2" userData="값2" selected="true"/>
  • toggleGroup 속성 - RadioButton, ToggleButton : 하나의 그룹으로 묶이고, 그룹 내에서는 하나만 선택
<fx:deine>
   <ToggleGroup fx:=id="groupName"/>
</fx:define>

<RadioButton text="라벨1" userData="값1" toggleGroup="$groupName" />
<RadioButton text="라벨2" userData="값2" toggleGroup="$groupName" selected="true" />
  • ActionEvent 발생 - CheckBox, RadioButton, ToggleButton : 컨트롤을 사용하가 클릭할 경우
<CheckBox ... onAction="#handleChkAction"/>
  • RadioButton, ToggleButton 그룹 내에서 선택 변경을 감시하고 싶다면
groupName.selectedToggleProperty().addListener(new ChangeListener<Toggle> {
    @Override
    public void changed(ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) {
        ...
    }
});
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>


<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="ch17.p897.RootController" prefHeight="150.0" prefWidth="420.0">
   <padding>
      <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
   </padding>

   <center>
      <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" spacing="10">
         <children>
            <VBox prefHeight="200.0" prefWidth="100.0" spacing="20.0" alignment="CENTER_LEFT">
               <children>
                  <CheckBox fx:id="chk1" text="안경" onAction="#handleChkAction" />
                  <CheckBox fx:id="chk2" text="모자" onAction="#handleChkAction" />
               </children>
            </VBox>

            <ImageView fx:id="checkImageView" fitWidth="200.0" preserveRatio="true">
               <image><Image url="@images/geek.gif" /></image>
            </ImageView>

            <Separator orientation="VERTICAL" prefHeight="200.0" />

            <VBox prefHeight="200.0" prefWidth="100.0">
               <fx:define>
                  <ToggleGroup fx:id="group" />
               </fx:define>

               <children>
                  <RadioButton fx:id="rad1" text="BubbleChart" userData="BubbleChart" toggleGroup="$group"/>
                  <RadioButton fx:id="rad2" text="BarChart" userData="BarChart" toggleGroup="$group" selected="true" />
                  <RadioButton fx:id="rad3" text="AreaChart" userData="AreaChart" toggleGroup="$group"/>
               </children>
            </VBox>

            <ImageView fx:id="radioImageView" fitHeight="100.0" preserveRatio="true">
               <image>
                  <Image url="@images/BarChart.png" />
               </image>
            </ImageView>
         </children>
      </HBox>
   </center>

    <bottom>
      <Button fx:id="btnExit" BorderPane.alignment="CENTER" onAction="#handleBtnExitAction">
         <graphic>
            <ImageView>
               <Image url="@images/exit.png" />
            </ImageView>
         </graphic>
         <BorderPane.margin>
            <Insets top="20.0" />
         </BorderPane.margin>
      </Button>
   </bottom>
</BorderPane>
package ch17.p897;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

public class RootController implements Initializable {
    @FXML private CheckBox chk1;
    @FXML private CheckBox chk2;
    @FXML private ImageView checkImageView;
    @FXML private ToggleGroup group;
    @FXML private ImageView radioImageView;
    @FXML private Button btnExit;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        group.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {

            @Override
            public void changed(ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) {
                Image image = new Image(getClass().getResource("images/" +
                                        newValue.getUserData().toString() + ".png").toString());
                radioImageView.setImage(image);                
            }
            
        });

    }

    // CheckBox 이벤트 처리
    public void handleChkAction(ActionEvent e) {
        if (chk1.isSelected() && chk2.isSelected()) {
            checkImageView.setImage(new Image(getClass().getResource("images/geek-glasses-hair.gif").toString()));
        } else if (chk1.isSelected()) {
            checkImageView.setImage(new Image(getClass().getResource("images/geek-glasses.gif").toString()));
        } else if (chk2.isSelected()) {
            checkImageView.setImage(new Image(getClass().getResource("images/geek-hair.gif").toString()));
        } else {
            checkImageView.setImage(new Image(getClass().getResource("images/geek.gif").toString()));
        }
    }

    // Button 이벤트 처리
    public void handleBtnExitAction(ActionEvent e) {
        Platform.exit();
    }

}


입력 컨트롤

뷰 컨트롤

ImageView 컨트롤

ListView 컨트롤

TableView 컨트롤

미디어 컨트롤

Slider 컨트롤

ProgressBar와 ProgressIndicator 컨트롤

차트 컨트롤

JavaFX 메뉴바(MenuBar)와 툴바(Toolbar)

MenuBar 컨트롤

ToolBar 컨트롤

JavaFX 다이얼로그(Dialog)

FileChooser, DirectoryChooser

Popup

Custom Dialog

컨트롤러에서 primaryStage 사용

메인 클래스에 전달하는 방법

컨테이너 또는 컨트롤로부터 얻는 방법