概要

JTabbedPaneの余白にJCheckBoxを配置して特定のタブの表示・非表示を切り替えます。

サンプルコード

class TabbedPaneWithCompBorder implements Border, MouseListener, SwingConstants {
  private final JCheckBox checkBox;
  private final JTabbedPane tab;
  private final Container rubberStamp = new JPanel();
  private final Rectangle rect = new Rectangle();

  protected TabbedPaneWithCompBorder(JCheckBox checkBox, JTabbedPane tab) {
    this.checkBox = checkBox;
    this.tab = tab;
  }

  @Override public void paintBorder(
      Component c, Graphics g, int x, int y, int width, int height) {
    Dimension size = checkBox.getPreferredSize();
    int xx = tab.getSize().width - size.width;
    Rectangle lastTab = tab.getBoundsAt(tab.getTabCount() - 1);
    int tabEnd = lastTab.x + lastTab.width;
    if (xx < tabEnd) {
      xx = tabEnd;
    }
    rect.setBounds(xx, -2, size.width, size.height);
    SwingUtilities.paintComponent(g, checkBox, rubberStamp, rect);
  }

  @Override public Insets getBorderInsets(Component c) {
    return new Insets(0, 0, 0, 0);
  }

  @Override public boolean isBorderOpaque() {
    return true;
  }

  private void dispatchEvent(MouseEvent e) {
    if (!rect.contains(e.getX(), e.getY())) {
      return;
    }
    checkBox.setBounds(rect);
    checkBox.dispatchEvent(SwingUtilities.convertMouseEvent(tab, e, checkBox));
  }

  @Override public void mouseClicked(MouseEvent e) {
    dispatchEvent(e);
  }

  @Override public void mouseEntered(MouseEvent e) {
    dispatchEvent(e);
  }

  @Override public void mouseExited(MouseEvent e) {
    dispatchEvent(e);
  }

  @Override public void mousePressed(MouseEvent e) {
    dispatchEvent(e);
  }

  @Override public void mouseReleased(MouseEvent e) {
    dispatchEvent(e);
  }
}
View in GitHub: Java, Kotlin

解説

  • JTabbedPaneBorderSwingUtilities.paintComponent(...)メソッドを使ってJCheckBoxを描画
  • JCheckBoxJTabbedPaneの子になってタブが増えないように、別途レンダリング用パネルを作成して中間コンテナに指定
  • JTabbedPaneで受け取ったマウスイベントをSwingUtilities.convertMouseEvent(...)メソッドを利用し、チェックボックス用に座標などを変換してイベント転送
  • タブとチェックボックスが重ならないようにフレームの最小サイズを設定
    frame.setMinimumSize(new Dimension(240, 80));
    

  • レイアウトマネージャーを利用して同様のことを行う方法もある

参考リンク

コメント