달력

42024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
나만의 자바 컴포넌트를 만들자
eapoeash (2004-03-22 17:40:14)

저자: 김영익 / (주)콘텔라


자바 프로그래머라면 당연히 AWT나 Swing 컴포넌트에 대해서 알고 있고 GUI를 위해서 여러 형태의 컴포넌트들을 조합해서 원하는 화면을 만들어 보았을 것이다. 그러나 때로는 JDK 에서 지원하는 표준 컴포넌트들만으로는 무엇인가 부족함을 느껴 본적은 없는가? 자신의 입맛에 딱 맞는 컴포넌트가 없어서 오랜 시간을 허비하거나 고생해본 경험이 있을 수도 있다. 이번 기사에서는 자신만의 간단한 컴포넌트를 작성해보기로 하자.


1. 이렇게 만들어 주세요~~~

필자가 작년에 수행했던 프로젝트 중에 이런 기능을 넣어 달라는 요구 사항이 있었다.
“유닉스 시스템의 CPU, 메모리, 파일 시스템의 상태를 감시하는 기능을 챠트를 이용해서 보기 좋게 넣어달라” 요구 사항 자체는 간단했지만 챠트를 만들기 위해서는 상당한 노력이 필요하기 때문에 다른 라이브러리를 사용하기로 결정했다. 비용 절감을 위해 “JFreeChart” 라는 오픈 소스 프로젝트를 사용해서 챠트 문제를 해결했지만 한가지 남은 문제가 있었다.
CPU의 상태를 윈도우의 작업 관리자에서 보이는 형태처럼 만들어 달라는 것이었다.

null


JProgressBar를 사용하면 비슷한 형태가 나오기는 하지만 아무래도 많이 다르다는 느낌이 들어서 직접 만들어서 사용하기로 결정했다. 최종적으로 구현된 결과는 아래 화면을 참고하자.



원래 이 컴포넌트만 단독으로 보여 주는 것은 아니었고 다른 그래프들과 함께 프레임에 포함된 것이었다. JFreeChart로 그려진 그래프도 구경할 겸해서 아래 그림도 첨가한다.




2. 주요 구현 설명

일반적으로 자바 컴포넌트를 만들기 위해서 Sun 에서는 자바 빈즈 컴포넌트 명세를 따르기를 권고한다. 그러나 지침대로 모든 사항을 맞추기에는 시간과 노력이 너무 많이 들기 때문에 최대한 간단하게 원하는 기능만을 수행하도록 작성 해보도록 하자.

소스의 양도 그리 길지 않고 어려운 부분도 없으므로 소스에 삽입된 주석만을 주의 깊게 살펴보면 된다.

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

public class PmTickChartPanel extends JPanel {
  BorderLayout borderLayout1 = new BorderLayout();
  JPanel centerPanel = new JPanel();
  JPanel southPanel = new JPanel();
  JPanel northPanel = new JPanel();
  JLabel dataLabel = new JLabel();
  GridLayout gridLayout1 = new GridLayout();
  BorderLayout borderLayout2 = new BorderLayout();
  JLabel titleLabel = new JLabel();
  BorderLayout borderLayout3 = new BorderLayout();
  JPanel westPanel = new JPanel();
  JPanel eastPanel = new JPanel();

  // 편의상 눈금은 10개만 보이고 색상 변경도 10 단위로만
  int tickCount = 10;

  Border centerPanelBorder;
  private Border border1;

  public PmTickChartPanel() {
    try {
      jbInit();
    } catch (Exception e) {
      e.printStackTrace();
   }
  }

