TITLE:JTableのセルをエクスプローラ風に表示する

JTableのセルをエクスプローラ風に表示する

編集者:Terai Atsuhiro~

作成日:2006-07-18
更新日:2024-02-14 (水) 23:39:51
  • category: swing folder: ExplorerLikeTable title: JTableのセルをエクスプローラ風に表示する tags: [JTable, TableCellRenderer, JLabel, Focus] author: aterai pubdate: 2006-07-17T08:23:31+09:00 description: セルの中にアイコンと文字列を配置し、エクスプローラ風に見えるよう、文字列だけにフォーカスをかけます。 image: https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTMWzLLVKI/AAAAAAAAAZA/k3vF14Jt-V0/s800/ExplorerLikeTable.png

概要

セルの中にアイコンと文字列を配置し、エクスプローラ風に見えるよう、文字列だけにフォーカスをかけます。

概要

セルの中にアイコンと文字列を配置し、エクスプローラ風に見えるよう、文字列だけにフォーカスをかけます。

サンプルコード

#spanend
#spanadd
class TestRenderer extends Box implements TableCellRenderer {
#spanend
  private final Border emptyBorder = BorderFactory.createEmptyBorder(1, 1, 1, 1);
  private final ImageIcon nicon;
  private final ImageIcon sicon;
  private final JLabel textLabel;
  private final JLabel iconLabel;
  public TestRenderer(JTable table) {
    super(BoxLayout.X_AXIS);
    textLabel = new JLabel("JLabel");
    textLabel.setOpaque(true);
    textLabel.setBorder(emptyBorder);
    nicon = new ImageIcon(getClass().getResource("wi0063-16.png"));
    FilteredImageSource fis = new FilteredImageSource(
      nicon.getImage().getSource(), new SelectedImageFilter());
    sicon = new ImageIcon(createImage(fis));
    iconLabel = new JLabel(nicon);
    iconLabel.setBorder(BorderFactory.createEmptyBorder());
    table.setRowHeight(Math.max(textLabel.getPreferredSize().height,
                  iconLabel.getPreferredSize().height));
    add(iconLabel);
    add(textLabel);
    add(Box.createHorizontalGlue());
  }

#spandel
#screenshot
#spanend
  @Override public Component getTableCellRendererComponent(JTable table,
      Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    textLabel.setText(Objects.toString(value, ""));
    FontMetrics fm = table.getFontMetrics(table.getFont());
    int swidth = fm.stringWidth(textLabel.getText()) + textLabel.getInsets().left
                              + textLabel.getInsets().right;
    int cwidth = table.getColumnModel().getColumn(column).getWidth()
                   -iconLabel.getPreferredSize().width;
    textLabel.setPreferredSize(new Dimension(swidth > cwidth ? cwidth : swidth, 0));
    if (isSelected) {
      textLabel.setForeground(table.getSelectionForeground());
      textLabel.setBackground(table.getSelectionBackground());
    } else {
      textLabel.setForeground(table.getForeground());
      textLabel.setBackground(table.getBackground());
    }
    if (hasFocus) {
      textLabel.setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
    } else {
      textLabel.setBorder(emptyBorder);
    }
    textLabel.setFont(table.getFont());
    iconLabel.setIcon(isSelected?sicon:nicon);
    return this;
  }

#spandel
**サンプルコード [#f06fb511]
#spanend
 public TestRenderer(JTable table) {
   super(BoxLayout.X_AXIS);
   label.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
   nicon = new ImageIcon(getClass().getResource("wi0063-16.png"));
   FilteredImageSource fis = new FilteredImageSource(
                 nicon.getImage().getSource(),
                 new SelectedImageFilter());
   sicon = new ImageIcon(createImage(fis));
   iconLabel.setIcon(nicon);
   textLabel = new MyLabel(table);
   table.setRowHeight(textLabel.getPreferredSize().height);
 }
 public Component getTableCellRendererComponent(
                  JTable table, Object value, boolean isSelected,
                  boolean hasFocus, int row, int column) {
   textLabel.setText((value ==null) ? "" : value.toString());
   FontMetrics fm = table.getFontMetrics(table.getFont());
   int swidth = fm.stringWidth(textLabel.getText()) +
                textLabel.getInsets().left +
                textLabel.getInsets().right;
   int cwidth = table.getColumnModel().getColumn(column).getWidth() -
                iconLabel.getPreferredSize().width;
   textLabel.setPreferredSize(
     new Dimension((swidth>cwidth)?cwidth:swidth, 10000));
   textLabel.setSelected(isSelected);
   textLabel.setFocusedBorder(hasFocus);
   textLabel.setFont(table.getFont());
   iconLabel.setIcon((isSelected)?sicon:nicon);
   removeAll();
   add(iconLabel);
   add(textLabel);
   add(Box.createHorizontalGlue());
   return this;
 }
  private static class SelectedImageFilter extends RGBImageFilter {
    public SelectedImageFilter() {
      canFilterIndexColorModel = false;
    }

-&jnlp;
-&jar;
-&zip;
    @Override public int filterRGB(int x, int y, int argb) {
      // Color color = new Color(argb, true);
      // float[] array = new float[4];
      // color.getComponents(array);
      // return new Color(array[0] * .5f, array[1] * .5f, array[2], array[3]).getRGB();
      int r = (argb >> 16) & 0xFF;
      int g = (argb >> 8) & 0xFF;
      return (argb & 0xFF_00_00_FF) | ((r >> 1) << 16) | ((g >> 1) << 8);
    }
  }
#spanadd
}
#spanend
#spanadd
View in GitHub: Java, Kotlin

解説

最初の列などをセルレンダラーを使って、エクスプローラの詳細のような表示にしています。

解説

Windows Explorer(ファイルシステム・エクスプローラ)の詳細表示風にするため、以下のような設定をしています。 レンダラーでは、アイコンと文字列を別々のJLabelで作成して並べることで、フォーカスはセルではなく文字列だけに点線で掛かるようになっています。
  • セル間の罫線を非表示(JTable#setShowHorizontalLinesJTable#setShowVerticalLines)
  • ひとつのセルの中でアイコンと文字列を表示するセルレンダラーを作成
  • フォーカスがJTableに無い場合選択されたセルの背景色をパネルの背景色に変更
また、選択時にはセル全体の背景色を変更するのではなく、文字列を表示しているJLabelの背景色を変更し、そのPreferredSizeを文字列の長さまで縮小して右側に余白を作成しています。 このレンダラーではアイコンと文字列を別々のJLabelで作成して並べることでJList#putClientProperty("List.isFileList", Boolean.TRUE)した場合のようにフォーカスはセルではなく文字列だけに点線で掛かるようになっています。
  • エクスプローラ風になっていない点
    • アイコンと文字列以外の場所(セル内)をクリックしても、選択できてしまう
      • JTableで文字列をクリックした場合だけセルを選択状態にする
      • WindowsLaFでのJFileChooserはどうやっているのだろうか?
    • マウスによる範囲指定で選択することができない
    • ソートすると選択状態がクリアされてしまう
      • TableSorterでソートしても選択状態を維持 選択時にはセル全体の背景色を変更するのではなく文字列を表示しているJLabelの背景色を変更しそのPreferredSizeを文字列の長さまで縮小して右側に余白を作成しています。

参考リンク

コメント

参考リンク

コメント