繁体   English   中英

Java-将选项卡添加到JTabbedPane导致StackOverflowError(禁用触发ChangeEvent?)

[英]Java - Adding tab to JTabbedPane causing StackOverflowError (Disabling a firing ChangeEvent?)

嘿StackOverflow社区,我遇到了StackOverflow问题。

当选择[+]选项卡时,我很难在GUI的JTabbedPane容器中添加新选项卡。 到目前为止,每当我单击[+]选项卡时,都会附加新选项卡,直到发生StackOverflowError。

当满足以下条件时,将向JTabbedPane添加新选项卡。

if(songPanel.getSelectedIndex()==songPanel.getTabCount()-1){
...
}

我试图恢复到先前选择的选项卡,以避免将选项卡重复添加到JTabbedPane,但无济于事。 触发ChangeEvent执行器后,它会无限期保持打开状态吗? 我没有在SE7 API中遇到任何有用的东西。

相关代码(不可编译,摘自较大的程序。可能会缺少方括号,仅是因为我复制粘贴了该代码的摘录,并容易出错)

@Override
    public void init(){
        setLayout(new GridLayout(MAIN_LAYOUT_ROWS, MAIN_LAYOUT_COLUMNS));
        add(renderPanel = new JScrollPane());
        add(controlPanel = new JPanel());
        add(colourPanel = new JPanel());
        add(songPanel = new JTabbedPane());

        //songPanel options
        songPanel = new JTabbedPane();
        songPanel.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
        songPanel.addTab("#1", new JTextArea());
        songPanel.addTab("+", null, new JLabel(), "+");

        Container cp = getContentPane();
        cp.add(BorderLayout.SOUTH, songPanel);

        //integrate songPanel changeListener 
        songPanel.addChangeListener(new ChangeListener(){

            @Override //Method called when selected tab changes
            public void stateChanged(ChangeEvent e){
                try {          
                    if(songPanel.getSelectedIndex()==songPanel.getTabCount()-1){
                        addTab("songPanel");
                    }
                } catch (StackOverflowError soe){soe.printStackTrace();}
            }
        });
//*************************************************************************
    @Override
    public void start(){

    }
//*************************************************************************
    private void addTab(String panelName){
        System.out.println("ADDING TAB");
        if(panelName.equals("songPanel")){
            String tabName = ("#" + Integer.toString(songPanel.getTabCount()-1));
            songPanel.insertTab(tabName, null, new JTextField(), tabName,           songPanel.getTabCount()-2);
        }
    }
}
//**************************************************************************
}

我试过了:

  • 在addTab()方法中设置一个还原索引,以便选择最新的选项卡(仍会导致StackOverflowError)

注意这一行:

songPanel.getSelectedIndex()==songPanel.getTabCount()-1)

“ songPanel.getSelectedIndex()”和“ songPanel.getTabCount()-1)始终相等,因此条件始终为true( 导致StackOverflowError

错误信息:

java.lang.StackOverflowError
at javax.swing.text.StyleContext$SmallAttributeSet.getAttributeNames(StyleContext.java:947)
at javax.swing.text.StyleContext$SmallAttributeSet.containsAttributes(StyleContext.java:973)
at javax.swing.text.StyleContext$SmallAttributeSet.equals(StyleContext.java:852)
at java.util.WeakHashMap.eq(WeakHashMap.java:282)
at java.util.WeakHashMap.get(WeakHashMap.java:379)
at java.util.Collections$SynchronizedMap.get(Collections.java:2031)
at javax.swing.text.StyleContext.getImmutableUniqueSet(StyleContext.java:520)
at javax.swing.text.StyleContext.addAttributes(StyleContext.java:340)
at javax.swing.text.AbstractDocument$AbstractElement.addAttributes(AbstractDocument.java:1985)
at javax.swing.text.AbstractDocument$AbstractElement.<init>(AbstractDocument.java:1777)
at javax.swing.text.AbstractDocument$LeafElement.<init>(AbstractDocument.java:2502)
at javax.swing.text.AbstractDocument$BidiElement.<init>(AbstractDocument.java:2674)
at javax.swing.text.AbstractDocument.<init>(AbstractDocument.java:149)
at javax.swing.text.AbstractDocument.<init>(AbstractDocument.java:109)
at javax.swing.text.PlainDocument.<init>(PlainDocument.java:90)
at javax.swing.text.PlainDocument.<init>(PlainDocument.java:80)
at javax.swing.text.DefaultEditorKit.createDefaultDocument(DefaultEditorKit.java:130)
at javax.swing.plaf.basic.BasicTextUI.installUI(BasicTextUI.java:799)
at javax.swing.JComponent.setUI(JComponent.java:655)
at javax.swing.text.JTextComponent.setUI(JTextComponent.java:338)
at javax.swing.text.JTextComponent.updateUI(JTextComponent.java:348)
at javax.swing.text.JTextComponent.<init>(JTextComponent.java:322)
at javax.swing.JTextField.<init>(JTextField.java:231)
at javax.swing.JTextField.<init>(JTextField.java:172)
at application.Analyzer.addTab(Analyzer.java:133)
at application.Analyzer.access$100(Analyzer.java:24)
at application.Analyzer$1.stateChanged(Analyzer.java:101)
at javax.swing.JTabbedPane.fireStateChanged(JTabbedPane.java:416)
at javax.swing.JTabbedPane$ModelListener.stateChanged(JTabbedPane.java:270)
at javax.swing.DefaultSingleSelectionModel.fireStateChanged(DefaultSingleSelectionModel.java:132)
at javax.swing.DefaultSingleSelectionModel.setSelectedIndex(DefaultSingleSelectionModel.java:67)
at javax.swing.JTabbedPane.setSelectedIndexImpl(JTabbedPane.java:616)
at javax.swing.JTabbedPane.insertTab(JTabbedPane.java:735)
at application.Analyzer.addTab(Analyzer.java:133)
at application.Analyzer.access$100(Analyzer.java:24)
.
.
.

你有什么建议吗? 我知道这有点含糊,但是我真的不确定到底出了什么问题。

有什么建议么? 谢谢。 泰勒

StackOverflow标识无限递归。 所以第一件事就是找到那个递归。 在您的情况下,这是用于标识该递归的stacktrace的各行:

在application.Analyzer.addTab(Analyzer.java:133)在application.Analyzer.access $ 100(Analyzer.java:24)在application.Analyzer $ 1.stateChanged(Analyzer.java:101)在javax.swing.JTabbedPane.fireStateChanged( JxabbedPane.java:416)在javax.swing.JTabbedPane $ ModelListener.stateChanged(JTabbedPane.java:270)在javax.swing.DefaultSingleSelectionModel.fireStateChanged(DefaultSingleSelectionModel.java:132)在javax.swing.DefaultSingleSelectionModel.setSelectedIndex(DefaultS) :67),位于javax.swing.JTabbedPane.insertTab(JTabbedPane.java:735)处的javax.swing.JTabbedPane.setSelectedIndexImpl(JTabbedPane.java:616)在application.Analyzer.addTab(Analyzer.java:133)

