실습 과제 풀이.

우리가 흔히 프로그램을 설치 또는 특정 작업을 컴퓨터가 처리 할 때 몇 퍼센트 정도 진행이 됐는지 알 수 있도록 하기 위해서 위와 같이 JProgressBar(JProgressBar는 자바에서 불리우는 명칭이자 클래스 입니다.)를 이용합니다.

위에 보이는 그림은 참으로 단순하기 그지 없는 JProgressBar 실습예제입니다. 그러나..

실습 과정에서 약간의 문제가 발생하는 부분이 있어서 해설편을 이렇게 준비를 했습니다.

그럼 하나 하나 알아보도록 합시다.
일단 위에 보이는대로 인터페이스를 완성합니다.
그리고 각 버튼에 이벤트를 정해주고 실행을 합니다.

문제가 되는 부분은 여기 부터 입니다. 캡쳐가 없어서 보여드리지는 못하지만 다음의 문제가 발생하는 경우 잘 봐두셔야 합니다.
증가 버튼을 누르면 버튼이 눌린 상태로 다운 먹은 듯한 현상이 잠시 일어난 뒤에 바의 색이 전부 파랗게 차 있다.

이런 문제가 발생했다면 해결 방법은 다음과 같습니다.

이벤트 버튼에 직접 JProgressBar 객체에 상태를 변화시키는 코딩을 했기 때문에 발생하는 문제입니다.

왜? 그렇게 코딩을 하면 안되느냐?
이는 멀티쓰레딩과도 같은 효과를 바라는 것이기 때문에 문제가 되는 것입니다.

우리는 메인 메소드를 통해서 프로그램을 동작시킵니다.
그 말은 현재 프로그램은 메인메소드가 동작중이라는 말이 되지요.

그러나 이벤트리스너를 적용시켰다면 버튼을 눌렀을 때는 이벤트가 발생합니다.
이벤트는 하나의 메소드가 실행되는 것이지요..

그럼 당연히 메인메소드는 잠시 중단이 되고 이벤트 메소드가 실행됩니다.
그래서 화면이 멈춰 있는 듯한 현상이 일어나는 것입니다.

약간의 해설을 더 하자면 완성된 인터페이스가 보여지는 것은 메인메소드에서 실행되기 때문입니다.
이벤트리스너는 단순히 이벤트 메소드를 실행하는 것입니다.(이래도 어렵다면 그림을 그리세요)

이를 해결 하는 방법은 두가지 방법이 존재합니다.
1. 멀티쓰레드를 이용한다.
2. 이벤트가 메인메소드에서 실행돼야 한다.

이 두가지 방법을 보면 멀티쓰레드를 사용할 줄 안다면 1번이 더 쉽다고 느껴질 수 있습니다. 그러나 멀티쓰레드로 해결하지는 않겠습니다. 멀티 쓰레드로 한다면 약간의 문제의 소지가 더 있기 때문에 2번으로 해결하겠습니다.

메인메소드에서 이벤트가 실행돼야 한다.
어떻게 할까요? 이벤트 메소드를 메인 안에서 해결한다는 것은 메인 메소드 안에서 무명 클래스 또는 기타 여러가지 방법을 이용해야 하지 않을까 하는 생각이 들 수도 있습니다. 그렇다면 변수의 접근할 수 있는 권한 설정이 바껴야 한다는 점도 있을 수 있고 여러가지 귀찮은 상황이 일어날 수 있습니다.

그래서 아주 간단하게 해결 하도록 하겠습니다.

일단 버튼을 클릭해서 실행 했을 때 JProgressBar 객체의 상태 변화를 주지는 않겠습니다.
단순히
증가는 증가 스위치, 감소는 감소 스위치, 정지는 정지 스위치
이렇게 변수를 지정해서 사용하겠습니다.
그럼 버튼을 클릭하면 메인은 아주 찰나의 시간 동안 멈추고 이벤트를 처리하고 다시 메인으로 돌아옵니다.
그럼 메인에서 스위치에 따라 동작을 하도록 하면 됩니다.

메인에서 직접 짜도 되고 메소드를 메인에서 실행 하는 방법을 취하면 됩니다.
이는 아주 간단하게 이해 할 수 있도록 소스롤 보는쪽으로 합시다.
 public void progressBar() {
  try {
   while (true) { // 루프는 무한으로 돌아야 한다.
    while (state == PLUS) { // state 변수의 변화에 따라 루프문을 실행한다.
     Thread.sleep(50); //잠시 쉰다.
     jpb.setValue(index); // JProgressBar 객체에 값을 변화 시킨다.
     label.setText("현재상태 : " + index + "%");
     if (index < 100) {
      index++;
     }

    }
    while (state == MINUS) {
     Thread.sleep(50);
     jpb.setValue(index);
     label.setText("현재상태 : " + index + "%");
     if (index > 0) {
      index--;
     }
    }
    while (state == STOP) {
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

PLUS, MINUS, STOP는 final 변수이고 state가 액션리스터 메소드에서 값을 변화합니다.
 private final int PLUS = 1;
 private final int STOP = 0;
 private final int MINUS = 2;
 private int state = 0;

그리고 메인메소드에서 이 루프문이 들어 있는 메소드를 실행하면 메인에서 동작하는 것이기에 다운 된 듯한 현상을 깔끔히 해결 할 수 있습니다.
 public static void main(String[] args){
  Exam1102 ex = new Exam1102();
  ex.progressBar();

 }

전체 소스는 아래 파일을 참고 하세요.
Exam1102.java 

그리고 아까 잠시 이야기 했던 멀티쓰레드를 이용하는 방법에 대해서 이야기 합시다.

이 문제가 발생할 수 있는 이유는 다음과 같습니다.
처음 이벤트를 실행 할 때는 전혀 문제가 되지 않습니다. 그러나 문제는 그 이후부터 발생합니다.
멀티쓰레드를 이용하기 위해서는 약간의 조건이 붙는데 한번 실행 된 메소드는 다시 실행이 불가능합니다.
다시 실행을 하려면 객체를 다시 만들어야 한다는 점이지요.
메소드의 재활용이 불가능하다.(?) 라고 할 수 있습니다.
그렇다면 매번 버튼이 눌러질 떄 마다 객체를 새로 생성해야 한다는 것이 문제가 되지요.
어떻게든 잘만 코딩을 한다면 이 문제점을 해결 할수도 있다고 보는데 일단은 효율적인 면에서 떨어진다고 봅니다.
너무 어려운 길을 돌아서 가는 방법이기 때문이지요.
자바를 이해하고 연구 분석을 하기에는 괜찮은 방법일지는 모르겠지만 얻는 것보다 손해 보는 것이 더 많다고 판단 되기 때문에 이 방법은 추천하지 않습니다.

그럼 이번 글은 여기서 마치도록 하겠습니다.

멀티쓰레드에 관한 정보는 아직 부족한 것이 많으니 보충 설명은 댓글을 달아주세요 ^^;

by 만성피로 | 2008/11/03 21:49 | 정리할 자료들 | 트랙백 | 덧글(1)

트랙백 주소 : http://maydaisy.egloos.com/tb/1049116
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by 김교수 at 2008/11/07 16:06
잘 이해하고 있군요. 설명도 좋습니다.

다만 설명상에 조금 확실하게 하고 싶은 부분은....이벤트처리를 메인안에 둔다하더라도 (즉, 내부무명클래스로 만든다고 하더라도), 이벤트처리는 별도 쓰레드로 돌아간다는 것입니다.^^

:         :

:

비공개 덧글

◀ 이전 페이지다음 페이지 ▶