Java 如何以通用方式将鼠标事件传播到父容器

Java 如何以通用方式将鼠标事件传播到父容器,java,swing,Java,Swing,我编写了以下代码,用于开发JTabbedPane“选项卡组件”。我在自定义选项卡窗格中使用setTabComponentAt(index,tabComponent)进行设置 package com.example.tabpane; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D;

我编写了以下代码,用于开发JTabbedPane“选项卡组件”。我在自定义选项卡窗格中使用setTabComponentAt(index,tabComponent)进行设置

package com.example.tabpane;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JLabel;
import javax.swing.event.EventListenerList;

import com.example.SwingUtilities;

public class TabComponent extends JLabel {
    private Point mousePointerAt;
    private Dimension crossIconDim = new Dimension(15, 15);
    private int crossIconDimLeftPadding = 5;
    private EventListenerList eventListeners = new EventListenerList();
    public TabComponent() {
        initComponent();
    }
    public TabComponent(String title) {
        super(title);   
        setOpaque(false);
        initComponent();
    }

    //You don't have to override the getSize() versions. It basically calls getWidth() and getHeight()
    //Also you should NOT override getWidth() and getHeight() because the layout managers set that properties
    //If you do the borders right/bottom edges won't be painted correctly

    @Override
    public Dimension getPreferredSize() {
        Dimension preferredSize = super.getPreferredSize();
        int width = (int)preferredSize.getWidth();
        int height = (int)preferredSize.getHeight();
        width += crossIconDim.getWidth() + crossIconDimLeftPadding;
        height = Math.max(height, (int) crossIconDim.getHeight());
        Dimension newSize = new Dimension(width, height);       
        return newSize;
    }

    @Override
    public Dimension getMinimumSize() {
        Dimension preferredSize = super.getMinimumSize();
        int width = (int)preferredSize.getWidth();
        int height = (int)preferredSize.getHeight();
        width += crossIconDim.getWidth() + crossIconDimLeftPadding;
        height = Math.max(height, (int) crossIconDim.getHeight());
        Dimension newSize = new Dimension(width, height);       
        return newSize;
    }

    @Override
    public Dimension getMaximumSize() {
        Dimension preferredSize = super.getMaximumSize();
        int width = (int)preferredSize.getWidth();
        int height = (int)preferredSize.getHeight();
        width += crossIconDim.getWidth() + crossIconDimLeftPadding;
        height = Math.max(height, (int) crossIconDim.getHeight());
        Dimension newSize = new Dimension(width, height);       
        return newSize;
    }   