因此,当您插入选项卡时,它会自动触发所选选项卡的更改,这又会调用ChangeEventListener,这将触发选项卡的插入等。

因此,您有两个简单的解决方案:

  1. 在添加新选项卡之前,请使用设置为true的标志( boolean ),并在完成后将其设置为false 在测试是否需要添加选项卡的条件下,还要检查此标志是否为true
  2. 在插入选项卡之前,您需要从JTabbedPane中删除更改侦听器,然后再将其放回去。

在这两种情况下,请使用try / finally块以确保返回一致状态。

更新的解决方案很抱歉,以前的解决方案无法正常工作。 这里是我更新的:

public class TabbedPaneTest {

    private final static JButton ADD_NEW_TAB_BUTTON = new JButton();
    private JFrame mainFrame;
    private JTabbedPane tabbedPane;

    public void run() {
        mainFrame = new JFrame("Test JTabbedPane");
        mainFrame.setSize(300, 400);
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        tabbedPane = new JTabbedPane();
        tabbedPane.addTab("default new tab", new JLabel("this is a default tab"));

        addNewTabButton();
        tabbedPane.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                if (tabbedPane.getSelectedComponent() == ADD_NEW_TAB_BUTTON) {
                    tabbedPane.addTab("new tab", new JLabel("new tab label"));
                    addNewTabButton();
                }
            }
        });


        mainFrame.getContentPane().add(tabbedPane);
        mainFrame.setVisible(true);
    }

    private void addNewTabButton() {
        tabbedPane.remove(ADD_NEW_TAB_BUTTON);
        tabbedPane.addTab("[+]", ADD_NEW_TAB_BUTTON);
    }

    public static void main(String[] params) {
        TabbedPaneTest test = new TabbedPaneTest();
        test.run();
    }

}

问题在于,添加后再次调用changeListener,并使用+选项卡作为选定选项卡,从而导致创建新选项卡,依此类推。

一个非常简单的解决方案可能就是像Guillaume Polet所说的那样添加一个bool标志:

    songPanel.addChangeListener(new ChangeListener(){

        @Override //Method called when selected tab changes
        public void stateChanged(ChangeEvent e){
            try {   
                if(songPanel.getSelectedIndex()==songPanel.getTabCount()-1 && !adding){
                    adding = true;
                    addTab("songPanel");
                    adding = false;
                }
            } catch (StackOverflowError soe){soe.printStackTrace();}
        }
    });

添加标志是一个初始化为false的类字段,它指示您是否正在添加选项卡。 对addTab进行了细微更改,以使所有功能正常工作:

private void addTab(String panelName){
    System.out.println("ADDING TAB");
    if(panelName.equals("songPanel")){
        String tabName = ("#" + Integer.toString(songPanel.getTabCount()));
        int index = songPanel.getTabCount()-1;
        songPanel.insertTab(tabName, null, new JTextField(), tabName, index);
        songPanel.setSelectedIndex(index);
    }
}

我对代码进行了一些更改,使活动选项卡成为新创建的选项卡,并使索引有些偏离。

希望这可以帮助 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM