TITLE:JTableの行を移動

Usage: #tags(tags)
Posted by at 2004-02-23

JTableの行を移動

ツールバーや、ポップアップメニューを使って、JTableの行を上下に移動します。

  • &jnlp;
  • &jar;
  • &zip;
MoveRow.png

サンプルコード

class DownAction extends AbstractAction{
  public DownAction(String str) {
    super(str);
  }
  public void actionPerformed(ActionEvent evt) {
    downActionPerformed(evt);
  }
}
private void downActionPerformed(ActionEvent e) {
  System.out.println("-------- 下へ --------");
  int[] pos = table.getSelectedRows();
  if(pos==null || pos.length<=0) return;
  DefaultTableModel mdl = (DefaultTableModel) table.getModel();
  if((e.getModifiers() & ActionEvent.SHIFT_MASK)!=0) {
    mdl.moveRow(pos[0], pos[pos.length-1], mdl.getRowCount()-pos.length);
    table.setRowSelectionInterval(mdl.getRowCount()-pos.length,
      mdl.getRowCount()-1);
  }else{
    if(pos[pos.length-1]==mdl.getRowCount()-1) return;
    mdl.moveRow(pos[0], pos[pos.length-1], pos[0]+1);
    table.setRowSelectionInterval(pos[0]+1, pos[pos.length-1]+1);
  }
  scrollSelectedRow();
}

public void showRowPop(MouseEvent e) {
  int row     = table.rowAtPoint(e.getPoint());
  int count   = table.getSelectedRowCount();
  int[] ilist = table.getSelectedRows();
  boolean flg = true;
  for(int i=0;i<ilist.length;i++) {
    if(ilist[i]==row) {
      flg = false;
      break;
    }
  }
  if(row>0 && flg) table.setRowSelectionInterval(row, row);
  JPopupMenu pop = new JPopupMenu();
  Action act = new TestCreateAction("追加", null);
  act.setEnabled(count==1);
  pop.add(act);
  pop.addSeparator();
  act = new DeleteAction("削除", null);
  act.setEnabled(row>=0);
  pop.add(act);
  pop.addSeparator();
  act = new UpAction("上へ");
  act.setEnabled(count>0);
  pop.add(act);
  act = new DownAction("下へ");
  act.setEnabled(count>0);
  pop.add(act);
  pop.show(e.getComponent(), e.getX(), e.getY());
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、DefaultTableModel#moveRowメソッドを使用して、選択した行を上下に動かしています。シフトキーを押しながら、ツールバーの移動ボタンを押すとそれぞれ、先頭、末尾に移動します。

コメント

  • いつもお世話になっております。違うカテゴリに投稿して、すみません。jTableのカラムの幅をマウスで広げたり、縮んだりする際、イベントで検出し、その幅を変数に取っておく方法はご存知でしょうか?当方はJDK1.5を使っています。よろしくお願いいたします。 -- Panda
  • こんばんは。TableColumnModelListenerを使うのはどうでしょうか。 -- aterai
    final TableColumnModel cm = table.getColumnModel();
    cm.addColumnModelListener(new TableColumnModelListener() {
      @Override public void columnAdded(TableColumnModelEvent e) {}
      @Override public void columnMarginChanged(ChangeEvent e) {
        for(int i=0;i<cm.getColumnCount();i++) {
          TableColumn c = cm.getColumn(i);
          System.out.println(c.getHeaderValue()+": "+c.getWidth());
        }
      }
      @Override public void columnMoved(TableColumnModelEvent e) {}
      @Override public void columnRemoved(TableColumnModelEvent e) {}
      @Override public void columnSelectionChanged(ListSelectionEvent e) {}
    });
    
  • ご回答、ありがとうございました。列の幅を変更するため、TableColumn c = cm.getColumn(i);・・・c.setPreferredWidth(int preferredWidth);で行いましたが、例えばc.setPreferredWidth(100)にすると、System.out.println(c.getHeaderValue()+": "+c.getWidth());の結果は75が表示されます。見た目上も100ピクセルになっていません。確実に幅100ピクセルにするにはどうすれば良いでしょうか? -- Panda
    • 列幅が自動調整される場合は、サイズ変更(デルタ)が有効な列に分散されます。このデルタの分散の詳細については http://docs.oracle.com/javase/jp/6/api/javax/swing/JTable.html#doLayout() を参考にしてください。自動調整がOFF(table.getAutoResizeMode()==AUTO_RESIZE_OFF)の場合はデルタの分散を考慮する必要がないので、ある列の幅をぴったり100pxにするのは簡単です(TableColumn#setPreferredWidth(100)とするだけで良い)。デフォルトのAUTO_RESIZE_SUBSEQUENT_COLUMNSの場合は、例えば以下のようにデルタの分散が0になるように?後の列も含めてサイズ調整しておく必要があります。 -- aterai
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import javax.swing.event.*;
      import javax.swing.table.*;
      public class ColumnPreferredWidthTest {
        String[] columnNames = {"String", "Integer", "Boolean"};
        Object[][] data = {
          {"aaa", 12, true}, {"bbb", 5, false},
          {"CCC", 92, true}, {"DDD", 0, false}
        };
        DefaultTableModel model = new DefaultTableModel(data, columnNames) {
          @Override public Class<?> getColumnClass(int column) {
            return getValueAt(0, column).getClass();
          }
        };
        JTable table = new JTable(model);
        TableColumnModel cm = table.getColumnModel();
        public JComponent makeUI() {
          EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
              int total = cm.getTotalColumnWidth();
              int count = cm.getColumnCount();
              cm.getColumn(0).setPreferredWidth(100); //0列目の幅を100pxにする
              total -= 100;
              int colwidth = total/(count-1); //残りの列幅は均等になるように計算
              for (int i=1; i<count-1; i++) {
                TableColumn col = cm.getColumn(i);
                col.setPreferredWidth(colwidth);
                total -= colwidth;
              }
              cm.getColumn(count-1).setPreferredWidth(total); //最後の列幅で余りを吸収
            }
          });
      
          JPanel p = new JPanel(new BorderLayout());
          p.add(new JScrollPane(table));
          p.add(new JButton(new AbstractAction("print width") {
            @Override public void actionPerformed(ActionEvent e) {
              for (int i=0; i<cm.getColumnCount(); i++) {
                TableColumn c = cm.getColumn(i);
                System.out.println(c.getHeaderValue()+": "+c.getWidth());
              }
            }
          }), BorderLayout.SOUTH);
          return p;
        }
        public static void main(String[] args) {
          EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
              createAndShowGUI();
            }
          });
        }
        public static void createAndShowGUI() {
          JFrame f = new JFrame();
          f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
          f.getContentPane().add(new ColumnPreferredWidthTest().makeUI());
          f.setSize(320, 240);
          f.setLocationRelativeTo(null);
          f.setVisible(true);
        }
      }
      
    • TableColumnの幅を比率で設定の解説を追加変更したので、そのうちこれらのコードはそちらに移動するかもしれません。 -- aterai