본문 바로가기
공부/java

18일차 복습

by 샤샤샤샤 2022. 12. 8.

GUI 기반 소프트웨어 만들기

GUI(Graphic User Interface)

우리가 흔히 보는 창을 띄워서 버튼을 눌러서 입력하고 x표시를 눌러 화면을 끄는 창(Interface)를 말한다.

 

요즘은 SAAS(서비스형 소프트웨어)라고 해서 대부분 웹 브라우져로 해결할수 있기 때문에 설치 소프트웨어 자체가 사장되어가는 분위기다. 특히 자바같이 연식이 있는 GUI라면 더더욱 그렇다.

 

크게 AWT와 SWING 두개의 방식이 존재한다.

AWT는 저수준의 UI를 지원하며 Frame, Panel을 사용한다. 반대로 향상된 SWING는 고수준의 UI를 지원하며, JFrame, JPnel을 사용한다.

여기서 Frame란 윈도우창 뼈대, Panel이란 컨트롤 컨테이너, 즉 각종 조작 버튼, 입력창 등을 포함한 프레임 안의 작은 프레임이라고 생각하면 된다.

우리는 SWING방식을 알아볼 것이다.

 

먼저 Layout, 배치법에 대해 알아보자.

 

크게 3가지가 존재한다.

1. BorderLayout : 가장 기본적인 형식으로, 상하좌우중앙 5구역으로 나눠 배치하는 방법이다.

2. FlowLayout : 흘러가는대로 배치하는 방식이다.

3. GridLayout : 바둑판 형태로 배치하는 방법이다.

 

GUI생성

import javax.swing.*;

public class Sample extends JFrame {
    public static void main(String[] args) {
        JFrame jf = new JFrame("샘플");  // 생성자함수. 이름 정하기
        jf.setSize(500,500); // 사이즈
        jf.setLocationRelativeTo(null); // 위치값, 중앙정렬
        jf.setDefaultCloseOperation(DISPOSE_ON_CLOSE); // 프로그램을 종료할수 있게 함
        jf.setVisible(true); // 가시화. 안하면 안보임
    }
}

결과

보다시피 아무것도 없는 "샘플"이라는 이름의 창이 화면 중앙에 나왔다. 위치 정보에 대한 값을 입력하지 않았다면 왼쪽 화면 상단에 나왔을 것이다.

setDefaultCloseOperation (DISPOSE_ON_CLOSE); : 화면을 끄면 백그라운드에서 실행되지 않고 완전히 프로그램이                                                                                              종료되게끔 한다.

setVisible( true ) : true값을 주지 않으면 화면이 보이지 않게 된다. 이때 보이지 않는다고 실행되고 있는 것이 아니라, 일정                               시간이 지나면 저절로 프로그램이 종료된다.

 

이것이 기본적인 화면을 만드는 방법이다. 이제 여기에 버튼과 출력문 화면을 만들어보자.

 

 

import javax.swing.*;
import java.awt.*;

public class Sample extends JFrame {
    static JFrame text = null;
    public Sample (String title){
        super(title);
        setSize(500,500);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setVisible(true);
        setLayout( new BorderLayout() );
        JPanel panel = new JPanel(); // 컨테이너 패널 생성
        JButton btn = new JButton("버튼"); // "버튼"이라는 버튼 생성
        panel.add(btn); // 패널에 버튼 추기
        add(panel); // 패널을 창에 추가
    }

    public static void main(String[] args) {
        new Sample("샘플");
    }
}

결과

JPanel : 패널을 만드는 클래스.

JButton : 버튼을 만드는 클래스. 생성자 매개변수에 버튼 이름을 넣을수 있다.

 

보다시피 클래스 이름과 함수 이름을 같게 한것을 알 수 있다.

Smple 함수가 생성자 함수이기 때문이다. 생성자 함수로 ui를 만든 것이다.

 

이제 문자 입출력창을 만들어보자.

