자바 프로그래밍

자바 스윙 첫번째 예제 - 업다운카운터

plas 2020. 10. 16. 21:58

업다운 버튼과 숫자 편집창, 그리고 기록을 누적하여 기록하는 다음과 같은 프로그램을 만들어 보자. 

이 프로그램은 다음과 같은 기능을 가진다.

  • 업 다운 버튼으로 상단 편집창의 숫자를 증가 또는 감소시킨다
  • RECORD 버튼으로 편집창의 숫자를 하단의 기록창에 누적하여 덧붙인다.
  • 업 다운 버튼이 눌려질 때마다 상단의 배경색을 랜덤하게 바꾸어 준다.

이런 기능을 구현하기 위해 필요한 단계를 차례로 살펴본다.

화면 구성 (레이아웃)

자바 스윙에서는 화면 구성이 좀 번거로운 점이 있다. 이것을 화면 빌더 같은 툴을 이용하여 설계하면 편리하지만, 간단한 화면 구성은 작성할 수 있으면 코드도 깔끔하고 유지보수가 쉽다.

위의 화면은 상단(편집창), 중간(버튼 세개), 하단(라벨로 텍스트 여러 줄 보여줌)으로 구성된다. 각각은 JPanel로 contentPane에 붙여지는데 각 패널 안에 컴포넌트가 들어가는 형태가 된다. 이 때 주의할 점은 패널과 컴포넌트를 모두 필드로 선언할 필요는 없다는 점이다. 구성하는 부분에서 지역변수로 사용해도 생성하고 붙이고 리스너 다는 등을 하나의 함수에서 할 수 있으면 충분하다. 그러나 두 개 이상의 메소드에서 쓰여야 하는 컴포넌트는 필드로 선언해야 한다. 대표적인 것이 액션 리스너에서 사용자 액션에 따라 값이나 상태를 바꾸어야 하는 것들이다. 여기서는 상단의 텍스트창, 상단의 배경 패널, 하단의 라벨 등이 변수로 선언되어야 하는 것들이다.

actionPerformed에서 버튼을 접근해야 되지만 그런 버튼을 필드로 선언할 필요는 없다. 왜냐하면 액션 이벤트가 어떤 컴포넌트가 발생시킨 것인지 getSource()를 통해 알려주므로 판별이 가능하다. 이 프로그램은 JFrame을 상속한 클래스가 메인 함수가 되면 된다.

public class UpDownFrame extends JFrame {
	private static final long serialVersionUID = 1L;
	JTextField resultTF = new JTextField("0", 20);
	JPanel top = new JPanel();
	JLabel bottomLabel = new JLabel("<html>카운트 업&다운 기록<br>");

JLabel에 보여질 텍스트를 여러 줄로 하고 싶을 때는 <html> 태그와 <br>을 이용해야 한다.

이 클래스의 메인 함수와 프로그램의 구동부는 다음과 같이 작성할 수 있다.

    private void createAndShowGUI() {   
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        addComponentsToPane();
	// 컴포넌트 크기를 설정하는 방법
    	setPreferredSize(new Dimension(300, 300));
        pack();
        setVisible(true);
    }
    public static void main(String[] args) {
    	UpDownFrame frame = new UpDownFrame();
        frame.createAndShowGUI();
    }

그럼 화면을 구성하는 대부분의 코드는 addComponentsToPane() 메소드에서 담당하게 된다. 이 부분은 JPanel 만들어서 버튼이나 컴포넌트 넣고 그 패널을 contentPane에 넣는 작업의 반복이다. 지루한 작업이기는 하지만 레이아웃을 적당히 설정해서 넣어주면 별 어려움 없이 화면을 구성할 수 있다.  BorderLayout을 쓰면 거의 실패하지 않고 만들 수 있다.

여기서 버튼에 액션 리스너를 다는 부분을 살펴보자. 흔히 actionPerformed는 여러 컴포넌트들 상태를 바꾸거나 이것저것 사용해야 할 일이 생기므로 액션 리스너는 내부 클래스로 만드는 것이 좋다.

	ActionListener listener = new ButtonListener();
	up.addActionListener(listener);
	down.addActionListener(listener);
	...
    }
    class ButtonListener implements ActionListener {
    	@Override
    	public void actionPerformed(ActionEvent e) {
    		// TODO Auto-generated method stub
    		String buttonName = e.getActionCommand();
    		int result = Integer.parseInt(resultTF.getText());
    		if (buttonName.equals("UP"))
    			result++;
    		else if (buttonName.equals("DOWN"))
    			result--;
    		resultTF.setText(""+result);
    		setPaneColor();
    	}
    }

setPaneColor() 메소드는 top 패널의 배경색을 랜덤하게 바꾸는 역할을 한다.

    void setPaneColor() {  // 랜덤하게 배경색을 바꾼다
    	top.setBackground(new Color((int)(Math.random() * 255), 
    			(int)(Math.random() * 255), (int)(Math.random() * 255)));
    }

다음은 RECORD 버튼의 핸들러 처리다. 이것은 버튼 한 개만 처리하면 되므로 무명클래스로 만들어준다.

		reset.addActionListener(new ActionListener() {
		    // RECORD 버튼의 리스너, 무명클래스로 구현
		    public void actionPerformed(ActionEvent e) {
		    	int current = Integer.parseInt(resultTF.getText());
		    	String recodLine = String.format("<br>[%d] %d (%+d)", 
		    					count++, current, current - last);
		    	last = current;
		    	bottomLabel.setText(bottomLabel.getText() + recodLine);
		    }
		});	

여기서 직전 값과의 증감값을 표시하기 위해 직전값을 필드로가져야 한다. 또한 count를 회수 증가시키면서 표시하기 위해 필드로 선언해야 한다. 

이상의 프로그램을 완성한 파일은 다음과 같다.

UpDownFrame.java
0.00MB