具有鼠标侦听器的JTabbedPane选项卡

时间:2018-10-28 15:16:33

标签: java swing mouselistener jtabbedpane

我正在尝试创建一个选项卡窗格,用户可以在其中双击该选项卡以编辑其标题。到目前为止,我已经能够创建一个选项卡组件,其中JPanelJTextField彼此重叠,当您双击{{1}时,它会切换到JTextField },并在按 Enter 时返回到JPanel

JPanel

当我将public class EditablePanel extends JPanel { private JLabel label; private JTextField field; public EditablePanel(String title) { super(); setLayout(new OverlayLayout(this)); setOpaque(false); add(label = new JLabel(title)); label.setFocusable(false); field = new JTextField(title); field.setBorder(BorderFactory.createEmptyBorder()); field.setVisible(false); field.addActionListener((e) -> finish(true)); add(field); label.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { label.setVisible(false); field.setVisible(true); field.requestFocusInWindow(); field.selectAll(); } } }); } private void finish(boolean commit) { label.setText(field.getText()); label.setVisible(true); field.setVisible(false); } } 中选项卡的组件设置为该JTabbedPane的实例时,如果鼠标悬停在标签上,则无法再单击该选项卡来选择它。此外,如果当鼠标悬停在选项卡上时LAF会执行某些操作(例如像Windows一样更改其颜色),则当鼠标悬停在标签上时,LAF会停止应用。如果单击EditablePanel以外的区域,则可以切换选项卡,但是如果单击JLabel,则不能切换选项卡。我希望它能正常工作,以便如果我单击选项卡中的任何位置,它将切换到该选项卡,但是如果我双击选项卡,它将开始编辑选项卡标题。

我尝试在JLabel中使用getMouseListeners将面板的鼠标事件转发到EditablePanel,但似乎忽略了它们。有没有一种方法可以将此组件用作选项卡组件,同时又保留鼠标悬停和单击以更改选项卡的现有功能?如果没有,是否可以扩展JLabel以获得我想要的可编辑标题功能?

这里有一个完整的SCCM演示了我的问题:

JTabbedPane

3 个答案:

答案 0 :(得分:0)

  

有没有一种方法可以扩展JTabbedPane以获得我想要的可编辑标题功能?

我将MouseListener添加到选项卡式窗格。

然后在mouseClicked(...)事件中,您可以检查是否有双击并在选项卡顶部显示JTextField。在文本字段上按Enter键时,将从选项卡式窗格中删除该文本字段。

因此,显示文本字段的基础是:

JTabbedPane tabbedPane = (JTabbedPane)e.getComponent();
TabbedPaneUI ui = tabbedPane.getUI();

int tab = ui.tabForCoordinate(tabbedfPane, e.getX(), e.getY());

if (tab != -1) // I believe -1 is returned if you don't click on a tab
{
    Rectangle bounds = ui.getTabBounds(tabbedPane, tab);
    JTextField textField = new JTextField();
    textField.setText(...);
    textField.setBounds( bounds );
    textField.addActionListener(...);
    tabbedPane.add( textField );
    tappedPane.repaint();
}

然后在ActionListener中,您将获取文本并更新选项卡标题,然后从选项卡式窗格中删除该文本字段。

现在,该选项卡应能正常工作,因为文本字段仅在您编辑文本标题时临时显示。

注意,这基本上就是JTable编辑器的工作方式。双击单元格时,将在该单元格上方的表格中添加一个文本字段,然后在完成编辑后将其删除。

答案 1 :(得分:0)

作为camickr建议的替代方案,可以使用MouseListener来将所有事件分派到JTabbedPane。这样可以达到不影响其他行为的预期效果,并且仍然可以处理双击的特殊情况。

这里是MCVE,我还修复了编辑行为,因为我添加了焦点监听器,当在编辑过程中选择了新标签时(即确认未确认 时,基本上取消了编辑)通过按 Enter )。

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.OverlayLayout;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class EditablePanel extends JPanel
{
    private JLabel label;
    private JTextField field;

    public EditablePanel(String title)
    {
        super();
        setLayout(new OverlayLayout(this));
        setOpaque(false);

        add(label = new JLabel(title));
        label.setFocusable(false);

        field = new JTextField(title);
        field.setBorder(BorderFactory.createEmptyBorder());
        field.setVisible(false);
        field.addActionListener((e) -> finish(true));
        field.addFocusListener(new FocusListener()
        {
            @Override
            public void focusLost(FocusEvent e)
            {
                finish(false);
            }

            @Override
            public void focusGained(FocusEvent e)
            {
                // Nothing to do here
            }
        });
        add(field);

        TabMouseAdapter mouseAdapter = new TabMouseAdapter()
        {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                super.mouseClicked(e);
                if (e.getClickCount() == 2)
                {
                    label.setVisible(false);
                    field.setVisible(true);
                    field.requestFocusInWindow();
                    field.selectAll();
                }
            }
            @Override
            public void mousePressed(MouseEvent e)
            {
                super.mousePressed(e);
                finish(false);
            }

        };
        label.addMouseListener(mouseAdapter);
    }

    static class TabMouseAdapter implements MouseListener
    {
        @Override
        public void mouseClicked(MouseEvent e)
        {
            redispatch(e);
        }

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

        @Override
        public void mouseReleased(MouseEvent e)
        {
            redispatch(e);
        }

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

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

        private void redispatch(MouseEvent e)
        {
            Component source = e.getComponent();
            Component target = source.getParent();
            while (true)
            {
                if (target == null)
                {
                    break;
                }
                if (target instanceof JTabbedPane)
                {
                    break;
                }
                target = target.getParent();
            }
            if (target != null)
            {
                MouseEvent targetEvent =
                    SwingUtilities.convertMouseEvent(source, e, target);
                target.dispatchEvent(targetEvent);
            }
        }
    }

    private void finish(boolean commit)
    {
        if (commit)
        {
            label.setText(field.getText());
        }
        label.setVisible(true);
        field.setVisible(false);
        field.transferFocusUpCycle();
    }

    public static void main(String[] args)
    {
        JFrame frame = new JFrame("Editable Tab Headers");
        frame.setPreferredSize(new Dimension(400, 300));
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JTabbedPane pane = new JTabbedPane();
        pane.addTab("First Tab", new JLabel("First tab contents"));
        pane.addTab("Second Tab", new JLabel("Second tab contents"));
        pane.setTabComponentAt(0, new EditablePanel("First Tab"));
        pane.setTabComponentAt(1, new EditablePanel("Second Tab"));
        frame.add(pane);

        frame.pack();
        frame.setVisible(true);
    }
}

答案 2 :(得分:0)

例如,如果您要将popupmenu添加到第i个标签 您可以使用所选标​​签和第i个标签的相等性。 在我的示例中,我想将popupmenu添加到我的第一个标签中,这样 我应该检查selectedtab和第一个选项卡(index = 0)的相等性

您可以使用这种方式:

JTabbedPane tabs=new JTabbedPane();
JPopupMenu popupMenu=new JPopupMenu("Edit");
popupMenu.add(new JMenuItem("Cut"));
popupMenu.add(new JMenuItem("Copy"));
JPanel bodyPanel=new JPanel();
tabs.add("Body",bodyPanel);
tabs.add("DummyTab",new JPanel());

tabs.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            if(tabs.getSelectedComponent().equals(tabs.getComponentAt(0))){
                popupMenu.show(bodyPanel,e.getX(),e.getY());
            }
        }
    });