BorderLayout 형태로 만든 만큼 위쪽(북쪽) 에다가 만들 것이다.

import javax.swing.*;
import java.awt.*;

public class Sample extends JFrame {
    public Sample (String title) {
        super(title);
        setSize(500, 500);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setVisible(true);
        setLayout( new BorderLayout() );
        JPanel panel = new JPanel(); // 버튼을 넣기 위한 패널 생성
        JButton btn = new JButton("버튼"); // "버튼"이라는 버튼 생성
        panel.add(btn);
        add(panel, BorderLayout.SOUTH);

        textField = new JTextField();
        textField.setFont(new Font("Arial", Font.PLAIN, 40)); // 글꼴, 타입(굵게 등), 크기 설정
        textField.setForeground(new Color(100,100,255));//글자색
        add(textField, BorderLayout.NORTH);
    }

    public static void main(String[] args) {
        Sample sam = new Sample("샘플");
        sam.setVisible(true); // 객체에 따로 설정하지 않으면 문자열 출력 안됨
    }
}

 

여기서 주의할 것은 setVisible() 함수는, 메소드 자체에 성질을 부여하는 것이 아니라 실행문이라는 것이다. 따라서 이보다 위에 쓰여진 코드들만 가시화가 되고, setVisible보다 아래에 있는 코드는 보이지 않게 된다. 이를 유의하자.

 

이제 버튼을 누르면 어떤 동작을 수행하게끔 해보자.

이를 위해서는 ActionListener인터페이스를 불러와 오버라이딩을 해야 한다.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Sample extends JFrame {
    static JTextField textField = null;
    public Sample (String title) {
        super(title);
        setSize(500, 500);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setVisible(true);
        setLayout( new BorderLayout() );
        JPanel panel = new JPanel(); // 버튼을 넣기 위한 패널 생성
        JButton btn = new JButton("버튼"); // "버튼"이라는 버튼 생성
        panel.add(btn);
        add(panel, BorderLayout.SOUTH);

        textField = new JTextField();
        textField.setFont(new Font("Arial", Font.PLAIN, 40));
        textField.setForeground(new Color(100, 100, 100));
        add(textField, BorderLayout.NORTH);

        textField = new JTextField();
        textField.setFont(new Font("Arial", Font.PLAIN, 40));
        textField.setForeground(new Color(100,100,255));//글자색
        add(textField, BorderLayout.NORTH);

        ActionListener al = new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                JButton btn = (JButton)e.getSource(); // e는 현재 발생하고 있는 이벤트. 즉, 버튼을 누를때 그 이벤트가 어떤 이벤트인지
                String btnText = btn.getText();       // 기록된다. 만약 1번과 2번 버튼이 존재하고 1번 버튼을 누른다면, 그 버튼의/
                if( btnText.equals("버튼") ) {         // 모든 속성이 불러와진다.
                    System.out.println("버튼이 눌릴때 실행되는 문장");
                }
                //문자열을 설정하고
                textField.setText( btnText + "Pressed...");
                //문자열 가져오기
                System.out.println( textField.getText() );
            }
        };
        btn.addActionListener( al ); // ActionLinstener 인터페이스에 오버라이딩된 실행문을
    }                                // 실행한다.

    public static void main(String[] args) {
        Sample sam = new Sample("샘플");
        sam.setVisible(true);
    }
}

결과

한글이여서 깨져 보인다.

ActionListener al = new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                JButton btn = (JButton)e.getSource(); // e는 현재 발생하고 있는 이벤트. 즉, 버튼을 누를때 그 이벤트가 어떤 이벤트인지
                String btnText = btn.getText();       // 기록된다. 만약 1번과 2번 버튼이 존재하고 1번 버튼을 누른다면, 그 버튼의/
                if( btnText.equals("버튼") ) {         // 모든 속성이 불러와진다.
                    System.out.println("버튼이 눌릴때 실행되는 문장");
                }
                //문자열을 설정하고
                textField.setText( btnText + "Pressed...");
                //문자열 가져오기
                System.out.println( textField.getText() );
            }
        };
        btn.addActionListener( al ); // ActionLinstener 인터페이스에 오버라이딩된 실행문을
    }                                // 실행한다.

