GUI - Graphical User Interface
클라이언트와
문자가 아닌 눈에 보이는 다른 것들로 소통
이제 본격적으로 클라이언트와의 이벤트 처리요소가 새롭게 추가되었다.
기존에는 콘솔에서만 소통했으면, GUI라는 새로운 클라이언트 이벤트가 추가되어
이에 대해서 고려하는 MVC 아키텍처 설계를 진행해야한다.
아예 새로운 MVC 아키텍처가 아닌 여기서 GUI 이벤트 처리를 위한 클래스가 확장된다.
(확장의 확장의 확장)
Event-Driven Programming
사용자 주도로 수시로 발생하는 일을 처리하는 GUI 프로그래밍이다.
Event-handler = Action Listener
액션 이벤트가 발생하기를 기다리고 있다가,
액션 이벤트가 발생하면 처리 (액션 이벤트 예외처리)
Java GUI
사례 학습1. 카운터 해주는 기능 만들기
카운터 기획
시간이
남을 때
기록
할
예
정
코드 구현 | 초기버전으로 구현 - 간이구현
해당 구현은
Model - Frame (Controller & View) 로 구현되었다.
아래의 구현된 코드를 참고하길 바란다.
# CounterModel 클래스
public class Counter {
private int count;
/** Counter - 카운터 초기 설정
* @param start - 카운터의 초기값 */
public Counter(int start) {
count = start;
}
/** increment - 카운터 값 증가 */
public void increment() {
count = count + 1;
}
/** count - 카운터 값 리턴
* @return 카운터 현재 값 */
public int count() {
return count;
}
}
# CounterFrame 클래스 | Controller & View Class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CounterFrame extends JFrame implements ActionListener {
private Counter counter;
private JLabel label = new JLabel("count = 0");
public CounterFrame(Counter c) {
counter = c;
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(label);
JButton button = new JButton("OK");
cp.add(button);
button.addActionListener(this); // 자신을 버튼에 연결 (버튼 이벤트가 발생하면 처리 가능하도록)
setTitle("Counter");
setSize(200,70);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
/** actionPerformed - '버튼 누르기' 액션 이벤트를 처리 */
public void actionPerformed(ActionEvent e) {
counter.increment();
label.setText("count = " + counter.count());
}
}
# CounterStarter 클래스
public class CounterStarter {
public static void main(String[] args) {
Counter model = new Counter(0);
new CounterFrame(model);
}
}
코드 구현 - MVC 구현 | 확장 Ver.1
해당 구현된 바는
Model - Frame (View) - Controller 로 구현되었다.
아래의 구현 코드를 참고하길 바란다.
# CounterModel 클래스
public class Counter {
private int count;
/** Counter - 카운터 초기 설정
* @param start - 카운터의 초기값 */
public Counter(int start) {
count = start;
}
/** increment - 카운터 값 증가 */
public void increment() {
count = count + 1;
}
/** count - 카운터 값 리턴
* @return 카운터 현재 값 */
public int count() {
return count;
}
}
# CounterController 클래스
import java.awt.event.*;
public class CounterController implements ActionListener {
private CounterFrame view;
private Counter model;
public CounterController(Counter m, CounterFrame v) {
view = v;
model = m;
}
/** actionPerformed - '버튼 누르기' 액션 이벤트를 처리 */
public void actionPerformed(ActionEvent e) {
model.increment();
view.update();
}
}
# CounterFrame 클래스 | View Class
import java.awt.*;
import javax.swing.*;
public class CounterFrame extends JFrame {
private Counter counter;
private JLabel label = new JLabel("count = 0");
public CounterFrame(Counter c) {
counter = c;
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(label);
JButton button = new JButton("OK");
cp.add(button);
button.addActionListener(new CounterController(counter, this)); // 자신을 버튼에 연결 (버튼 이벤트가 발생하면 처리 가능하도록)
setTitle("Counter");
setSize(200,70);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
/** update - 뷰 갱신 */
public void update() {
label.setText("count = " + counter.count());
}
}
코드 구현 - 버튼 클래스 분할 | 확장 Ver.2
해당 구현은
Controller에서 버튼 액션을 처리하도록 구현을 했다.
이로써, 독립적인 버튼 (여러 개의 버튼처리)을 구현할 수 있다.
# Counter의 Model {Counter} 클래스
public class Counter {
private int count;
/** Counter - 카운터 초기 설정
* @param start - 카운터의 초기값 */
public Counter(int start) {
count = start;
}
/** increment - 카운터 값 증가 */
public void increment() {
count = count + 1;
}
/** count - 카운터 값 리턴
* @return 카운터 현재 값 */
public int count() {
return count;
}
}
# Counter의 Controller 클래스 {CountButton} 확장 | Button Listener 할당
해당 클래스에서 버튼 액션을 처리하는 작업을 추가하여
여러 개의 버튼을 처리할 수 있도록 만들었다.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CountButton extends JButton implements ActionListener {
private CounterFrame view;
private Counter model;
/** CountButton - 버튼 컨트롤러
* @param label - 버튼에 붙는 라벨
* @param m - 협조할 모델
* @param v - 갱신할 뷰 */
public CountButton(String label, Counter m, CounterFrame v) {
super(label);
view = v;
model = m;
addActionListener(this);
}
/** actionPerformed - '버튼 누르기' 액션 이벤트를 처리
* @param e - 이벤트 */
public void actionPerformed(ActionEvent e) {
model.increment();
view.update();
}
}
# Counter의 Frame 클래스 {CounterFrame} | View Class
import java.awt.*;
import javax.swing.*;
public class CounterFrame extends JFrame {
private Counter counter;
private JLabel label = new JLabel("count = 0");
public CounterFrame(Counter c) {
counter = c;
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(label);
cp.add(new CountButton("OK", counter, this));
setTitle("Counter");
setSize(200,70);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
/** update - 뷰 갱신 */
public void update() {
label.setText("count = " + counter.count());
}
}
Final 코드 구현 - 버튼 추가 & GUI 업데이트
GUI에 대한 MVC 아키텍처 구성은 약간 다른 듯하다.
이에 대해서 추가로 공부해보고,
GUI의 MVC 아키텍처를 더 심도있게 배워보도록 하겠다.
(개발 규칙이니, 완벽한 답이 아닌 좋은 설계 중 하나라고 생각하자.)
# ExitButton 클래스 | Controller 클래스
import java.awt.event.*;
import javax.swing.*;
public class ExitButton extends JButton implements ActionListener {
/** ExitButton - 종료 컨트롤러
* @param label - 버튼에 붙는 라벨 */
public ExitButton(String label) {
super(label);
// 안드로이드에서 onClickListener() 메소드와 동일한 원리
addActionListener(this);
}
/** actionPerformed - '버튼 누르기' 액션 이벤트를 처리
* @param e - 이벤트 */
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
# CountButton 클래스 | Controller 클래스
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CountButton extends JButton implements ActionListener {
private CounterFrame view;
private Counter model;
Drawing panel;
/** CountButton - 버튼 컨트롤러
* @param label - 버튼에 붙는 라벨
* @param m - 협조할 모델
* @param v - 갱신할 뷰 */
public CountButton(String label, Counter m, CounterFrame v, Drawing p) {
super(label);
view = v;
model = m;
panel = p;
addActionListener(this);
}
/** actionPerformed - '버튼 누르기' 액션 이벤트를 처리
* @param e - 이벤트 */
public void actionPerformed(ActionEvent e) {
model.increment();
view.update();
panel.repaint();
}
}
# Drawing 클래스 | View 클래스
import java.awt.*;
import javax.swing.*;
public class Drawing extends JPanel {
private Counter counter;
public Drawing(Counter c) {
counter = c;
setSize(200, 200);
}
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 200, 200);
g.setColor(Color.red);
int x = 0, y = 0;
for (int i = 0; i != counter.count(); i++) {
g.fillOval(x*25, y*25, 20, 20);
x++;
if (x > 7) {
x = 0;
y++;
}
}
}
}
# Frame 클래스 | View Controller 클래스
이 부분에 대해선, MVC에서 어디서 속하는 지 감이 아직안잡힘.
Controller 인 듯한데, MVC 구조가 어떻게 되는 것일까?
해당 클래스에서 Container 를 이용해,
Frame의 Layout을 구성했다. 그리고 Layout과 Panel을 추가해서 하나의 Layout을 구성했다.
(안드로이드의 Layout + Activity 과정을 합친 것,
viewBinding 을 처리한 걸 Java GUI에서는 하나의 클래스에서 Layout + Activity 처리)
import java.awt.*;
import javax.swing.*;
public class CounterFrame extends JFrame {
private Counter counter;
private JLabel label = new JLabel("count = 0");
private Drawing panel;
public CounterFrame(Counter c, Drawing p) {
counter = c;
panel = p;
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel p1 = new JPanel(new FlowLayout());
p1.add(label);
JPanel p2 = new JPanel(new FlowLayout());
p2.add(new CountButton("OK", counter, this));
p2.add(new ExitButton("Exit"));
cp.add(p1, BorderLayout.NORTH);
cp.add(panel, BorderLayout.CENTER);
cp.add(p2,BorderLayout.SOUTH);
setTitle("Counter");
setSize(200,280);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
/** update - 뷰 갱신 */
public void update() {
label.setText("count = " + counter.count());
panel.repaint();
}
}
'CS 대학강의' 카테고리의 다른 글
[CS 1-2 | 시스템 프로그래밍 기초] 함수 포인터 & 포인터 배열 14주차 (0) | 2022.11.08 |
---|---|
[CS 1-2 | 시스템 프로그래밍 기초] 배열 포인터 13주차 (0) | 2022.11.04 |
[CS 1-2 | 대학생을 위한 실용금융] 투자의 정리 8주차 (0) | 2022.11.02 |
[CS 1-2 | 시스템 프로그래밍 기초] 포인터 심화 12주차 (1) | 2022.11.01 |
[CS 1-2 | 프로그램 설계 방법론] Java 인터페이스와 상속 10주차 (0) | 2022.10.27 |