Swing/TableRowHeader のバックアップの現在との差分(No.4)
TITLE:JTableに行ヘッダを追加
JTableに行ヘッダを追加
編集者:Terai Atsuhiro~
作成日:2006-09-04
更新日:2022-09-27 (火) 17:29:54
- 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
で作成した行ヘッダを追加します。
Screenshot
Advertisement
概要
JTableに行ヘッダを追加を追加します。サンプルコード
#spanend
#spanadd
class RowHeaderList<E> extends JList<E> {
#spanend
private final JTable table;
private final ListSelectionModel tableSelection;
private final ListSelectionModel rListSelection;
private int rollOverRowIndex = -1;
private int pressedRowIndex = -1;
#spandel
#screenshot
#spanend
public RowHeaderList(ListModel<E> model, JTable table) {
super(model);
this.table = table;
setFixedCellHeight(table.getRowHeight());
setCellRenderer(new RowHeaderRenderer<E>(table.getTableHeader()));
RollOverListener rol = new RollOverListener();
addMouseListener(rol);
addMouseMotionListener(rol);
#spandel
**サンプルコード [#kfa64240]
#spanend
#spandel
#code{{
#spanend
class RowHeaderList extends JList {
private final JTable table;
private final ListSelectionModel tableSelection;
private final ListSelectionModel rListSelection;
public RowHeaderList(ListModel model, JTable table) {
super(model);
this.table = table;
setFixedCellHeight(table.getRowHeight());
setCellRenderer(new RowHeaderRenderer(table.getTableHeader()));
RollOverListener rol = new RollOverListener();
addMouseListener(rol);
addMouseMotionListener(rol);
tableSelection = table.getSelectionModel();
rListSelection = getSelectionModel();
}
class RowHeaderRenderer extends JLabel implements ListCellRenderer {
private final JTableHeader header;
public RowHeaderRenderer(JTableHeader header) {
this.header = header;
this.setOpaque(true);
//this.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
this.setBorder(BorderFactory.createMatteBorder(0,0,1,2,Color.gray));
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) {
setBackground(Color.gray);
}else if(index==rollOverRowIndex) {
setBackground(Color.white);
}else if(isSelected) {
setBackground(Color.gray.brighter());
}else{
setForeground(header.getForeground());
setBackground(header.getBackground());
}
setText((value==null)?"":value.toString());
return this;
}
}
}
tableSelection = table.getSelectionModel();
rListSelection = getSelectionModel();
}
#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.brighter()));
this.setHorizontalAlignment(CENTER);
this.setForeground(header.getForeground());
this.setBackground(header.getBackground());
this.setFont(header.getFont());
}
#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) {
setBackground(Color.WHITE);
} else if (isSelected) {
setBackground(Color.GRAY.brighter());
} else {
setForeground(header.getForeground());
setBackground(header.getBackground());
}
setText(Objects.toString(value, ""));
return this;
}
}
// ...
#spanadd
}
#spanend
View in GitHub: Java, Kotlin- &jnlp;
- &jar;
- &zip;
解説
上記のサンプルでは、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);
#spanadd
rowHeader.setBackground(Color.BLUE);
#spanend
#spanadd
scrollPane.setBackground(Color.RED);
#spanend
#spanadd
scrollPane.getViewport().setBackground(Color.GREEN);
#spanend
参考リンク
参考リンク
コメント
- 不正なセルレンダラーを設定していたので修正しました。 -- terai
コメント
- 不正なセルレンダラーを設定していたので修正しました。 -- 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
#spanend
#spanadd
import java.awt.*;
#spanend
#spanadd
import java.awt.event.*;
#spanend
#spanadd
import javax.swing.*;
#spanend
#spanadd
import javax.swing.event.*;
#spanend
#spanadd
import javax.swing.table.*;
#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) {
@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);
#spanadd
#spanend
JTableHeader header = table.getTableHeader();
header.setReorderingAllowed(false);
#spanadd
#spanend
TableCellRenderer hr = header.getDefaultRenderer();
TableColumn col = table.getColumnModel().getColumn(0);
col.setCellRenderer(new HeaderRenderer(table, hr));
#spanadd
#spanend
JPanel p = new JPanel(new BorderLayout());
p.add(new JScrollPane(table));
p.setPreferredSize(new Dimension(320, 240));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} 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);
}
#spanadd
}
#spanend
#spanadd
class HeaderRenderer implements TableCellRenderer {
#spanend
private final TableCellRenderer tcr;
public HeaderRenderer(JTable table, TableCellRenderer tcr) {
this.tcr = tcr;
RollOverListener rol = new RollOverListener();
table.addMouseListener(rol);
table.addMouseMotionListener(rol);
}
@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);
l.setOpaque(!flg);
return l;
}
private int rollOverRowIndex = -1;
private class RollOverListener extends MouseInputAdapter {
@Override public void mouseExited(MouseEvent e) {
rollOverRowIndex = -1;
JTable table = (JTable) e.getSource();
table.repaint();
}
@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;
table.repaint();
}
@Override public void mouseDragged(MouseEvent e) {}
@Override public void mousePressed(MouseEvent e) {}
@Override public void mouseReleased(MouseEvent e) {}
}
#spanadd
}
#spanend
#spanadd
- すばやい返答ありがとうございます。わざわざサンプルまで。自分で定義する
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- あー、前者と後者が何を指しているのか誤解してたみたいです。 -- aterai
- こんばんは。
ページ上部の「このページを編集する」で、だれでも適当に編集できます。パスワードは日付を更新せずに編集する場合に必要なだけです。スパムが鬱陶しいので編集禁止にしました(2014-05-16)。とりあえず勝手に改行入れときましたm(_ _)m。 -- aterai