새롭게 추가된 위의 코드만 따로 봐보자.

일단 ActionListener 인터페이스를, 버튼이 눌릴때 실행하고 싶은 실행문으로 오버라이딩한다. 그리고 그것을 버튼이 눌릴때 코드가 실행되도록 addActionListener() 함수로 추가해준다.

어떤 이벤트(버튼, 숫자 입력 등)에 대응되는 코드를 리스너(Listener)이라고 한다.

 

여기서 어려운 것은 

JButton btn = (JButton) e.getsource();

이 코드일것이다.

 

여기서 매개변수로 받는 ActionEvent e는 현재 발생하고 있는 이벤트를 말한다. 그리고 e.getSource() 함수는, e라는 이벤트가 발생할때, 이 이벤트의 모든 속성을 가져온다. 버튼이 눌릴때 그 버튼의 이름, 폰트 등 그 행동의 모든 정보를 가져오는 것이다. JButton 으로 타입이 정해졌기 때문에 버튼이 눌릴때 발생하는 일을 말한다.

 

따라서

btn.addActonListener (al);

이 문장은 어떤 버튼이 눌릴때, 그 버튼의 모든 정보를 받아와 그에 맞춰 인터페이스 ActionListener의 오버라이딩된 수행문을 실행하는 것이다.

 

버튼의 다량 생성

  JPanel panel = new JPanel( new GridLayout(4,4) ); // 패널 크기 지정
        String[] buttons = {"7","8","9","+",
                            "4","5","6","-",
                            "1","2","3","*",
                            "0","C","=","/", };

for( String button : buttons ){ // 향상된 for문을 이용해 개별적으로 문자열형으로 만듬
            JButton btn = new JButton(button); //타이틀설정
            btn.setFont(new Font("Arial", Font.PLAIN, 30));
            btn.addActionListener(al); // 버튼이 눌릴때 al의 수행문이 실행되도록 하는 코드
            panel.add( btn ); // 패널에 버튼 더하기
        }
        add(panel, BorderLayout.CENTER);

for 문을 이용해 생성한다. 전체 코드는 아래와 같다.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Sample extends JFrame {
    static JTextField textField = null;
    public Sample (String title) {
        super(title);
        setSize(500, 500);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setVisible(true);
        setLayout( new BorderLayout() );

        textField = new JTextField();
        textField.setFont(new Font("Arial", Font.PLAIN, 40));
        textField.setForeground(new Color(100, 100, 100));
        add(textField, BorderLayout.NORTH);

        textField = new JTextField();
        textField.setFont(new Font("Arial", Font.PLAIN, 40));
        textField.setForeground(new Color(100,100,255));//글자색
        add(textField, BorderLayout.NORTH);

        JPanel panel = new JPanel( new GridLayout(4,4) ); // 패널 크기 지정
        String[] buttons = {"7","8","9","+",
                "4","5","6","-",
                "1","2","3","*",
                "0","C","=","/", };



        ActionListener al = new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                JButton btn = (JButton)e.getSource(); // e는 현재 발생하고 있는 이벤트. 즉, 버튼을 누를때 그 이벤트가 어떤 이벤트인지
                btn.getFont();                       // 기록된다. 만약 1번과 2번 버튼이 존재하고 1번 버튼을 누른다면, 그 버튼의
                textField.setText( "Pressed...");    // 모든 속성이 불러와진다.
                //문자열 가져오기
                System.out.println( textField.getText() );
            }
        };

        for( String button : buttons ){
            JButton btn = new JButton(button); //타이틀설정
            btn.setFont(new Font("Arial", Font.PLAIN, 30));
            btn.addActionListener(al); 
            panel.add( btn );
        }
        add(panel, BorderLayout.CENTER);
    }

    public static void main(String[] args) {
        Sample sam = new Sample("샘플");
        sam.setVisible(true);
    }

