2012/05/20

【Java/Swing】 JTableにJProgressBarを配置して使ってみたよ(σ・ω・)σ

現在Javaで制作中のソフトに、『Progressバーを表示する表』を導入しようと思っているのですが、
Java/Swingの表コンポーネントである『JTable』を使う際に、いろいろつまづいたのでメモします(;´∀`)

表にデータや表示方法を関連づける
まず、表にするデータをTableModelによってJTableに渡します。
そして、『データをどのように表示するのか』をTableCellRendererによって決めます。

.Net FrameworkでのDataGridViewにBindingSourceをバインドするイメージに近いのでしょうか?w

では順番に見ていきましょう(`・ω・´)
表にデータを渡しましょう
まずは、表にデータを渡して進捗率が数字で表示されるところまでを見ていきますw

package t2wonderland.java;

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.JButton;
import javax.swing.BoxLayout;
import javax.swing.JScrollPane;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class TableFrame extends JFrame {

 private static final long serialVersionUID = 1L;
 private JTable tableTest;
 private ProgressTableModel tableMedel;
 private JButton btnStart;

 // アプリケーションを起動します。ここから始まるよw
 public static void main(String[] args) {
  TableFrame frame = new TableFrame();
  frame.setVisible(true);
 }

 // 画面を初期化するよ
 public TableFrame() {
  // Windowサイズと、閉じるボタン押下時の処理を追加
  this.setSize(400,300);
  this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
  
  // PaneやComponentなど、UI部品を配置します
  JScrollPane scrollPane = new JScrollPane();
  getContentPane().add(scrollPane);
  
  tableTest = new JTable();
  scrollPane.setViewportView(tableTest);
  
  btnStart = new JButton("Start");
  btnStart.addActionListener(new ActionAdapter());
  btnStart.setAlignmentX(Component.CENTER_ALIGNMENT);
  getContentPane().add(btnStart);
  
  // JTableに、TableModelとTableCellRendererを設定します
  
  // ※1 後で、TableModel設定を追加するよ( ・`ω・´)

  // ※2 後で、TableCellRenderer設定を追加するよ( ・`ω・´)
 }
 
 // ※3 後で、Startボタン押下時の処理を追加するよ( ・`ω・´)
}
まず土台となる画面を作成します。※印の部分は、後で順番に追記してゆきます。

package t2wonderland.java;

import javax.swing.table.AbstractTableModel;

// カスタムTableModelクラス
public class ProgressTableModel extends AbstractTableModel
{
 private static final long serialVersionUID = 1L;
 
 // データ
 private String[] columnNames = {"Progress"};
 private int[] progress = {0};

 // Progress列のデータGet、Set
 public int[] getProgress() {
  return progress;
 }

 public void setProgress(int[] progress) {
  this.progress = progress;
 }

 /// AbstractTableModelのオーバーライド
 @Override // 列数を返すMethod
 public int getColumnCount() {
  return 1;
 }

 @Override // 行数を返すMethod
 public int getRowCount() {
  return progress.length;
 }

 @Override // 指定セルの値を返すMethod
 public Object getValueAt(int rowIndex, int columnIndex) {
  return progress[rowIndex];
 }
 
 @Override // 列名称を変えすMethod
 public String getColumnName(int column) {
  return columnNames[column];
 } 
}
次に、データを制御するTableModelクラスを作成します。今回、AbstractTableModelを拡張して作ってみましたヽ(´ー`)ノ
列名を「Progress」とし、セルの値をInt型で返すようにしています。

tableMedel = new ProgressTableModel();
tableTest.setModel(tableMedel);
※1の箇所に上記の処理を追加すれば、表へのTableModel設定完了です( ・`ω・´)b
項目の表示方法を変更しましょう
表のセルに、数字ではなくJProgressBarコンポーネントを表示するようにします。

package t2wonderland.java;

import java.awt.Component;
import javax.swing.JProgressBar;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;

// JTableのセルにJProgressBarを表示するためのレンダラークラス
public class ProgressRenderer extends DefaultTableCellRenderer {

 private static final long serialVersionUID = 1L;
 private JProgressBar progress = new JProgressBar(0,100);
 
 // 実際に表示するオブジェクトを返す
 public Component getTableCellRendererComponent(JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column) {

  progress.setValue( ((Integer)value) );
  return progress;
 }

}
まず、JProgressBarを表示させるためのTableCellRendererクラスを作成します。

tableTest.setDefaultRenderer(Object.class, new ProgressRenderer());
一つ目のコードの※2の箇所に、上記のコードを追加します。これで、表にTableCellRendererを設定完了です。
実際に表示するオブジェクトが、数字(Int型)からJProgressBarに変更されます。
JProgressBarの進捗率を増やしてみるテスト
Startボタンを押したら進捗率が進むようにしてみます。

// イベントリスナー用の内部クラス
class ActionAdapter implements ActionListener
{
 @Override // actionに対する処理を記述します
 public void actionPerformed(ActionEvent e) {
  if( btnStart == e.getSource() ) // Startボタンが押された場合
  {
   // サンプルスレッドを起動します
   ProgressThread progThread = new ProgressThread();
   progThread.start();
  }
  
 }
 
 // サンプルスレッドを内部クラスとして実装
 class ProgressThread extends Thread
 {
  @Override // スレッド処理の内容を記述します
  public void run() {
   int[] nProgress = tableMedel.getProgress();
   int row = 0;
   int value = 0;
   
   for( row = 0; row < nProgress.length; row++ )
   {
    // row行目のJProgressBarをぐりぐりと進める
    for( value = 0; value <= 100; value++)
    {
     // 進捗率を増やして表示を更新
     nProgress[row]=value;
     tableMedel.setProgress(nProgress);
     tableTest.updateUI();
     
     // 200 msecごとに増やす
     try {
      sleep(100);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   }
  }
 
 }
}
一つ目のコードの※3の箇所に、上記のコードを追記します。イベントリスナーをTableFrameクラスの内部クラスとしました。 

実装が雑過ぎですが、これから頑張ります・・・ (;´Д`)<とりあえず動かしたかっただけ~w
Intの配列をガリガリ受け渡しとかどうかと思うので、皆様はもっとスマートな方法を考案して下さい。。
参考記事

(2012.05.26 : 一部の画像を修正しました。)

0 件のコメント: