본문 바로가기

자바공부

자바 페인팅 메커니즘, 명품자바12장

728x90
반응형

* 스윙에서 페인팅의 기본 골격은 JComponent에 구현되어 있다.

모든 스윙 컴포넌트들은 JComponent를 상속받음으로써 자연스럽게 스윙의 페인팅 메커니즘이 구현된다.

스윙의 페인팅과 관련하여 JComponent가 가지고 있는 메소드는 다음과 같다.

void paint(Graphics g)
// 컴포넌트 자신과 모든 자손 그리기
void paintComponent(Graphics g)
// 컴포넌트 자신의 모양 그리기
void paintBorder(Graphics g)
// 컴포넌트의 외곽 그리기
void paintChildren(Graphics g)
// 컴포넌트의 자식들 그리기

* 스윙에서 컨테이너와 컴포넌트들이 그려지는 과정

컨테이너 container의 그리기 시작은 자신의 부모로부터 container.paint(Graphics g)의 호출에서 시작된다.

paint(Graphics g)는 단순히 다음 세 개의 메소드를 연속적으로 호출하며, paint() 메소드가 종료하면 container 자신과 모든 자손 컴포넌트의 그리기가 종료된다.

void paintComponent(Graphics g) // 1번 
void paintBorder(Graphics g) // 2번
void paintChilderen(Graphics g) // 3번

1) 컨테이너의 paint() 메소드는 일차적으로 자신의 paintComponent(g)를 호출하여 자신의 내부를 그린다.

2) 그리고 나서 paintBorder(g)를 호출하여 자신의 영역 외곽을 그린다.

3) 마지막으로 자식들을 그리기 위해 paintChildren(g)를 호출한다.

paintChildren(g)은 모든 자식들에 대해 순서대로 하나씩 paint(g) 메소드를 호출한다.

이런 식으로 마지막 자식 컴포넌트가 그려지면 페인팅이 종료된다.

✅ JButton처럼 자식이 없는 컴포넌트의 경우 paintChilderen()은 호출되지 않는다.

 

* 한 가지 기억해 둘 것이 있다.

paintComponent(), paintBorder(), paintChildren()의 3개 메소드는 내부적으로 paint()에 의해 호출되는 메소드이므로 이들을 응용프로그램에서 직접 호출하여서는 안 된다는 점이다.

필요한 경우 이들 메소드를 오버라이딩하면 자신만의 새로운 GUI를 창울할 수 있다.

그러나 꼭 필요한 경우가 아니라면 paintComponent()만 오버라이딩하는 것이 좋다.

 

* 스윙의 페인팅 과정은 AWT의 페인팅 과정과 매우 다르다.

스윙은 AWT와는 달리 불투명성, 버퍼링등 몇 개의 추가적 기능을 가지고 있기 때문에 페인팅 메커니즘이 완전히 다시 설계되었다.

AWT 컴포넌트와 스윙 컴포넌트를 섞어 사용하여 자바 응용프로그램을 작성하여서는 안 된다.

 

스윙 컴포넌트 페인팅 과정

* repaint()는 Component 클래스의 메소드로서 매우 중요하다. 응용프로그램 내에서 컴퓨터의 모양, 문자열, 크기, 색 등을 변경하는 경우 이 변경 사항이 바로 화면에 반영되어 나타나지 않는 경우가 있다.

응용프로그램 내에서 컴포넌트의 모양, 문자열, 크기, 색 등을 변경한 것이 화면에 반영되기 위해서는 변경 후 컴포넌트의 paintComponent() 메소드가 다시 실행되어야 한다.

paintComponent()는 응용프로그램 내에서 직접 호출하여서는 안 된다.

이 메소드는 자바 플랫폼에서 호출되기 때문이다.

그러므로 만일 자바 플랫폼에 의해 컴포넌트의 paintComponent()가 호출되지 않으면 비록 프로그램 내에서 컴포넌트의 크기, 모양, 텍스트, 색 등이 변경되었다 하더라도 화면에는 어떤 변화도 일어나지 않을 수 있다.

이 문제에 대한 해결책은 repaint()이다.

repaint()는 자바 플랫폼에게 컴포넌트의 페인팅을 강제로 실행할 것을 지시하는 메소드이다. 

개발자는 응용프로그램 내에서 컴포넌트의 색, 모양, 크기, 텍스트 등을 임의로 변경한 후 repaint()를 호출하여 강제로 컴포넌트의 페인팅 과정이 다시 시작되도록 하여야 한다. 이렇게 하면 빠른 시간 내에 컴포넌트에 대한 변경이 화면에 반영되게 된다.

 

* 어떤 스윙 컴포넌트 component를 다시 그리고자 할 때 다음과 같이 repaint()를 호출한다.

component.repaint();

 

* 컴포넌트를 다시 그리기 위해서는 부모 컴포넌트부터 다시 그리는 것이 좋다.

컴포넌트의 모양이나 위치가 변경되었다면, 자신의 부모에게 자신의 이전 모양이나 이전 위치의 잔상을 지우도록 해야 하기 때문이다.

컴포넌트 component의 부모 컴포넌트부터 다시 그리고자 하는 경우 다음과 같이 호출한다.

component.getParent().repaint();
반응형