결과

 

이를 이용해 만든 계산기 코드를 첨부하겠다.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

//자바에서 GUI기반 앱 만들기
//Graphic User Interface
//AWT,SWING 클래스 사용(JAVA FX은 사용안함)
//AWT : 저수준의 UI지원, Frame, Panel
//SWING : 고수준의 UI지원, JFrame, JPanel
//Frame : 윈도우창 뼈대
//Panel : 컨트롤를 감싸놓은 것(컨테이너)
//Layout : 배치하는 방법
// 1. BoderLayout : 기본레이아웃, 상하좌우중앙에 배치
// 2. FlowLayout : 흘러가는대로 배치
// 3. GridLayout : 바둑판모양 배치
public class Calculator extends JFrame {
    static JTextField textField = null;

    public Calculator(String title){
        super(title);
        //Frame 설정
        setSize(500, 500); //프레임 크기
        setLocationRelativeTo(null); //프레임 화면위치 가운데
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);//프로그램 종료버튼 활성화

        setLayout(new BorderLayout());//보더레이아웃으로 설정

        //윗쪽(NORTH) UI 만들기
        //TextField : 문자입력창(문자출력)
        textField = new JTextField();
        textField.setFont(new Font("Arial", Font.PLAIN, 40));
        textField.setForeground(new Color(100,100,255));//글자색
        add(textField, BorderLayout.NORTH);
        //가운데(CENTER) UI 만들기
        //그리드레이아웃이 들어가는 공간(컨테이너)을 만들어줌.
        JPanel panel = new JPanel( new GridLayout(4,4) );
        String[] buttons = {"7","8","9","+",
                            "4","5","6","-",
                            "1","2","3","*",
                            "0","C","=","/", };

        ActionListener al = new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                //System.out.println("버튼이 클릭되었습니다.");
                //버튼이 눌렸을때, 눌린 버튼 객체를 가져오기
                JButton btn = (JButton)e.getSource();
                String btnText = btn.getText();
                System.out.println( btnText );
                if( btnText.equals("1") ) {
                    System.out.println("1입니다.");
                }
                //문자열을 설정하고
                textField.setText( btnText + "Pressed...");
                //문자열 가져오기
                System.out.println( textField.getText() );
            }
        };

        //JButton을 만들어서 Panel에 추가한다.
        for( String button : buttons ){
            JButton btn = new JButton(button); //타이틀설정
            btn.setFont(new Font("Arial", Font.PLAIN, 30));
            //각버튼에 이벤트(마우스클릭)처리 코드를 추가한다.
            //이벤트 대응 코드를 리스너(Listener)라고 한다.
            //ActionListener 인터페이스의 구현객체를 넣어준다.
            btn.addActionListener(al); //this는 Calculator클래스를 의미
            panel.add( btn );
        }
        add(panel, BorderLayout.CENTER);
    }
    public static void main(String[] args) {
        Calculator calc = new Calculator("계산기");
        calc.setVisible(true);
    }
}

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

public class Calculator extends JFrame {
    static JTextField textField = null;
    static String collector = "";

    public Calculator(String title) {
        super(title);
        //Frame 설정
        setSize(500, 500); //프레임 크기
        setLocationRelativeTo(null); //프레임 화면위치 가운데
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);//프로그램 종료버튼 활성화

        setLayout(new BorderLayout());//보더레이아웃으로 설정

        textField = new JTextField();
        textField.setFont(new Font("D2Coding", Font.PLAIN, 40));
        textField.setForeground(new Color(100, 100, 255));//글자색
        add(textField, BorderLayout.NORTH);
        //가운데(CENTER) UI 만들기
        //그리드레이아웃이 들어가는 공간(컨테이너)을 만들어줌.
        JPanel panel = new JPanel(new GridLayout(4, 4));
        String[] buttons = {"7", "8", "9", "+",
                "4", "5", "6", "-",
                "1", "2", "3", "*",
                "0", "C", "=", "/",};
        ActionListener al = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //System.out.println("버튼이 클릭되었습니다.");
                //버튼이 눌렸을때, 눌린 버튼 객체를 가져오기
                JButton btn = (JButton) e.getSource();
                String btnText = btn.getText();
                collector += btnText + " ";

