[Java swing] 자바 스윙 4 : 윈도우 빌더 설치, 버튼 누르면 다른 패널로 전환하기(모듈 나누기), 창 닫기
버튼을 누를때 해당 패널을 보이지 않게 하고 다른 패널을 보이게 하는 방법으로 화면 전환을 할 수 있으나 인터넷에 있는 많은 자료들이 하나의 파일에 코드를 쭉 써놨기에 파일별로 코드를 분리했을 때도 이를 수행할 수 있는 방법을 소개한다.
그리고 앞으로는 이클립스 환경을 기준으로 포스팅을 하겠다.
[Eclipse] 자바 스윙( Swing ) / WindowBuilder 설치 방법 (tistory.com)
자바의 windowBuilder를 사용하면 gui구성을 정말 편하게 할 수 있다.
인텔리제이의 swing gui기능은 이클립스에서 지원하는 absolute layout기능을 지원하지 않기 때문에 스윙을 사용하는데 있어서는 이클립스를 사용하는 것이 훨씬 편해보인다. (abslute layout기능은 사용자가 원하는 방향에 컨테이너 배치를 쉽게 할 수 있게 한다.)
먼저 새로운 프로젝트를 만든다.
맨밑에 Create module-info.java 파일을 체크하는 부분이 있는데 저걸 생성하면 JFrame을 import를 못하는 에러가 생기는 경우가 있다. 체크 해제하고 프로젝트를 생성하는 것이 좋고, 실수로 생성을 했다면 그냥 그 파일을 삭제하면 에러가 해결될 것이다.
src - new - Other를 선택한다.
window builder가 스윙을 설치할 때 체크가 되어있었다면 위와같은 경로가 존재할 것이다.
만약 없다면 따로 window builder를 설치하면 된다.
Application Window를 설치하고 Next버튼을 누른다.
App1이라는 이름으로 설정하고 Finish버튼을 누른다.
그러면 화면을 구성하는 코드가 처음부터 쓰여져있는 것을 확인할 수 있다.
밑에 Design버튼을 눌러보자.
폼화면을 쉽게 구성할 수 있는 디자인 창이 나타난다.
초기상태는 Frame하나에 기본패널이 올려져 있는 모습이다.
여기서 패널 하나를 더 만들고 그 위에 버튼을 올려보자.
레이아웃 기능중에 위에서 언급한 Absolute layout 기능을 선택한다.
그리고 getContentPane()을 클릭하면 해당 레이아웃 기능이 적용된다.
Absolute layout기능은 해당 레이아웃 기능이 적용된 패널 위에서 UI의 크기 조정이나 배치를 제한없이 내 마음대로 설정할 수 있도록 한다.
이후에 Containers의 JPanel를 같은방법으로 getContentPane()에 올려주면 오른쪽 폼 화면에 새로운 패널의 크기를 조정할 수 있게 된다.
마우스로 끌어서 폼화면 최대크기에 맞게 설정해주자.
Absolute layout을 새로운 panel에 적용하고 Components의 JButton을 panel에 올린다.
Absolute layout이 설정된 panel위에 버튼이 존재하는 한 버튼의 위치와 크기를 마우스 포인터로 간편하게 조절할 수 있다.
왼쪽에 Properties 테이블을 통해 버튼 객체에 대한 설정을 쉽게 지정할 수 있다.
맨 위의 Variable은 버튼 객체의 변수명을, 아래의 text는 버튼 내 텍스트 값을 지정한다.
각각 btn1, 화면1로 바꾸어 보자.
버튼의 텍스트가 바뀐 것을 확인할 수 있다. 폼화면에서 오른쪽 마우스 - Test/Preview를 클릭하면 폼화면이 어떻게 구성되는지 미리볼 수 있다.
아무런 코드를 따로 적지 않았는데도 디자인 한 그대로 폼화면이 구성되어 있는 것을 확인할 수 있다.
이제 Design옆에 있는 Source버튼을 눌러 소스 코드 창으로 되돌아 가보자.
기존에 없었던 코드가 자동으로 생성되어있음을 확인할 수 있다.
frame위에 getContentPane()패널이, 그위에 panel패널이, 그 위에 btn1 버튼이 올라가있다.
setBounds()메소드는 해당 컴포넌트의 절대 위치와 크기를 지정할 수 있다.
setBounds(x, y, w, h); (x, y좌표의 기준은 왼쪽 위. w, h는 가로, 세로 크기를 지정한다.)
add()메소드로 컴포넌트를 컨테이너에 추가한다.
setLayout(null)은 컨테이너의 배치관리자를 absolute layout으로 지정했을 때 추가되는 코드이다.
아까 각 패널들에 대해 absolute layout으로 레이아웃 설정을 했기에 코드에 반영된 것을 확인할 수 있다.
배치관리자에 대한 자세한 설명은 아래 블로그를 참고하면 좋다.
그냥 window desiner에 의존할거라면 굳이 몰라도 상관없을 듯.
SWING 컨테이너와 배치관리자 : 네이버 블로그 (naver.com)
src 폴더에 대해서 아까와 같은 방법으로 App2폼을 추가로 생성하자.
아까와 같은 방법으로 버튼을 만들고 변수명을 btn2, 버튼 텍스트를 화면2로 지정하고 App1의 소스코드 화면으로 돌아와보자.
App1 패널의 버튼을 클릭하면 App2 화면으로 이동되고, App2 패널의 버튼을 클릭하면 App1 화면으로 이동되게 만들어 보자.
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
App2 a2 = new App2();
a2.setVisible(true);
frame.dispose();
}
});
App2에 대한 객체 a2를 생성하고 setVisible(true) 메소드를 이용해 App2를 화면에 보이도록 한다.
frame.dispose()는 현재화면을 종료시키는 메소드이다.
이대로 코드를 적용하려니 App2에 대한 setVisible 메소드가 정의되지 않아 에러가 발생하므로, App1과 App2가 클래스 자체적으로 JFrame 클래스를 상속받도록 코드를 대대적으로 바꿔보았다.
코드 작성중에 제대로 import되지 않는 문제가 발생하면 ctrl + shift + o를 눌러보자. 자동 import 단축키이다.
App1 코드
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
public class App1 extends JFrame{
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
App1 window = new App1();
window.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public App1() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
setBounds(100, 100, 450, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setLayout(null);
JPanel panel = new JPanel();
panel.setBounds(0, 0, 434, 261);
getContentPane().add(panel);
panel.setLayout(null);
JButton btn1 = new JButton("\uD654\uBA741");
btn1.setBounds(171, 111, 97, 23);
panel.add(btn1);
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
App2 a2 = new App2();
a2.setVisible(true);
dispose();
}
});
}
}
App2 코드
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
public class App2 extends JFrame{
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
App2 window = new App2();
window.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public App2() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
setBounds(100, 100, 450, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setLayout(null);
JPanel panel = new JPanel();
panel.setBounds(0, 0, 434, 261);
getContentPane().add(panel);
panel.setLayout(null);
JButton btn2 = new JButton("\uD654\uBA742");
btn2.setBounds(172, 108, 97, 23);
panel.add(btn2);
btn2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
App1 a1 = new App1();
a1.setVisible(true);
dispose();
}
});
}
}
App2의 버튼을 누르면 App1의 객체를 생성해서 setVisible(true)메소드를 적용하여 화면에 띄우고, App2는 dispose()메소드를 적용해 종료시켰다.
이제 App1을 Run시켜서 의도대로 작동하는지 확인해 보자.
창 전환을 여러가지 방법으로 활용할 수 있다.
화면1 버튼을 누르면 새로운 창으로 App2가 등장하게 하고, 화면2 버튼을 누르면 App2창이 종료되도록 만들 수도 있다.
App1의 버튼 액션 코드를 다음과 같이 변경해보자.
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
App2 a2 = new App2();
a2.setVisible(true);
}
});
App2의 버튼 액션 코드를 이렇게 바꿔보자.
btn2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
});
그런데 App2의 화면이 생성되었을 때 x버튼을 누르면 App1, App2의 화면 모두 종료되어 버린다.
App2의 코드를 다음과 같이 바꾸어보자.
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
public class App2 extends JFrame{
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
App2 window = new App2();
window.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public App2() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
setBounds(100, 100, 450, 300);
setDefaultCloseOperation(DISPOSE_ON_CLOSE); // 변경된 부분
getContentPane().setLayout(null);
JPanel panel = new JPanel();
panel.setBounds(0, 0, 434, 261);
getContentPane().add(panel);
panel.setLayout(null);
JButton btn2 = new JButton("\uD654\uBA742");
btn2.setBounds(172, 108, 97, 23);
panel.add(btn2);
btn2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
}
});
}
}
App1에서는
setDefaultCloseOperation(EXIT_ON_CLOSE);를 적용하여
x를 클릭할때 프로그램이 완전히 종료되도록 했지만,
App2에서는
setDefaultCloseOperation(DISPOSE_ON_CLOSE);를 적용하여
해당 창만 종료되도록 설정을 바꾸었다.
App2의 닫기 창을 눌러도 App1이 종료되지 않는다. App1의 닫기창을 누르면 모든 창이 종료될 것이다.
'JAVA > SWING' 카테고리의 다른 글
[Java swing] 자바 스윙 6 : 컴포넌트 위치 크기 지정 주의 사항 (0) | 2022.05.01 |
---|---|
[Java swing] 자바 스윙 5 : JTable 총정리 (0) | 2022.05.01 |
[Java swing] 자바 스윙 사용법 정리 3 : 로그인 창 구현 (0) | 2022.04.29 |
[Java swing] 자바 스윙 사용법 정리 2 : 버튼 누를 때 프로그램 종료, 문자열 출력하기 (0) | 2022.04.28 |
[Java swing] 자바 스윙 사용법 정리 1 : 창 띄우기, Frame, Panel, Button, Label, TextArea 객체 생성 (0) | 2022.04.28 |