Swing/TableRowHeader のバックアップの現在との差分(No.14)
TITLE:JTableに行ヘッダを追加
Posted by aterai at 2006-09-04
JTableに行ヘッダを追加
JTableに行ヘッダを追加を追加します。-
category: swing
folder: TableRowHeader
title: JTableに行ヘッダを追加
tags: [JTable, JList, JScrollPane]
author: aterai
pubdate: 2006-09-04T01:10:03+09:00
description: JTableを設定したJScrollPaneのRowHeaderViewに、JListで作成した行ヘッダを追加します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2011/01/jtable-rowheader.html lang: en
概要
JTable
を設定したJScrollPane
のRowHeaderView
に、JList
で作成した行ヘッダを追加します。
- &jnlp;
- &jar;
- &zip;
Screenshot
Advertisement
サンプルコード
#spanend
#spandel
class RowHeaderList extends JList {
#spanend
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
#spanadd
class RowHeaderList<E> extends JList<E> {
#spanend
private final JTable table;
private final ListSelectionModel tableSelection;
private final ListSelectionModel rListSelection;
public RowHeaderList(ListModel model, JTable table) {
private int rollOverRowIndex = -1;
private int pressedRowIndex = -1;
#spanadd
#spanend
public RowHeaderList(ListModel<E> model, JTable table) {
super(model);
this.table = table;
setFixedCellHeight(table.getRowHeight());
setCellRenderer(new RowHeaderRenderer(table.getTableHeader()));
setCellRenderer(new RowHeaderRenderer<E>(table.getTableHeader()));
RollOverListener rol = new RollOverListener();
addMouseListener(rol);
addMouseMotionListener(rol);
#spanadd
#spanend
tableSelection = table.getSelectionModel();
rListSelection = getSelectionModel();
}
class RowHeaderRenderer extends JLabel implements ListCellRenderer {
private final JTableHeader header;
#spanadd
#spanend
class RowHeaderRenderer<E> extends JLabel
implements ListCellRenderer<E> {
private final JTableHeader header; // = table.getTableHeader();
public RowHeaderRenderer(JTableHeader header) {
super();
this.header = header;
this.setOpaque(true);
//this.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
this.setBorder(BorderFactory.createMatteBorder(0,0,1,2,Color.GRAY));
// this.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
this.setBorder(BorderFactory.createMatteBorder(
0, 0, 1, 2, Color.GRAY.brighter()));
this.setHorizontalAlignment(CENTER);
this.setForeground(header.getForeground());
this.setBackground(header.getBackground());
this.setFont(header.getFont());
}
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if(index==pressedRowIndex) {
#spanadd
#spanend
@Override public Component getListCellRendererComponent(
JList<? extends E> list, E value, int index,
boolean isSelected, boolean cellHasFocus) {
if (index == pressedRowIndex) {
setBackground(Color.GRAY);
}else if(index==rollOverRowIndex) {
} else if (index == rollOverRowIndex) {
setBackground(Color.WHITE);
}else if(isSelected) {
} else if (isSelected) {
setBackground(Color.GRAY.brighter());
}else{
} else {
setForeground(header.getForeground());
setBackground(header.getBackground());
}
setText((value==null)?"":value.toString());
setText(Objects.toString(value, ""));
return this;
}
}
// ...
}
解説
上記のサンプルでは、JListで作成した行ヘッダをJScrollPaneにsetRowHeaderViewメソッドで追加しています。解説
上記のサンプルでは、JList
で作成した行ヘッダをJScrollPane#setRowHeaderView(...)
メソッドで追加しています。
表の余白などに色がついているのは、テストの名残です。特に意味は無いのですが、そのまま残しています。
- -
-
Corner
:JScrollPane.html#setCorner(...)
で左上隅などにコンポーネントを設定しておらずJScrollPane
自体の背景色(赤)が表示されている -
Viewport
:JTable
のセルが存在しない領域はJViewport
の背景色(緑)が表示されている
rowHeader.setBackground(Color.BLUE);
scrollPane.setBackground(Color.RED);
scrollPane.getViewport().setBackground(Color.GREEN);
参考リンク
参考リンク
コメント
- 不正なセルレンダラーを設定していたので修正しました。 -- aterai
- excelのように、行ヘッダをクリックしてその行が選択されたり、テーブルの本体にてセルをクリックしてそのセルだけが選択されたりすることはできますか?いろいろ試しましたが、なかなかできませんでした。 -- javalover?
- セル選択は、table.setCellSelectionEnabled(true);で可能です。行ヘッダをクリックしてその行を選択することは、現在でも出来るような。もし、列のことなら、
JTableHeaderに以下のようなコードを書けばよさそうです。JTableHeaderをクリックしてそのColumnのセルを全選択を参考にしてください。 -- aterai - あ、もしかして、TableCellRendererでセルの背景色を変更 の例のように、JTable#prepareRendererをオーバーライドして行ごとの背景色を変更していますか? あちらの例では、行選択しか考慮していなのでisRowSelectedを使って、一行まるごと選択色で塗りつぶすかどうかを判断しています*1が、セル選択する場合は、ちゃんとisCellSelected(int,int)でそのセルが選択されているかを判断する必要があります。 -- aterai
- セル選択は、table.setCellSelectionEnabled(true);で可能です。行ヘッダをクリックしてその行を選択することは、現在でも出来るような。もし、列のことなら、
- ここのサンプルを変更して、行列ヘッダクリックで、各行列を選択するように変更しました。 -- aterai
- プログラム自体大学で始めて触れてる者で参考にさせてもらっています。 -- D.Umeda(ES)?
- すいません、上のミスです。改行と思ってEnterKeyを..。DefaultTableCellRenderer r1 = (DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer()をした上でこのr1を必要なColumにsetCellRendererしてやれば、その機能は再現できるのではないでしょうか?
- Ver1.6環境Vistaで実行しましたが、オンマウス時の背景変化以外は全て実装できているように思います。
- JScrollPaneに対してJPanelを追加、その上にテーブルヘッダを1行ずつ追加していけばVista仕様でもXP仕様でもオンマウスの変化を再現できますが、Vistaの場合、グラフィックの問題で1pxずれる上、結局リスナを設定しなければヘッダ選択による行の全選択が出来ないので前者の方が効率が良いですが。
- 逐一ヘッダを作って張ってなので後者は処理速度的にも実装形式的にも非効率だと思われます。ちなみにDefaultでもTableCellRendererでもVista上では結果は同じでWindowsClassicが適応されているように見えます。
- 多々間違いがあれば訂正か削除をお願いします。長文、ミス失礼しました。 -- D.Umeda(ES)?
- どうもです。多分以下のような提案だと思っているのですが、合ってます? 処理速度とかは、この程度のサンプルだと、どちらもあまり気にしなくてもいいと思います。 -- aterai
コメント
- 不正なセルレンダラーを設定していたので修正しました。 -- aterai
-
excel
のように、行ヘッダをクリックしてその行が選択されたり、テーブルの本体にてセルをクリックしてそのセルだけが選択されたりすることはできますか?いろいろ試しましたが、なかなかできませんでした。 -- javalover- セル選択は、
table.setCellSelectionEnabled(true);
で可能です。行ヘッダをクリックしてその行を選択することは、現在でも可能?なはずです。もし行ヘッダではなく、列ヘッダのことなら、JTableHeaderをクリックしてそのColumnのセルを全選択を参考にしてください。 -- ateraiJTableHeader
に以下のようなコードを書けばよさそうです。 - あ、もしかして、TableCellRendererでセルの背景色を変更 の例のように、
JTable#prepareRenderer
をオーバーライドして行ごとの背景色を変更していますか? あちらの例では、行選択しか考慮していなのでisRowSelected
を使って、一行まるごと選択色で塗りつぶすかどうかを判断しています(table.setCellSelectionEnabled(true)
しても、一行選択されているように見えるようになっている)が、セル選択する場合は、ちゃんとisCellSelected(int,int)
でそのセルが選択されているかを判断する必要があります。 -- aterai
- セル選択は、
- ここのサンプルを変更して、行列ヘッダクリックで、各行列を選択するように変更しました。 -- aterai
- プログラム自体大学で始めて触れてる者で参考にさせてもらっています。 -- D.Umeda(ES)
- すいません、上のミスです。改行と思って
EnterKey
を..。DefaultTableCellRenderer r1 = (DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer()
をした上でこのr1
を必要なColumn
にsetCellRenderer
してやれば、その機能は再現できるのではないでしょうか? -
Ver1.6
環境Vista
で実行しましたが、オンマウス時の背景変化以外は全て実装できているように思います。 -
JScrollPane
に対してJPanel
を追加、その上にテーブルヘッダを1
行ずつ追加していけばVista
仕様でもXP
仕様でもオンマウスの変化を再現できますが、Vista
の場合、グラフィックの問題で1px
ずれる上、結局リスナを設定しなければヘッダ選択による行の全選択が出来ないので前者の方が効率が良いですが。 - 逐一ヘッダを作って張ってなので後者は処理速度的にも実装形式的にも非効率だと思われます。ちなみに
Default
でもTableCellRenderer
でもVista
上では結果は同じでWindowsClassic
が適応されているように見えます。 - 多々間違いがあれば訂正か削除をお願いします。長文、ミス失礼しました。 -- D.Umeda(ES)
- どうもです。多分以下のような提案だと思っているのですが、合ってます? 処理速度とかは、この程度のサンプルだと、どちらもあまり気にしなくてもいいと思います。 -- aterai
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
#spandel
public class HeaderRendererTest{
#spanend
#spanadd
public class HeaderRendererTest {
#spanend
public JComponent makeUI() {
String[] columnNames = {"", "String", "Boolean"};
Object[][] data = {
{0, "AAA", true}, {1, "BBB", false},
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
public Class<?> getColumnClass(int column) {
@Override public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
JTable table = new JTable(model);
table.setRowSelectionAllowed(true);
table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
JTableHeader header = table.getTableHeader();
header.setReorderingAllowed(false);
TableCellRenderer hr = header.getDefaultRenderer();
TableColumn col = table.getColumnModel().getColumn(0);
col.setCellRenderer(new HeaderRenderer(table, hr));
JPanel p = new JPanel(new BorderLayout());
p.add(new JScrollPane(table));
p.setPreferredSize(new Dimension(320, 160));
p.setPreferredSize(new Dimension(320, 240));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
try{
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
}catch(Exception e) {
} catch (Exception e) {
e.printStackTrace();
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new HeaderRendererTest().makeUI());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class HeaderRenderer implements TableCellRenderer {
private final TableCellRenderer tcr;
public HeaderRenderer(JTable table, TableCellRenderer tcr) {
this.tcr = tcr;
RollOverListener rol = new RollOverListener();
table.addMouseListener(rol);
table.addMouseMotionListener(rol);
}
public Component getTableCellRendererComponent(
@Override public Component getTableCellRendererComponent(
JTable tbl, Object val, boolean isS,
boolean hasF, int row, int col) {
JLabel l;
boolean flg = (row==rollOverRowIndex);
l = (JLabel)tcr.getTableCellRendererComponent(
tbl, val, isS, flg?flg:hasF, row, col);
boolean flg = row == rollOverRowIndex;
l = (JLabel) tcr.getTableCellRendererComponent(
tbl, val, isS, flg ? flg : hasF, row, col);
l.setOpaque(!flg);
return l;
}
private int rollOverRowIndex = -1;
private class RollOverListener extends MouseInputAdapter {
public void mouseExited(MouseEvent e) {
@Override public void mouseExited(MouseEvent e) {
rollOverRowIndex = -1;
JTable table = (JTable)e.getSource();
JTable table = (JTable) e.getSource();
table.repaint();
}
public void mouseMoved(MouseEvent e) {
JTable table = (JTable)e.getSource();
@Override public void mouseMoved(MouseEvent e) {
JTable table = (JTable) e.getSource();
Point pt = e.getPoint();
int column = table.columnAtPoint(pt);
rollOverRowIndex = (column==0)?table.rowAtPoint(pt):-1;
rollOverRowIndex = (column == 0) ? table.rowAtPoint(pt) : -1;
table.repaint();
}
public void mouseDragged(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
@Override public void mouseDragged(MouseEvent e) {}
@Override public void mousePressed(MouseEvent e) {}
@Override public void mouseReleased(MouseEvent e) {}
}
}
- すばやい返答ありがとうございます。わざわざサンプルまで。自分で定義するHeaderRendererは無くとも「col.setCellRenderer(hr);」である程度再現できますが、やはりオンマウスやクリックでの変化はUI観点から見て必要ですね。やはり行ヘッダの領域を見るとどうしてもVistaだとズレが生じてしまうのが気になりますが、結局OS依存しないプログラムを作ろうとするとMetalかカスタムUIですね。列ヘッダをVista,行ヘッダをクラシックにする誤差は生じないのですが。 -- D.Umeda?
- Vistaは持ってないので、なんとも言えないのですが、XPでもオレンジのハイライト?が下に付くのはあれですね。まじめにやるなら右につけたいところです。-- aterai
- また醜い状態で設定してしまったorz見苦しいようであれば是非とも削除を。参考になるかは定かではありませんが、javaForumで掲示したところ次のようなサンプルURLを頂きました。http://tips4java.wordpress.com/2008/11/18/row-number-table/
- すばやい返答ありがとうございます。わざわざサンプルまで。自分で定義する
HeaderRenderer
は無くともcol.setCellRenderer(hr);
で、ある程度再現できますが、やはりオンマウスやクリックでの変化はUI
観点から見て必要ですね。やはり行ヘッダの領域を見るとどうしてもVista
だとズレが生じてしまうのが気になりますが、結局OS
依存しないプログラムを作ろうとするとMetal
かカスタムUI
ですね。列ヘッダをVista
,行ヘッダをクラシックにする誤差は生じないのですが。 -- D.Umeda-
Vista
は持ってないので、なんとも言えないのですが、XP
でもオレンジのハイライト?が下に付くのはあれですね。まじめにやるなら右につけたいところです。-- aterai
-
- また醜い状態で設定してしまったorz見苦しいようであれば是非とも削除を。参考になるかは定かではありませんが、
javaForum
で掲示したところ次のようなサンプルURLを頂きました。https://tips4java.wordpress.com/2008/11/18/row-number-table/- camickrさんとこのブログですね。どこのjavaForum かは知らないのですが、いいとこ突いてると思います。 -- aterai
- 終わりに、わざわざサンプルを提示してくださってありがとうございました。これからも活用させてもらいます。
- 文章で説明するより、サンプルのほうが簡単なので(^^;。 -- aterai
- 追記になりますが、処理速度の件は私がこれをする前に1列1行だけのヘッダをrowHeaderViewのパネルにひたすら並べ続けた、ということを書きたかったんですが、きちんと用語を用いて説明する勉強もしなければいけないようです。データ数によってはヘッダを量産するので非常に非効率だと思ったのですが、勉強しておきます。 -- D.Umeda?
- 追記になりますが、処理速度の件は私がこれをする前に
1
列1
行だけのヘッダをrowHeaderView
のパネルにひたすら並べ続けた、ということを書きたかったんですが、きちんと用語を用いて説明する勉強もしなければいけないようです。データ数によってはヘッダを量産するので非常に非効率だと思ったのですが、勉強しておきます。 -- D.Umeda- あー、前者と後者が何を指しているのか誤解してたみたいです。 -- aterai
- こんばんは。ページ上部の「このページを編集する」で、だれでも適当に編集できます。パスワードは日付を更新せずに編集する場合に必要なだけです。とりあえず勝手に改行入れときましたm(_ _)m。 -- aterai
- こんばんは。
ページ上部の「このページを編集する」で、だれでも適当に編集できます。パスワードは日付を更新せずに編集する場合に必要なだけです。スパムが鬱陶しいので編集禁止にしました(2014-05-16)。とりあえず勝手に改行入れときましたm(_ _)m。 -- aterai