关闭的JTabbedPane—关闭按钮的对齐方式。

时间:2022-03-28 11:07:19

I have implemented my own closeable JTabbedPane (essentially following advice from here - by extending JTabbedPane and overriding some methods and calling setTabComponentAt(...)). It works perfectly except one thing - when there are too many tabs to fit on one row (when there are 2 or more rows of tabs), the cross button/icon is not aligned to the right of the tab but it remains next to the tab title, which looks ugly. I've tried the demo from Java tutorials and it suffers from the same problem.

我已经实现了我自己的可关闭的JTabbedPane(本质上是下面的建议——通过扩展JTabbedPane并覆盖一些方法并调用setTabComponentAt(…))。它工作得很好,除了一件事——当有太多的选项卡要放在一行上时(当有两行或更多的选项卡时),交叉按钮/图标没有对齐到选项卡的右边,但是它仍然在选项卡标题旁边,看起来很难看。我尝试过Java教程中的演示,它也有同样的问题。

What I want is that the cross button/icon is always aligned to the very right, but the text is always aligned to the center. Can this be achieved by some layouting tricks? Note: I do not want to implement a custom TabbedPaneUI as this leads to other problems.

我想要的是交叉按钮/图标总是对齐到最右边,但是文本总是对齐到中心。这能通过一些布图技巧来实现吗?注意:我不想实现定制的TabbedPaneUI,因为这会导致其他问题。

UPDATE I'm forced to use Java 6

更新我*使用Java 6

The complete code is below, just run it and add 5 or more tabs.

完整的代码如下,只需运行它并添加5个或更多的选项卡。

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;


/**
 * CloseableTabbedPane is a tabbed pane with a close icon on the right side of all tabs making it possible to close a tab.
 * You can pass an instance of TabClosingListener to one of the constructors to react to tab closing.
 * 
 * @author WiR
 */
public class CloseableTabbedPane extends JTabbedPane {

    public static interface TabClosingListener {
        /**
         * @param aTabIndex the index of the tab that is about to be closed
         * @return true if the tab can be really closed
         */
        public boolean tabClosing(int aTabIndex);

        /**
         * @param aTabIndex the index of the tab that is about to be closed
         * @return true if the tab should be selected before closing
         */
        public boolean selectTabBeforeClosing(int aTabIndex);
    }

    private TabClosingListener tabClosingListener;
    private String iconFileName = "images/cross.gif";
    private String selectedIconFileName = "images/cross_selected.gif";

    private static Icon CLOSING_ICON;
    private static Icon CLOSING_ICON_SELECTED;

    private class PaintedCrossIcon implements Icon {

        int size = 10;

        @Override
        public void paintIcon(Component c, Graphics g, int x, int y) {
            g.drawLine(x, y, x + size, y + size);
            g.drawLine(x + size, y, x, y + size);
        }

        @Override
        public int getIconWidth() {
            return size;
        }

        @Override
        public int getIconHeight() {
            return size;
        }

    }

    public CloseableTabbedPane() {
        super();
    }

    public CloseableTabbedPane(TabClosingListener aTabClosingListener) {
        super();
        tabClosingListener = aTabClosingListener;
    }

    /**
     * Sets the file name of the closing icon along with the optional variant of the icon when the mouse is over the icon.
     */
    public void setClosingIconFileName(String aIconFileName, String aSelectedIconFileName) {
        iconFileName = aIconFileName;
        selectedIconFileName = aSelectedIconFileName;
    }

    /**
     * Makes the close button at the specified indes visible or invisible
     */
    public void setCloseButtonVisibleAt(int aIndex, boolean aVisible) {
        CloseButtonTab cbt = (CloseButtonTab) getTabComponentAt(aIndex);
        cbt.closingLabel.setVisible(aVisible);
    }

    @Override
    public void insertTab(String title, Icon icon, Component component, String tip, int index) {
        super.insertTab(title, icon, component, tip, index);
        setTabComponentAt(index, new CloseButtonTab(component, title, icon));
    }

    @Override
    public void setTitleAt(int index, String title) {
        super.setTitleAt(index, title);
        CloseButtonTab cbt = (CloseButtonTab) getTabComponentAt(index);
        cbt.label.setText(title);
    }

