Java

[JAVA] Swing GUI 기초(1) - JFrame

흔한공대생 2023. 11. 23. 21:37

 

 

Swing 이란?

Swing은 자바에서 GUI 응용 프로그램을 쉽게 제작에 도움을 주기 위해 순수 자바 언어로 제작된 GUI 컴포넌트를 제공하는 패키지입니다. AWT(Abstract Windowing Toolkit)라는 기본적인 자바 GUI 패키지의 클래스들을 상속받는 클래스들로 구성되어 있습니다.(AWT의 고급 버전인 셈이죠!) 이때 이 GUI 클래스를 컴포넌트라고 따로 부르는데요, Swing과 AWT는 기본적인 버튼, 텍스트 입력창 뿐만 아니라 스크롤을 지원하는 사진창, 파일 경로들을 보여주는 트리 등 다양한 컴포넌트를 지원합니다. 그럼 로그 창을 벗어나 새로운 응용 프로그램으로 넘어가보도록 하겠습니다!

더보기

AWT와 Swing, 이 둘의 차이점은 바로 운영체제 의존성입니다. AWT는 운영체제의 도움을 받기 때문에 각종 컴포넌트들이 귀속되어 운영체제에 부담을 줄 뿐만 아니라 운영체제에 따라 컴포넌트도 바뀌기 때문에 개발자가 의도대로 실행되지 않는다는 불확정성이 있어요. 이렇게 운영체제에 의존하는 컴포넌트를 중량 컴포넌트라고 하며 스윙과 같이 순수 자바 언어로 제작되어 의존하지 않는 컴포넌트를 경량 컴포넌트라고 합니다.

 

Swing 의 밑바탕, JFrame

우선 Swing 컴포넌트들은 JFrame, JButton, JLabel과 같이 AWT 컴포넌트 앞에 J를 붙인 형태이기 때문에 육안으로 구분 가능합니다. 이 중 가장 밑바탕이 되는 JFrame을 생성해보도록 할텐데요, 대표적으로 2가지 방법이 있습니다.

 

1.JFrame을 생성한다

2.JFrame을 상속받는 클래스를 만든다

 

가장 직관적인 방법인 1번부터 진행해보도록 하겠습니다. 우선 Swing 프로그램을 짤 때 아래와 같이 swing 패키지를 import 해주셔야 합니다. 일반적으로 보던 java.*이 아닌 javax.*로 접근해주셔야 swing 패키지를 가져오실 수 있습니다. 

import javax.swing.*;

 

다음으론 main 함수에서 JFrame 컴포넌트를 생성하고 화면을 보이도록 해보겠습니다.

import javax.swing.*;

public class JFrameEx {
	public static void main(String[] args) {
		JFrame jf = new JFrame("JFrame Demo"); // JFrame 컴포넌트 생성
		jf.setSize(400, 300); // 창 크기 지정
		jf.setVisible(true); // 창을 보이게 설정
	}
}

 

간단하게 jf 라는 컴포넌트를 생성한 후 사이즈를 지정(setSize)해주고 보이게끔 설정(setVisible)합니다. JFrame 생성자에 매개변수로 문자열을 주면 응용 프로그램의 타이틀을 설정하실 수 있습니다. 이렇게 기본적인 세 단계로 JFrame을 보이게 해봤습니다.

 

 

또 다르게 JFrame을 생성하는 방법인 상속은 자바에서 서브(자식) 클래스가 슈퍼(부모) 멤버와 메소드를 물려받는다는 점을 이용한 것입니다. extends 키워드로 JFrame을 상속받은 후 실행해보도록 하겠습니다.

import javax.swing.*;

public class JFrameEx {
	public static void main(String[] args) {
		JFrameEx2 j = new JFrameEx2();
	}
}

class JFrameEx2 extends JFrame{
	JFrameEx2() {
		super("JFrame Demo2");
		setSize(200, 300);
		setVisible(true);
	}
}

 

JFrameEx2 라는 클래스가 JFrame 을 상속받아 super() 메소드로 부모 클래스(JFrame)의 생성자에 문자열을 주어 타이틀을 설정한 후 JFrame의 메소드들을 사용하는 모습입니다. 점(.) 키워드 없이 바로 메소드를 사용할 수 있습니다. 조금의 변화점을 주기 위해 사이즈를 변경시켜 봤습니다.

 

 

main 은 종료됐는데도 창은 살아있는 이유