  private void jbInit() throws Exception {
    centerPanelBorder = BorderFactory.createLineBorder(Color.green, 1);
    border1 = BorderFactory.createBevelBorder(BevelBorder.LOWERED, new Color(4, 4, 4), new Color(3, 3, 3), Color.black, Color.black);
    this.setBackground(Color.black);
    this.setForeground(Color.green);
    this.setBorder(border1);
    this.setLayout(borderLayout1);
    centerPanel.setBackground(Color.black);
    centerPanel.setFont(new java.awt.Font("Dialog", 0, 12));
    centerPanel.setForeground(Color.green);
    centerPanel.setBorder(centerPanelBorder);
    centerPanel.setLayout(gridLayout1);
    southPanel.setBackground(Color.black);
    southPanel.setForeground(Color.green);
    southPanel.setLayout(borderLayout2);
    northPanel.setBackground(Color.black);
    northPanel.setForeground(Color.green);
    northPanel.setLayout(borderLayout3);
    dataLabel.setBackground(Color.black);
    dataLabel.setFont(new java.awt.Font("Dialog", 1, 12));
    dataLabel.setForeground(Color.green);
    dataLabel.setHorizontalAlignment(SwingConstants.CENTER);
    dataLabel.setHorizontalTextPosition(SwingConstants.CENTER);
    dataLabel.setText("");
    titleLabel.setBackground(Color.black);
    titleLabel.setFont(new java.awt.Font("Dialog", 1, 12));
    titleLabel.setForeground(Color.green);
    titleLabel.setHorizontalAlignment(SwingConstants.CENTER);
    titleLabel.setHorizontalTextPosition(SwingConstants.CENTER);
    this.titleLabel.setText("CPU");
    gridLayout1.setColumns(1);
    gridLayout1.setRows(tickCount);
    gridLayout1.setHgap(1);
    gridLayout1.setVgap(1);
    eastPanel.setBackground(Color.black);
    eastPanel.setForeground(Color.green);
    westPanel.setBackground(Color.black);
    westPanel.setForeground(Color.green);
    this.add(centerPanel, BorderLayout.CENTER);
    this.add(southPanel, BorderLayout.SOUTH);
    southPanel.add(dataLabel, BorderLayout.CENTER);
    this.add(northPanel, BorderLayout.NORTH);
    northPanel.add(titleLabel, BorderLayout.CENTER);
    this.add(westPanel, BorderLayout.WEST);
    this.add(eastPanel, BorderLayout.EAST);
    setPreferredSize(new Dimension(90, 180));

    for (int i = 0; i < tickCount; i++) {
      Tick tick = new Tick(); // 눈금(tick)을 10개 생성하여 추가
      this.centerPanel.add(tick);
    }
  }

  /* 실제 컴포넌트에 값을 설정하면 눈금에 색상을 변경한다
  *  값의 범위는 0~100 으로 하자
  */
  public void setValue(int value) {
    if (value > 100) { // 100을 넘어가면 100으로
      value = 100;
    }
    else if (value < 0) { // 0보다 작으면 0으로
      value = 0;
    }

    // 일단 전체 tick 을 검정색으로 칠하고
    for (int j = 0; j < tickCount; j++) {
      Tick tick = (Tick)this.centerPanel.getComponent(j);
      tick.setBackground(Color.black);
      tick.repaint();
    }

    // 입력된 value 값에 해당하는 tick들만 다시 녹색으로 칠한다
    for (int i = 0; i < tickCount; i++) {
      Tick tick = (Tick)this.centerPanel.getComponent(i);
      if (tickCount - i > value / 10) {
        // nothing to do
      } else {
        tick.setColor(Color.green);
        tick.repaint();
      }
    }

    // 하단에 숫자로 값을 표시
    this.dataLabel.setText(value + " %");
  }

  public static void main(String args[]) {
    JFrame frame = new JFrame(); // 테스트용 프레임을 생성하자
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    PmTickChartPanel tickPanel = new PmTickChartPanel();
    frame.getContentPane().setLayout(new BorderLayout());
    frame.getContentPane().add(tickPanel, BorderLayout.CENTER);

    frame.setSize(300, 300);
    frame.setVisible(true);
    
    for (int i = 0 ; i < 100 ; i++) { // 테스트를 위해 값을 설정하는 부분
      try {
        Thread.sleep(100); // 잠시 쉬었다가
        tickPanel.setValue(i); // 1씩 증가되는 값을 설정, 10 단위로 눈금 색상 변경
      }
      catch (InterruptedException ie) {
        ie.printStackTrace();
      }
    }
  }
}

/* 10 단위의 눈금 하나에 해당하는 컴포넌트
* 같은 값을 갖는 것이 좌우 하나씩 쌍으로 구성된다
*/
class Tick extends JPanel {
  JPanel lPanel = new JPanel();
  JPanel rPanel = new JPanel();
  GridLayout layout = new GridLayout(1, 2);

  public Tick() {
    this.setBackground(Color.black);
    this.setForeground(Color.black);
    lPanel.setBackground(Color.black);
    lPanel.setForeground(Color.green);
    rPanel.setBackground(Color.black);
    rPanel.setForeground(Color.green);
    layout.setHgap(1);
    setLayout(layout);
    add(lPanel);
    add(rPanel);
  }

  protected void setColor(Color color) {
    lPanel.setBackground(color);
    rPanel.setBackground(color);
  }
}

3. 나만의 컴포넌트 작성 소감

위의 소스를 작성하고 컴파일까지 이상 없이 진행되었다면 실행해보자. 앞에서 보여진 그림처럼 값이 증가됨에 따라 눈금이 올라가는 것을 볼 수 있다. 대단한 것은 아니지만 예상보다 예쁘게 보이는 컴포넌트가 대견하기만 하다. 여러분은 용도에 따라 별도의 구현만 추가한다면 입맛에 바꿔 사용할 수 도 있고, 이 예제를 기반으로 다른 컴포넌트를 작성할 준비가 된 것이다. 언제까지 남이 만든 것만 사용할 것인가? 머리 속에 무엇인가 떠오르는 것이 있다면 지금 당장 준비하자 !!!
Posted by tornado
|