JavaFX | Canvas 그래픽 그리기 | Canvas와 GraphicsContext

그래픽 그리기는 AWT에도 Swing에서도 기본적인 아이디어는 동일했었다. 구성 요소에는 표시를 업데이트 할 때 호출되는 paint 메소드 (또는 paintComponent)가 제공되어 있으며, 이 메서드를 오버라이딩하면 자동으로 호출되어 그리기가 실행되었다.

각각의 구성 요소에는 렌더링 처리를 관리하는 Graphics (또는 Graphics2D) 클래스의 인스턴스가 포함되어 그것이 paint 메소드에 인수로 전달된다. 이 Graphics에 있는 드로잉 메서드를 호출하여 그리기를 할 수 있었다.

하지만 JavaFX는 상당히 사정이 다르다. 먼저, 컨트롤에는 표시를 업데이트 때에 호출되는 메소드가 없다. 이 시점에서 “어? 그럼 어떻게 하는 거야?“라고 머리 하얗게 되어 버리는 Java 프로그래머도 많을지도 모르겠다. 메소드가 없으니 당연히 Graphics 전달되지 않는다. 그렇다면 그리기 수단이 없다 …?

아니다. 그것은 반대다. 즉, “표시를 업데이트 때에 호출되는 메소드를 오버라이드(override)하지 않으면 그릴 수 없다"가 아니라, “언제 어디서나 필요할 때 그릴 수 있게 됐다"것이다. “이 메소드를 오버라이드하고 렌더링 처리를 작성하지 않으면 안된다"는 제한이 없고, 어디에서든 그려도 항상 그것이 컨트롤에 표시되며 이를 마음대로 끄거나 할 수 없게 되는 것이다.

그래픽 그리기를 하려면 “Canvas"라는 컨트롤를 준비해야 된다. AWT에도 같은 이름의 Canvas 클래스가 있었지만, 그것과는 전혀 다른 것이다. JavaFX용은 javafx.scene.canvas 패키지에 포함되어 있다.

Canvas에는 “GraphicsContext"라는 클래스의 인스턴스가 포함되어 있다. 이것이 AWT/Swing의 Graphics 클래스에 해당된다. 이 인스턴스를 얻어서 거기에 있는 메소드를 호출하는 것으로, Canvas에 도형 등을 그릴 수 있게 된다.

그럼 실제로 해보자. 우선은 FXML에서 Canvas를 추가하도록 하자. 아래와 같이 FXML 파일을 만들고 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
 
<?import java.lang.*?>
<?import javafx.scene.canvas.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.*?>
<BorderPane xmlns="http://javafx.com/javafx"
    xmlns:fx="http://javafx.com/fxml"
    fx:controller="com.devkuma.javafx.AppController">
    <center>
        <Canvas fx:id="canvas" width="300" height="300" />
    </center>
</BorderPane>

이 FXML을 로드하고 표시하는 Application 클래스는 별도 준비하도록 하자 (이전까지 작성했던 것을 그대로 사용해도 된다).

BorderPane의 center에 단순히 <Canvas> 태그를 배치 했을 뿐이다. <Canvas>에는 width와 height 속성을 추가되어 있다. 이렇게 하면 컨트롤의 크기가 조정된다.