我正在尝试创建一个选项卡窗格,用户可以在其中双击该选项卡以编辑其标题。到目前为止,我已经能够创建一个选项卡组件,其中JPanel
和JTextField
彼此重叠,当您双击{{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
答案 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());
}
}
});