Closeable JTabbedPane - alignment of the close button

会有一股神秘感。 提交于 2019-12-01 17:06:06

Here is one possible implementation using JLayer:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;

public class CloseableTabbedPaneTest {
  public JComponent makeUI() {
    UIManager.put("TabbedPane.tabInsets", new Insets(2, 2, 2, 50));
    final JTabbedPane tabbedPane = new JTabbedPane();
    tabbedPane.addTab("aaaaaaaaaaaaaaaa", new JPanel());
    tabbedPane.addTab("bbbbbbbb", new JPanel());
    tabbedPane.addTab("ccc", new JPanel());

    JPanel p = new JPanel(new BorderLayout());
    p.add(new JLayer<JTabbedPane>(tabbedPane, new CloseableTabbedPaneLayerUI()));
    p.add(new JButton(new AbstractAction("add tab") {
      @Override public void actionPerformed(ActionEvent e) {
        tabbedPane.addTab("test", new JPanel());
      }
    }), 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 CloseableTabbedPaneTest().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}

class CloseableTabbedPaneLayerUI extends LayerUI<JTabbedPane> {
  private final JPanel p = new JPanel();
  private final Point pt = new Point(-100, -100);
  private final JButton button = new JButton("x") {
    @Override public Dimension getPreferredSize() {
      return new Dimension(16, 16);
    }
  };
  public CloseableTabbedPaneLayerUI() {
    super();
    button.setBorder(BorderFactory.createEmptyBorder());
    button.setFocusPainted(false);
    button.setBorderPainted(false);
    button.setContentAreaFilled(false);
    button.setRolloverEnabled(false);
  }
  @Override public void paint(Graphics g, JComponent c) {
    super.paint(g, c);
    if (c instanceof JLayer) {
      JLayer jlayer = (JLayer) c;
      JTabbedPane tabPane = (JTabbedPane) jlayer.getView();
      for (int i = 0; i < tabPane.getTabCount(); i++) {
        Rectangle rect = tabPane.getBoundsAt(i);
        Dimension d = button.getPreferredSize();
        int x = rect.x + rect.width - d.width - 2;
        int y = rect.y + (rect.height - d.height) / 2;
        Rectangle r = new Rectangle(x, y, d.width, d.height);
        button.setForeground(r.contains(pt) ? Color.RED : Color.BLACK);
        SwingUtilities.paintComponent(g, button, p, r);
      }
    }
  }
  @Override public void installUI(JComponent c) {
    super.installUI(c);
    ((JLayer)c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
  }
  @Override public void uninstallUI(JComponent c) {
    ((JLayer)c).setLayerEventMask(0);
    super.uninstallUI(c);
  }
  @Override protected void processMouseEvent(MouseEvent e, JLayer<? extends JTabbedPane> l) {
    if (e.getID() == MouseEvent.MOUSE_CLICKED) {
      pt.setLocation(e.getPoint());
      JTabbedPane tabbedPane = (JTabbedPane) l.getView();
      int index = tabbedPane.indexAtLocation(pt.x, pt.y);
      if (index >= 0) {
        Rectangle rect = tabbedPane.getBoundsAt(index);
        Dimension d = button.getPreferredSize();
        int x = rect.x + rect.width - d.width - 2;
        int y = rect.y + (rect.height - d.height) / 2;
        Rectangle r = new Rectangle(x, y, d.width, d.height);
        if (r.contains(pt)) {
          tabbedPane.removeTabAt(index);
        }
      }
      l.getView().repaint();
    }
  }
  @Override protected void processMouseMotionEvent(MouseEvent e, JLayer<? extends JTabbedPane> l) {
    pt.setLocation(e.getPoint());
    JTabbedPane tabbedPane = (JTabbedPane) l.getView();
    int index = tabbedPane.indexAtLocation(pt.x, pt.y);
    if (index >= 0) {
      tabbedPane.repaint(tabbedPane.getBoundsAt(index));
    } else {
      tabbedPane.repaint();
    }
  }
}

Edit:

Here is an example using a GlassPane(Note: this is NOT tested at all):

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class CloseableTabbedPaneTest2 {
  public JComponent makeUI() {
    UIManager.put("TabbedPane.tabInsets", new Insets(2, 2, 2, 50));
    final JTabbedPane tabbedPane = new JTabbedPane();
    tabbedPane.addTab("aaaaaaaaaaaaaaaa", new JPanel());
    tabbedPane.addTab("bbbbbbbb", new JPanel());
    tabbedPane.addTab("ccc", new JPanel());

    JPanel p = new JPanel(new BorderLayout());
    //p.setBorder(BorderFactory.createLineBorder(Color.RED, 10));
    p.add(tabbedPane);
    p.add(new JButton(new AbstractAction("add tab") {
      @Override public void actionPerformed(ActionEvent e) {
        tabbedPane.addTab("test", new JScrollPane(new JTree()));
      }
    }), BorderLayout.SOUTH);

    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        JPanel gp = new CloseableTabbedPaneGlassPane(tabbedPane);
        tabbedPane.getRootPane().setGlassPane(gp);
        gp.setOpaque(false);
        gp.setVisible(true);
      }
    });

    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 CloseableTabbedPaneTest2().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}

class CloseableTabbedPaneGlassPane extends JPanel {
  private final Point pt = new Point(-100, -100);
  private final JButton button = new JButton("x") {
    @Override public Dimension getPreferredSize() {
      return new Dimension(16, 16);
    }
  };
  private final JTabbedPane tabbedPane;
  private final Rectangle buttonRect = new Rectangle(button.getPreferredSize());

