GUI(Graphic User Interface)란? 사용자 인터페이스를 구성할 때 다양한 그래픽 요소들을 적용하여 구성한 형태
JAVA에서는 GUI를 AWT와 Swing으로 표현하고 있다.
AWT와 Swing의 차이점에 대해서 알아보자.
AWT는 자바 초기에 GUI를 제공하기 위해 제공한 '패키지'이다. 그래픽을 제공하기 위해 운영체제에 있는 그래픽 요소를 끌어다 사용한다. 그렇기 때문에 운영체제가 제공하는 그래픽 컴포넌트와 일대일로 연결되어 작동해야하는 overhead가 발생하고, 운영체제가 제공하지 않는 그래픽을 표현할 수 없다는 단점이 있다.
Swing은 새로운 그래픽 툴킷으로 자바가상기계인 JVM이 자체적으로 처리한다. 이러한 Swing component를 경량 컴포넌트, lightweight component라고 한다. 경량 컴포넌트는 실행 중인 시스템의 그래픽 컴포넌트를 사용하지 않고 JVM자체에서 처리하기 때문에 실행시간과 메모리가 많이 요구되는 단점이 있다.
GUI를 구현하기에 앞서 필요한 사전지식은 클래스에 대한 이해이다. extends와 implements, override 등 다양한 클래스에 있는 기법들이 사용된다. 또한, 코딩자체는 높은 수준을 요하지는 않으나 큰 틀을 구상하고, 작은 부분부터 쌓아나가서 합치는 능력이 요구된다.
그렇기 때문에 이 글에서는 작은 부분부터 시작하여 합치는 과정으로 진행하도록 할 것이고, 메소드의 사용법은 다루지 않고 언급만 하고 넘어가겠다. 개념만 알고 있으면 조금의 삽질을 통한 이해를 진행하면 한두가지의 예제만 가지고 많은 것을 할 수 있다. 그리고 상당히 많은 개념을 알고 있어야해서, 세부 메소드를 언급하면 분량이 기하 급수적으로 많아질 것이다.

일단 파란색의 루트 노드를 보자. JComponent이다. 이 클래스는 스윙에 속하는 모든 컴포넌트 클래스의 상위 클래스이다. 이 클래스는 추상 클래스로써, 이 클래스로부터 상속된 대부분의 스윙 컴포넌트에서 이 메소드를 사용하고 있다.
1. 텍스트를 입력받아보자.
JTextField -> 한 줄의 텍스트를 입력받는 클래스
JTextArea -> 여러 줄의 텍스트를 입력받는 클래스
2. 버튼을 사용해보자.
AbstractButton class->(버튼, 체크박스 버튼, 라디오 버튼)
JButton -> 버튼 ex) 출력하기
JCheckBox -> 체크박스 버튼 ex) 음식 종류
JRadioButton -> 라디오 버튼 ex) 회원&비회원

3. 여러가지 중 하나만 선택해보자.
JComboBox -> 텍스트 필드와 풀다운 리스트를 조합한 형태
4. 여러가지 중 여러개를 선택해보자.
JList
5. 스크롤바를 사용해보자.
JScrollPane
6. 메뉴를 구성해보자.
JMenuBar -> 메뉴 클래스 구성하는 최상위
JMenu -> 메뉴들을 생성
JMenuItem -> 서브 메뉴들을 생성

이렇게 많은 기능들을 어떻게 관리할 수 있을까?
이는 조금 더 큰 범주의 클래스인 JLabel, JPanel, JFrame, Container 등이 있다.
JLabel에는 텍스트와 이미지를 표현한다.
JPanel은 배치를 효율적으로 해주는 기능으로, 여러가지 스윙 컴포넌트를 하나로 묶어주는 기능을 한다.
JFrame은 GUI를 구축할 때 필수적으로 사용해야 하는 틀을 제공하는 컴포넌트이다. 즉, GUI 창의 전반적인 부분을 담당하고 있다고 생각하면 된다.
Container는 여러개로 모인 JPanel, JLabel 하나로 모으는 기능을 해준다.
그렇다면 어떻게 배치할 수 있을까?
우리는 배치관리자를 배울 것이다.
배치관리자는 FlowLayout, BorderLayout, GridLayout 클래스 가 있다.
FlowLayout은 수평방향으로 계속 추가하여 배치하는 방식이고,
BorderLayout은 동서남북과 중앙을 선택하여 배치하는 방식이고,
GridLayout은 표처럼 나타내는 방식이다. (완전히 표가 되지는 않는다.)
이로써 GUI에 대한 전반적인 개념에 대해서 알아볼 수 있었다.
하지만 아직 세부 메소드나 어떻게 코딩해야하는지, 어떤 방식으로 작동하는지에 대해서는 설명하지 않았다.
이제 GUI구현을 하는데에 있어, 반드시 필요한 세부 메소드들을 알아보고, 예제를 만나보자.
GUI를 사용할때 반드시 필요한 예제들을 만나보자.
일단 설계부터 해보자.
동서남북중앙에 버튼이 있다. 동서남북중앙? Layout이 BorderLayout이겠네?