                String[] array = collector.split(" ");
                ArrayList<String> list = new ArrayList<>();
                for (int i = 0; i < array.length; i++) {
                    list.add(array[i]);
                }
                if (btnText.equals("C")) {
                    collector = "";
                    textField.setText(collector);
                }
                System.out.println(collector);

                for (int i = list.size()-1; i >0 ; i--) { // 연산부호를 i로 두는 로직
                    if (list.size() > 1) {
                    if (list.get(i).matches("-?\\d+")) {
                            if (list.get(i - 1).matches("-?\\d+")) {
                                list.set(i - 1, list.get(i - 1) + list.get(i));
                                list.remove(i);
                            }
                        }
                    }
                }
                textField.setText(collector);
                if (btnText.equals("=")) {
                    loop1:
                    for (; ; ) { // i-1과 i+1을 연산부호 맞게 연산하고 그 값을 i-1에 저장. i와 i+1은 삭제
                        for (int i = 1; i < list.size() - 1; i++) {
                            if (list.get(i).equals("*")) {
                                list.set(i - 1, String.valueOf(Integer.valueOf(list.get(i - 1)) * Integer.valueOf(list.get(i + 1))));
                                list.remove(i + 1); 
                                list.remove(i);
                                textField.setText(list.get(0));
                                System.out.println(list.get(0));
                                continue;
                            }
                            if (list.get(i).equals("/")) {
                                list.set(i - 1, String.valueOf(Integer.valueOf(list.get(i - 1)) / Integer.valueOf(list.get(i + 1))));
                                list.remove(i + 1);
                                list.remove(i);
                                textField.setText(list.get(0));
                                System.out.println(list.get(0));
                                continue;
                            }
                            if (list.get(i).equals("+")) {
                                list.set(i - 1, String.valueOf(Integer.valueOf(list.get(i - 1)) + Integer.valueOf(list.get(i + 1))));
                                list.remove(i + 1);
                                list.remove(i);
                                textField.setText(list.get(0));
                                System.out.println(list.get(0));
                                continue;
                            }
                            if (list.get(i).equals("-")) {
                                list.set(i - 1, String.valueOf(Integer.valueOf(list.get(i - 1)) - Integer.valueOf(list.get(i + 1))));
                                list.remove(i + 1);
                                list.remove(i);
                                textField.setText(list.get(0));
                                System.out.println(list.get(0));
                                continue;
                            }
                        }
                        if (list.size() <= 2) { // 리스트가 2, 즉 = 과 숫자 결과만 남을때까지 반복
                            collector = "";
                            break loop1;
                        }
                    }
                }
            }
        };
        //JButton을 만들어서 Panel에 추가한다.
        for (String button : buttons) {
            JButton btn = new JButton(button); //타이틀설정
            btn.setFont(new Font("D2Coding", Font.PLAIN, 30));
            btn.addActionListener(al); 
            panel.add(btn);
        }
        add(panel, BorderLayout.CENTER);
    }
    public static void main(String[] args) {
        Calculator calc = new Calculator("계산기");
        calc.setVisible(true);
    }
}

정말 힘들었다....

2자리수 이상의 숫자를 계산하기 위해, 입력된 값이 정수형인지 판별하기 위한 정규식을 사용했다.

list.get(i).matches("-?\\d+")

 

'공부 > java' 카테고리의 다른 글

자바(java)의 출력 함수  (0) 2023.01.22
19일차  (0) 2022.12.08
16-17일 통신  (0) 2022.12.06
16일차 복습  (0) 2022.12.06
15일차 복습  (0) 2022.12.04