    @Override
    public void setIconAt(int index, Icon icon) {
        super.setIconAt(index, icon);
        CloseButtonTab cbt = (CloseButtonTab) getTabComponentAt(index);
        cbt.label.setIcon(icon);
    }

    @Override
    public void setComponentAt(int index, Component component) {
        CloseButtonTab cbt = (CloseButtonTab) getTabComponentAt(index);
        super.setComponentAt(index, component);
        cbt.tab = component;
    }

    //note: setToolTipTextAt(int) must NOT be overridden !

    private Icon getImageIcon(String aImageName) {
        URL imageUrl = CloseableTabbedPane.class.getClassLoader().getResource(aImageName);
        if (imageUrl == null) {
            return new PaintedCrossIcon();
        }
        ImageIcon result = new ImageIcon(imageUrl);
        if (result.getIconWidth() != -1) {
            return result;
        } else {
            return null;
        }
    }

    private class CloseButtonTab extends JPanel {
        private Component tab;
        private JLabel label;
        private JLabel closingLabel;

        public CloseButtonTab(Component aTab, String aTitle, Icon aIcon) {
            tab = aTab;
            setOpaque(false);
            setLayout(new GridBagLayout());
            setVisible(true);

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(0, 0, 0, 5);

            label = new JLabel(aTitle);
            label.setIcon(aIcon);
            add(label, gbc);
            if (CLOSING_ICON == null) {
                CLOSING_ICON = getImageIcon(iconFileName);
                CLOSING_ICON_SELECTED = getImageIcon(selectedIconFileName);
            }
            closingLabel = new JLabel(CLOSING_ICON);
            closingLabel.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    JTabbedPane tabbedPane = (JTabbedPane) getParent().getParent();
                    int tabIndex = indexOfComponent(tab);
                    if (tabClosingListener != null) {
                        if (tabClosingListener.selectTabBeforeClosing(tabIndex)) {
                            tabbedPane.setSelectedIndex(tabIndex);
                        }
                        if (tabClosingListener.tabClosing(tabIndex)) {
                            tabbedPane.removeTabAt(tabIndex);
                        }
                    } else {
                        tabbedPane.removeTabAt(tabIndex);
                    }
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    if (CLOSING_ICON_SELECTED != null) {
                        closingLabel.setIcon(CLOSING_ICON_SELECTED);
                    }
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    if (CLOSING_ICON_SELECTED != null) {
                        closingLabel.setIcon(CLOSING_ICON);
                    }
                }
            });
            gbc.insets = new Insets(0, 0, 0, 0);
            add(closingLabel, gbc);
        }
    }

    static int count = 0;

    /**
     * For testing purposes.
     * 
     */
    public static void main(String[] args) {

        final JTabbedPane tabbedPane = new CloseableTabbedPane();
        tabbedPane.addTab("test" + count, new JPanel());
        count++;
        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.add(tabbedPane, BorderLayout.CENTER);

        JButton addButton = new JButton("Add tab");
        addButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                tabbedPane.addTab("test" + count, new JPanel());
                count++;
            }
        });
        mainPanel.add(addButton, BorderLayout.SOUTH);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(700,  400);
        frame.getContentPane().add(mainPanel);
        frame.setVisible(true);
    }
}

2 个解决方案

#1


3  

Here is one possible implementation using JLayer:

下面是一个使用JLayer的可能实现:

关闭的JTabbedPane—关闭按钮的对齐方式。

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();
      }
    }
  }
}

#2


0  

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

我使用的是这个:http://docs.oracle.com/javase/tutorial/uiswing/examples/components/tabcomponentsdemoproject/src/components/buttontabcomponenttabenttabenttabenttable .java

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

关闭按钮是由它自己绘制的,所以如果可以放置在任何地方。

#1


3  

Here is one possible implementation using JLayer:

下面是一个使用JLayer的可能实现:

关闭的JTabbedPane—关闭按钮的对齐方式。

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();
      }
    }
  }
}

#2


0  

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

我使用的是这个:http://docs.oracle.com/javase/tutorial/uiswing/examples/components/tabcomponentsdemoproject/src/components/buttontabcomponenttabenttabenttabenttable .java

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

关闭按钮是由它自己绘制的,所以如果可以放置在任何地方。