  public CloseableTabbedPaneGlassPane(JTabbedPane tabbedPane) {
    super();
    this.tabbedPane = tabbedPane;
    MouseAdapter h = new Handler();
    tabbedPane.addMouseListener(h);
    tabbedPane.addMouseMotionListener(h);
    button.setBorder(BorderFactory.createEmptyBorder());
    button.setFocusPainted(false);
    button.setBorderPainted(false);
    button.setContentAreaFilled(false);
    button.setRolloverEnabled(false);
  }
  @Override public void paintComponent(Graphics g) {
    Point glassPt = SwingUtilities.convertPoint(tabbedPane, 0, 0, this);
    for (int i = 0; i < tabbedPane.getTabCount(); i++) {
      Rectangle tabRect = tabbedPane.getBoundsAt(i);
      int x = tabRect.x + tabRect.width - buttonRect.width - 2;
      int y = tabRect.y + (tabRect.height - buttonRect.height) / 2;
      buttonRect.setLocation(x, y);
      button.setForeground(buttonRect.contains(pt) ? Color.RED : Color.BLACK);
      buttonRect.translate(glassPt.x, glassPt.y);
      SwingUtilities.paintComponent(g, button, this, buttonRect);
    }
  }
  class Handler extends MouseAdapter {
    @Override public void mouseClicked(MouseEvent e) {
      pt.setLocation(e.getPoint());
      int index = tabbedPane.indexAtLocation(pt.x, pt.y);
      if (index >= 0) {
        Rectangle tabRect = tabbedPane.getBoundsAt(index);
        int x = tabRect.x + tabRect.width - buttonRect.width - 2;
        int y = tabRect.y + (tabRect.height - buttonRect.height) / 2;
        buttonRect.setLocation(x, y);
        if (buttonRect.contains(pt)) {
          tabbedPane.removeTabAt(index);
        }
      }
      tabbedPane.repaint();
    }
    @Override public void mouseMoved(MouseEvent e) {
      pt.setLocation(e.getPoint());
      int index = tabbedPane.indexAtLocation(pt.x, pt.y);
      if (index >= 0) {
        tabbedPane.repaint(tabbedPane.getBoundsAt(index));
      } else {
        tabbedPane.repaint();
      }
    }
  }
}

I'm using this one: http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TabComponentsDemoProject/src/components/ButtonTabComponent.java

The close button is painted by this itself so if can be placed anywhere.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!