GUI를 만들다보면 이 UI가 계속해서 입력을 받고 그것에 대해 반응하기 위해 loop(반복문)를 물려주는 경우가 있습니다. 근데 오늘 우리가 만든 코드에는 loop문이 없는데도 JFrame은 살아있습니다. 왜냐하면 Swing에서 JFrame 객체가 생성되면 main 스레드 이외에 이벤트 처리(분배) 스레드(Event Dispatch Thread)가 추가 생성되기 때문입니다. 스레드가 분기됐기 때문에 main 함수가 끝났다고 해도(JFrame을 만들고 끝났죠) JFrame 스레드는 살아있기 때문에 계속 창이 떠있을 수 있는 것입니다.

 

창을 껐는데 왜 프로그램이 돌아가나요?

예제를 실행하시면서 또 다른 의문점이 하나 생기셨을 것 같습니다. "왜 창을 닫았는데 자바 프로그램은 계속 실행 중이지?"  이에 대한 답변을 드리자면 닫기 버튼을 눌러 창을 끄면 프로그램이 자동으로 종료된다는 우리의 인식과 달리 응용 프로그램은 '창만 닫은 상태'로 인식하기 때문에 JFrame이 없어지지 않고 스레드는 계속 돌면서 사용자의 입력을 처리하게 됩니다. 따라서 닫기 버튼을 눌렀을 때 프로그램도 같이 종료될 수 있도록 다음과 같이 setDefaultCloseOperation 메소드를 추가적으로 삽입해줘야 합니다.

import javax.swing.*;

public class JFrameEx {
	public static void main(String[] args) {
        JFrame jf = new JFrame("JFrame Demo"); // JFrame 컴포넌트 생성
        jf.setSize(400, 300); // 창 크기 지정
        // 추가된 코드 --------
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // --------------
        jf.setVisible(true); // 창을 보이게 설정
	}
}

 

setDefaultCloseOperation 메소드는 닫기 버튼을 눌렀을 때 어떤 작업을 수행할지 정하는 메소드입니다. 인자로는 아래와 같이 대표적으로 4개가 올 수 있습니다.

JFrame.EXIT_ON_CLOSE 프로그램을 중단합니다.
JFrame.HIDE_ON_CLOSE Frame을 숨깁니다. 하지만 프로그램은 계속 돌아갑니다.
JFrame.DISPOSE_ON_CLOSE Frame을 숨긴 후 파기합니다. 하지만 프로그램은 계속 돌아갑니다.
JFrame.DO_NOTHING_ON_CLOSE 닫기 버튼을 무시합니다. (아무 일도 일어나지 않습니다.)

 

메소드의 기본 인자는 HIDE_ON_CLOSE 입니다. 따라서 창은 닫히지만 프로그램은 돌아가는 것이죠. 따라서 EXIT_ON_CLOSE 를 사용하여 프로그램을 완전히 종료할 수 있습니다.

더보기

추가 정보) 아래에 첨부한 Java JFrame에 대한 영어 원문에 따르면 EXIT_ON_CLOSE 는 JFrame 에 정의되어 있는 반면, 다른 3개의 상수는 WindowConstants 라는 윈도우 상수에 정의되어있습니다. (정확한 의미는 모르겠습니다)

public void setDefaultCloseOperation(int operation)
 
Sets the operation that will happen by default when the user initiates a "close" on this frame. You must specify one of the following choices:
 
  • DO_NOTHING_ON_CLOSE (defined in WindowConstants): Don't do anything; require the program to handle the operation in the windowClosing method of a registered WindowListener object.
  • HIDE_ON_CLOSE (defined in WindowConstants): Automatically hide the frame after invoking any registered WindowListener objects.
  • DISPOSE_ON_CLOSE (defined in WindowConstants): Automatically hide and dispose the frame after invoking any registered WindowListener objects.
  • EXIT_ON_CLOSE (defined in JFrame): Exit the application using the System exit method. Use this only in applications.

The value is set to HIDE_ON_CLOSE by default. Changes to the value of this property cause the firing of a property change event, with property name "defaultCloseOperation".

Note: When the last displayable window within the Java virtual machine (VM) is disposed of, the VM may terminate. See AWT Threading Issues for more information.

Parameters:operation - the operation which should be performed when the user closes the frameThrows:IllegalArgumentException - if defaultCloseOperation value isn't one of the above valid valuesSecurityException - if EXIT_ON_CLOSE has been specified and the SecurityManager will not allow the caller to invoke System.exitSee Also:Window.addWindowListener(java.awt.event.WindowListener), getDefaultCloseOperation(), WindowConstants, Runtime.exit(int)

 

또 다른 방법으로는 System.exit(0); 코드를 실행하면 됩니다. 더 간단하지만 코드를 어딘가에 집어넣어야 하기 때문에 추후에 JButton 과 함께 다뤄보도록 하겠습니다.

 

감사합니다.

 

<참고 문헌>

[왜 setVisible을 마지막에 써야 하는가? - StackOverflow 질문]

https://stackoverflow.com/questions/29722434/why-does-setvisible-remove-my-components