    private void initComponent() {

        addMouseMotionListener(new MouseMotionAdapter() {           
            @Override
            public void mouseMoved(MouseEvent e) {
                SwingUtilities.bubbleEvent(e);
                TabComponent tab = (TabComponent) e.getComponent();
                tab.mousePointerAt = e.getPoint();
                tab.repaint();
            }
        });

        addMouseListener(new MouseAdapter() {           
            @Override
            public void mouseExited(MouseEvent e) {
                SwingUtilities.bubbleEvent(e);
                TabComponent tab = (TabComponent) e.getComponent();
                tab.mousePointerAt = null;
                tab.repaint();
            }
            @Override
            public void mouseClicked(MouseEvent e) {
                SwingUtilities.bubbleEvent(e);
                TabComponent tab = (TabComponent) e.getComponent();
                if (tab.mousePointerAt != null) {
                    int componentWidth = tab.getWidth();
                    Insets insets = tab.getInsets();
                    Point gfxXlatePoint = new Point(componentWidth - (int) crossIconDim.getWidth() - insets.right, insets.top);     
                    Rectangle paintRectangle = new Rectangle(gfxXlatePoint, crossIconDim);
                    if (mousePointerAt != null) {
                        if (paintRectangle.contains(mousePointerAt)) {
                            tab.fireTabEvent(new TabEvent(tab, TabEvent.TAB_CLOSING));
                        }
                    }
                }
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D gfx = (Graphics2D) g.create();

        int componentWidth = getWidth();
        int ovalRadius = (int) (crossIconDim.getWidth());           
        Insets insets = getInsets();
        Point gfxXlatePoint = new Point(componentWidth - (int) crossIconDim.getWidth() - insets.right, insets.top);     
        Rectangle paintRectangle = new Rectangle(gfxXlatePoint, crossIconDim);
        gfx.translate(gfxXlatePoint.x, gfxXlatePoint.y);

        boolean mouseOverCloseCue = false;      
        if (mousePointerAt != null) {
            if (paintRectangle.contains(mousePointerAt)) {
                mouseOverCloseCue = true;
            }
        }
        gfx.setStroke(new BasicStroke(2));
        gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Insets crossIconPadding = new Insets(5, 5, 5, 5);
        if (mouseOverCloseCue) {
            gfx.setColor(new Color(0xf49f94));
            //The mouse pointer is on the x mark
            gfx.fillOval(0, 0, ovalRadius, ovalRadius);
            gfx.setColor(Color.WHITE);          
            gfx.drawLine(0 + crossIconPadding.left, 0 + crossIconPadding.top, (int)crossIconDim.getWidth() - crossIconPadding.right, (int)crossIconDim.getHeight() - crossIconPadding.bottom);
            gfx.drawLine((int)crossIconDim.getWidth() - crossIconPadding.right, 0 + crossIconPadding.top, 0 + crossIconPadding.left, (int)crossIconDim.getHeight() - crossIconPadding.bottom);
        } else {
            gfx.setColor(Color.BLACK);
            gfx.drawLine(0 + crossIconPadding.left, 0 + crossIconPadding.top, (int)crossIconDim.getWidth() - crossIconPadding.right, (int)crossIconDim.getHeight() - crossIconPadding.bottom);
            gfx.drawLine((int)crossIconDim.getWidth() - crossIconPadding.right, 0 + crossIconPadding.top, 0 + crossIconPadding.left, (int)crossIconDim.getHeight() - crossIconPadding.bottom);
        }
        gfx.dispose();
    }   

    public void addTabEventListener(TabEventListener listener) {
        eventListeners.add(TabEventListener.class, listener);
    }

    public void removeTabEventListener(TabEventListener listener) {
        eventListeners.remove(TabEventListener.class, listener);
    }

    protected void fireTabEvent(TabEvent evt) {
        Object[] listeners = eventListeners.getListeners(TabEventListener.class);
        for (int i = 0, n = listeners.length; i < n; i++) {
            ((TabEventListener) listeners[i]).handleEvent(evt);
        }
    }
}
问题是,选项卡组件无法工作,因为它正在使用鼠标事件。当用户单击tab组件时,TabbedPane不会像预期的那样更改选项卡。我可以自己点击并改变标签的可视性,但我在想,这是否是另一种让事件浮出水面的方式。我试着写一个通用的事件冒泡器,但它的Through StackOverflower错误

package com.example;

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;

public class SwingUtilities {
    public static void bubbleEvent(AWTEvent event) {
        Component source = (Component) event.getSource();
        Container parent = source.getParent();
        int i = 0, deep = 10;
        while (parent != null && i < deep) {
            i++;
            System.out.println("Dispatching to the parent with i = " + i);
            parent.dispatchEvent(event);
            parent = parent.getParent();
        }
    }
}
package.com.example;
导入java.awt.AWTEvent;
导入java.awt.Component;
导入java.awt.Container;
公营部门{
公共静态无效bubbleEvent(AWTEEvent事件){
组件源=(组件)事件。getSource();
容器父级=source.getParent();
int i=0,deep=10;
while(parent!=null&&i
您的想法是错误的

  • 当鼠标位于“关闭”图标上方时,您只希望鼠标事件触发“关闭”事件
  • 所有其他情况下,您都需要选项卡的默认行为
为什么不创建一个
CloseIcon
类,然后将其包含在
TabComponent
中,而不是创建一个尝试同时执行这两项操作的单一、全emcompassing类呢

通过这种方式,您可以分离逻辑并隔离责任,而无需求助于肮脏的黑客和变通方法来实现它

(对不起,我有点破坏了你的代码)

CloseIcon
所有这一切只是绘制关闭图标并响应鼠标事件。单击时,它会触发一个
ActionEvent
(作为一般事件)供其他组件侦听

public class CloseIcon extends JPanel {

    private static final Dimension CROSS_ICON_SIZE = new Dimension(15, 15);
    private static final int CROSS_ICON_INSET = 5;
    private boolean mouseInTheHouse = false;

    public CloseIcon() {
        setOpaque(false);

        addMouseListener(new MouseAdapter() {

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

            @Override
            public void mouseEntered(MouseEvent e) {
                mouseInTheHouse = true;
            }

            @Override
            public void mouseExited(MouseEvent e) {
                mouseInTheHouse = false;
            }

        });
    }

    public void addActionListener(ActionListener listener) {
        listenerList.add(ActionListener.class, listener);
    }

    protected void fireActionPerformed() {
        ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
        if (listeners.length > 0) {
            ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "Closed");
            for (ActionListener listener : listeners) {
                listener.actionPerformed(evt);
            }
        }
    }

    //You don't have to override the getSize() versions. It basically calls getWidth() and getHeight()
    //Also you should NOT override getWidth() and getHeight() because the layout managers set that properties
    //If you do the borders right/bottom edges won't be painted correctly
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(CROSS_ICON_SIZE.width + CROSS_ICON_INSET, CROSS_ICON_SIZE.height);
    }

    @Override
    public Dimension getMinimumSize() {
        return getPreferredSize();
    }

    @Override
    public Dimension getMaximumSize() {
        return getPreferredSize();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D gfx = (Graphics2D) g.create();

        int componentWidth = getWidth();
        int ovalRadius = (int) (CROSS_ICON_SIZE.getWidth());
        Insets insets = getInsets();
        Point gfxXlatePoint = new Point(componentWidth - (int) CROSS_ICON_SIZE.getWidth() - insets.right, insets.top);
        Rectangle paintRectangle = new Rectangle(gfxXlatePoint, CROSS_ICON_SIZE);
        gfx.translate(gfxXlatePoint.x, gfxXlatePoint.y);

        gfx.setStroke(new BasicStroke(2));
        gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Insets crossIconPadding = new Insets(5, 5, 5, 5);
        if (mouseInTheHouse) {
            gfx.setColor(new Color(0xf49f94));
            //The mouse pointer is on the x mark
            gfx.fillOval(0, 0, ovalRadius, ovalRadius);
            gfx.setColor(Color.WHITE);
            gfx.drawLine(0 + crossIconPadding.left, 0 + crossIconPadding.top, (int) CROSS_ICON_SIZE.getWidth() - crossIconPadding.right, (int) CROSS_ICON_SIZE.getHeight() - crossIconPadding.bottom);
            gfx.drawLine((int) CROSS_ICON_SIZE.getWidth() - crossIconPadding.right, 0 + crossIconPadding.top, 0 + crossIconPadding.left, (int) CROSS_ICON_SIZE.getHeight() - crossIconPadding.bottom);
        } else {
            gfx.setColor(Color.BLACK);
            gfx.drawLine(0 + crossIconPadding.left, 0 + crossIconPadding.top, (int) CROSS_ICON_SIZE.getWidth() - crossIconPadding.right, (int) CROSS_ICON_SIZE.getHeight() - crossIconPadding.bottom);
            gfx.drawLine((int) CROSS_ICON_SIZE.getWidth() - crossIconPadding.right, 0 + crossIconPadding.top, 0 + crossIconPadding.left, (int) CROSS_ICON_SIZE.getHeight() - crossIconPadding.bottom);
        }
        gfx.dispose();
    }

}
TabComponent
TabComponent
只是一个
JPanel
,上面有一个
JLabel
CloseIcon
。组件监听
ActionEvents的
CloseIcon
,然后使用该图标触发
TabEvent

public class TabComponent extends JPanel {

    private CloseIcon closeIcon;

    public TabComponent(String title) {
        setLayout(new GridBagLayout());
        setOpaque(false);

        JLabel lblTitle = new JLabel(title);
        closeIcon = new CloseIcon();
        closeIcon.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                fireTabEvent(new TabEvent(this));//, TabEvent.TAB_CLOSING));
            }
        });

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        add(lblTitle, gbc);

        gbc.gridx++;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.NORTHEAST;
        add(closeIcon);

    }

    public void addTabEventListener(TabEventListener listener) {
        listenerList.add(TabEventListener.class, listener);
    }

    public void removeTabEventListener(TabEventListener listener) {
        listenerList.remove(TabEventListener.class, listener);
    }

    protected void fireTabEvent(TabEvent evt) {
        Object[] listeners = listenerList.getListeners(TabEventListener.class);
        for (int i = 0, n = listeners.length; i < n; i++) {
            ((TabEventListener) listeners[i]).handleEvent(evt);
        }
    }

}
public类TabComponent扩展了JPanel{
私人关闭图标关闭图标;
公共选项卡组件(字符串标题){
setLayout(新的GridBagLayout());
设置不透明(假);
JLabel lblTitle=新的JLabel(标题);
closeIcon=新的closeIcon();
addActionListener(新建ActionListener()){
@凌驾
已执行的公共无效操作(操作事件e){
fireTabEvent(新TabEvent(this));/,TabEvent.TAB_CLOSING));
}
});
GridBagConstraints gbc=新的GridBagConstraints();
gbc.gridx=0;
gbc.gridy=0;
gbc.weightx=1;
gbc.anchor=GridBagConstraints.WEST;
添加(lblTitle,gbc);
gbc.gridx++;
gbc.weightx=0;
gbc.anchor=GridBagConstraints.NORTHEAST;
添加(关闭图标);
}
public void addTabEventListener(TabEventListener侦听器){
添加(TabEventListener.class,listener);
}
public void removeTabEventListener(TabEventListener侦听器){
删除(TabEventListener.class,listener);
}
受保护的无效fireTabEvent(TabEvent evt){
Object[]listeners=listenerList.getListeners(TabEventListener.class);
for(int i=0,n=listeners.length;i
可运行的示例。。。
import java.awt.BasicStroke;
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.Component;
导入java.awt.Dimension;
导入java.awt.EventQueue;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.GridBagConstraints;
导入java.awt.GridBagLayout;
导入java.awt.Insets;
导入java.awt.Point;
导入java.awt.Rectangle;
导入java.awt.RenderingHints;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入java.util.EventListener;
导入java.util.EventObject;
导入javaapplication222.Test.TestPane;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
导入javax.swing.JTabbedPane;
导入javax.swing.UIManager;
导入javax.swing.UnsupportedLookAndFeelException;
公开课考试{
公共静态void main(字符串[]args){
新测试();
}
公开考试(){
invokeLater(新的Runnable(){
@凌驾
公开募捐{
试一试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(ClassNotFoundException |实例化Exception | IllegalacessException |不支持ookandfeelException ex){
例如printStackTrace();
}
JFrame=新JFrame(“测试”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(newtestpane());
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
});
}
公共类TestPane扩展了JPanel{
公共测试窗格(){
setLayout(新的BorderLayout());
ClosingTabbedPane ctp=新ClosingTabbedPane();
ctp.addTab(“香蕉”,createPanel(“你好”);
ctp.addTab(“苹果”,createPanel(“Kanchiwa”);
添加(ctp);
}
受保护的JPanel createPanel(字符串消息){
JPanel panel=newjpanel(newgridbagloayout());
JLabel标签=新JLabel(msg);
MouseAdapter ma=新的MouseAdapter(){
@凌驾
穆塞克里公共空间
public class TabComponent extends JPanel {

    private CloseIcon closeIcon;

    public TabComponent(String title) {
        setLayout(new GridBagLayout());
        setOpaque(false);

        JLabel lblTitle = new JLabel(title);
        closeIcon = new CloseIcon();
        closeIcon.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                fireTabEvent(new TabEvent(this));//, TabEvent.TAB_CLOSING));
            }
        });

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        add(lblTitle, gbc);

        gbc.gridx++;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.NORTHEAST;
        add(closeIcon);

    }

    public void addTabEventListener(TabEventListener listener) {
        listenerList.add(TabEventListener.class, listener);
    }

    public void removeTabEventListener(TabEventListener listener) {
        listenerList.remove(TabEventListener.class, listener);
    }

    protected void fireTabEvent(TabEvent evt) {
        Object[] listeners = listenerList.getListeners(TabEventListener.class);
        for (int i = 0, n = listeners.length; i < n; i++) {
            ((TabEventListener) listeners[i]).handleEvent(evt);
        }
    }

}
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.EventListener;
import java.util.EventObject;
import javaapplication222.Test.TestPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());
            ClosingTabbedPane ctp = new ClosingTabbedPane();

            ctp.addTab("Bananas", createPanel("Hello"));
            ctp.addTab("Apples", createPanel("Kanchiwa"));
            add(ctp);
        }

        protected JPanel createPanel(String msg) {

            JPanel panel = new JPanel(new GridBagLayout());
            JLabel label = new JLabel(msg);
            MouseAdapter ma = new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    System.out.println("clicked");
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    System.out.println("in");
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    System.out.println("out");
                }

            };
            label.addMouseListener(ma);
            label.addMouseMotionListener(ma);
            panel.add(label);

            return panel;

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public class ClosingTabbedPane extends JTabbedPane {

        /**
         *
         */
        private static final long serialVersionUID = 1L;

        public ClosingTabbedPane() {
        }

        @Override
        public void addTab(String title, Component component) {
            super.addTab(title, component);
            final int index = getTabCount() - 1;
            TabComponent tabLabel = new TabComponent(title);
            tabLabel.addTabEventListener(new TabEventListener() {
                @Override
                public void handleEvent(TabEvent evt) {
                    System.out.println("Boo");
//                  if (evt.getEventType() == TabEvent.TAB_CLOSING) {
//                      ClosingTabbedPane.this.removeTabAt(index);
//                  }
                }
            });
            setTabComponentAt(index, tabLabel);
        }
    }

    public class TabEvent extends EventObject {

        public TabEvent(Object source) {
            super(source);
        }

    }

    public interface TabEventListener extends EventListener {

        public void handleEvent(TabEvent evt);

    }

    public static class CloseIcon extends JPanel {

        private static final Dimension CROSS_ICON_SIZE = new Dimension(15, 15);
        private static final int CROSS_ICON_INSET = 5;
        private boolean mouseInTheHouse = false;

        public CloseIcon() {
            setOpaque(false);

            addMouseListener(new MouseAdapter() {

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

                @Override
                public void mouseEntered(MouseEvent e) {
                    mouseInTheHouse = true;
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    mouseInTheHouse = false;
                }

            });
        }

        public void addActionListener(ActionListener listener) {
            listenerList.add(ActionListener.class, listener);
        }

        protected void fireActionPerformed() {
            ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
            if (listeners.length > 0) {
                ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "Closed");
                for (ActionListener listener : listeners) {
                    listener.actionPerformed(evt);
                }
            }
        }

        //You don't have to override the getSize() versions. It basically calls getWidth() and getHeight()
        //Also you should NOT override getWidth() and getHeight() because the layout managers set that properties
        //If you do the borders right/bottom edges won't be painted correctly
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(CROSS_ICON_SIZE.width + CROSS_ICON_INSET, CROSS_ICON_SIZE.height);
        }

        @Override
        public Dimension getMinimumSize() {
            return getPreferredSize();
        }

        @Override
        public Dimension getMaximumSize() {
            return getPreferredSize();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D gfx = (Graphics2D) g.create();

            int componentWidth = getWidth();
            int ovalRadius = (int) (CROSS_ICON_SIZE.getWidth());
            Insets insets = getInsets();
            Point gfxXlatePoint = new Point(componentWidth - (int) CROSS_ICON_SIZE.getWidth() - insets.right, insets.top);
            Rectangle paintRectangle = new Rectangle(gfxXlatePoint, CROSS_ICON_SIZE);
            gfx.translate(gfxXlatePoint.x, gfxXlatePoint.y);

            gfx.setStroke(new BasicStroke(2));
            gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            Insets crossIconPadding = new Insets(5, 5, 5, 5);
            if (mouseInTheHouse) {
                gfx.setColor(new Color(0xf49f94));
                //The mouse pointer is on the x mark
                gfx.fillOval(0, 0, ovalRadius, ovalRadius);
                gfx.setColor(Color.WHITE);
                gfx.drawLine(0 + crossIconPadding.left, 0 + crossIconPadding.top, (int) CROSS_ICON_SIZE.getWidth() - crossIconPadding.right, (int) CROSS_ICON_SIZE.getHeight() - crossIconPadding.bottom);
                gfx.drawLine((int) CROSS_ICON_SIZE.getWidth() - crossIconPadding.right, 0 + crossIconPadding.top, 0 + crossIconPadding.left, (int) CROSS_ICON_SIZE.getHeight() - crossIconPadding.bottom);
            } else {
                gfx.setColor(Color.BLACK);
                gfx.drawLine(0 + crossIconPadding.left, 0 + crossIconPadding.top, (int) CROSS_ICON_SIZE.getWidth() - crossIconPadding.right, (int) CROSS_ICON_SIZE.getHeight() - crossIconPadding.bottom);
                gfx.drawLine((int) CROSS_ICON_SIZE.getWidth() - crossIconPadding.right, 0 + crossIconPadding.top, 0 + crossIconPadding.left, (int) CROSS_ICON_SIZE.getHeight() - crossIconPadding.bottom);
            }
            gfx.dispose();
        }

    }

    public class TabComponent extends JPanel {

        private CloseIcon closeIcon;

        public TabComponent(String title) {
            setLayout(new GridBagLayout());
            setOpaque(false);

            JLabel lblTitle = new JLabel(title);
            closeIcon = new CloseIcon();
            closeIcon.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    fireTabEvent(new TabEvent(this));//, TabEvent.TAB_CLOSING));
                }
            });

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 1;
            gbc.anchor = GridBagConstraints.WEST;
            add(lblTitle, gbc);

            gbc.gridx++;
            gbc.weightx = 0;
            gbc.anchor = GridBagConstraints.NORTHEAST;
            add(closeIcon);

        }

        public void addTabEventListener(TabEventListener listener) {
            listenerList.add(TabEventListener.class, listener);
        }

        public void removeTabEventListener(TabEventListener listener) {
            listenerList.remove(TabEventListener.class, listener);
        }

        protected void fireTabEvent(TabEvent evt) {
            Object[] listeners = listenerList.getListeners(TabEventListener.class);
            for (int i = 0, n = listeners.length; i < n; i++) {
                ((TabEventListener) listeners[i]).handleEvent(evt);
            }
        }

    }
}