위에 있는 set이 붙은 메소드는 JFrame 을 extends하여 나온 메소드들이다. 이 점을 주의하면서 시작하자.
setTitle을 윈도우바에 있는 제목을 의미한다.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 는 GUI 창을 껐을때 어떤 행동을 취할 것인지 의미한다.
자바에서는 이 GUI 창을 JVM이라는 가상 머신을 이용하여 관리하게 되는데, 만약 이 메소드를 사용해주지 않는다면, 창을 끈 이후에도 메모리 상에는 남아있게 됨을 의미한다.
setLayout은 전체적인 Layout에 어떤 틀을 잡을 것인지를 의미한다.
setSize는 화면의 크기(가로, 세로)를 의미하고,
setVisible은 이 GUI 창을 띄울 것인지, 아닐 것인지를 의미한다. 따라서, 작업을 끝낸 뒤 이 메소드를 true로 넣어주지 않는다면 결과가 나오지 않을 것이다.
다음은 메뉴바를 만들고, 텍스트 필드에 추가하는 예제이다.
코드가 길어보이고 난잡해보일 수 있지만, 하나하나 쌓아가면 어느샌가 완성되어 있는 것을 볼 수 있다.


본격적으로 그래픽 프로그래밍을 하기 위해서는 Graphic class를 사용한다.
Graphic은 주로 JPanel class를 이용하여 그린다. 왜냐하면 패널은 그림을 그릴 수 있는 서비스를 가지고 있을 뿐만 아니라, 동시에 컨테이너 역할을 하기 때문에 배경을 그린 후, 다른 컴포넌트를 추가할 수 있다.
따라서 UI와 Graphic을 동시에 구현할 수 있음을 의미한다.
Graphic class : 그림을 그리는데 필요한 모든 설정값과 그림 그리는 메소드를 가지고 있다. 따라서 자바에서의 모든 그리기는 그래픽 객체에서 이루어져야 한다.
- method
repaint() : paintComponent method는 사용자가 아닌 자동적으로 호출되어야 한다. 따라서 사용자가 화면을 다시 그리고 싶다면 repaint()메소드를 호출하면 된다.
super.paintComponent(g) : 그림이 그려지는 컴포넌트가 JPanel, JLabel처럼 Graphic Component인 경우, paintComponent method를 override 할 때 유용하다. 왜냐하면 그래픽 컴포넌트를 상속받았을 때, 부모 클래스가 그려야 될 부분도 있기 때문이다. 자기 그림만 그리고 종료해버리면 부모 클래스는 그릴 기회를 얻지 못한다.
- 그래픽 좌표계는 왼쪽 상단부터(0, 1)로 시작한다.
KeyListener를 발동하기 위해서는 focus가 존재해야한다.
특정 이벤트가 발생했을때 해당 컴포넌트에 포커스를 줘서 키 이벤트를 반환하라는 의미이다.
이를 수행하기 위한 메소드는 requestFocus로 setContentPane의 메소드로 사용할 수 있다.
focus는 말 그대로 초점을 맞추는 것이기 때문에, 다른 곳에서 focus를 선언하면, 기존에 있던 focus를 잃게 된다.
예제를 살펴보자.
위 화면은 결과화면이다.
우리가 배운 것으로 먼저 만들 것을 설계해보자.
위에는 TextField있고, 가운데에는 JButton이 2개가 있고,
밑에는 "print here"이라는 글자가 써있다. 이 글자는 JLabel로 관리하면 되겠네?
그 전체적인 틀은 BorderLayout을 사용해야겠구나!



우리가 알아야 할 것은 MyActionListener(listener)이다.
이 함수를 만들어줄때, ActionListener라는 interface를 implements하게 된다.
implements 한다는 것의 의미는 내장되어 있는 메소드를 전부 override하여 구현해야 함을 의미한다.
따라서 actionPerformed(ActionEvent e) 함수를 override하여 버튼의 동작이 감지되었을 때, 어떤 행동을 취할 것인지 의미한다.
위에 구현되어 있는 것은 글자를 입력한 후, copy를 누르게 되면 JLabel에 "이곳에 출력됨"이 입력한 Text가 설정한 Font가 적용되어 변환될 것이다.
이런 방식은 좀 불편하다.

따라서 이렇게 내장 클래스에 implements 한다면 별도의 함수를 만들지 않고도 바로 override하여 사용할 수 있다.
하나의 함수에 여러 개의 버튼을 다루는 것이 아닌,
여러 개의 버튼에 여러 개의 동작을 독립적으로 다루기 위해서는 어떻게 해야할까?
이를 위한 방법으로 익명 클래스와 람다 방식이 있다.
여기에서는 익명 클래스 사용 방법만 다루도록 하겠다.
익명 클래스란 기본적으로 '함수의 이름'이 없는 클래스를 의미한다.
따라서 메소드를 사용하기 위해 별개의 클래스 생성을 거치지 않고, 바로 메소드를 사용할 수 있다.
대신, 함수 명을 제외한 모든 조건을 충족해주어야 한다.
이에 대한 예제를 알아보도록 하자.

addActionListener 메소드를 사용했지만 이에 대한 인자의 정보에 대해서는 아무것도 모르는 상황이다.
따라서 이 인자에 대한 정보를 추가해주어야 한다. 이 메소드는 ActionListener의 객체를 필요로 한다. 그렇기 때문에 new를 활용하여 바로 객체를 일회성으로 생성해주고, 이 클래스에 속해있는 정보를 override해주면 된다.
많은 예제가 있을수록 많은 정보를 알 수 있는 얕으면서 넓은 범위의 강의인데, 많은 내용을 필요한 부분만 설명하려다보니 길어지면서도 부족한 부분이 많이 있었다.