0

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

I'm having difficulty adding a new tab to my GUI's JTabbedPane container, when the [+] tab is selected. 到目前为止,每当我单击 [+] 选项卡时,都会添加新选项卡,直到发生 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)" 总是相等的,所以条件总是为真(导致 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)
.
.
.

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

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

4

3 回答 3

1

StackOverflow 标识了一个无限递归。所以首先要做的是找到那个递归。在您的情况下,这些是标识该递归的堆栈跟踪行:

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

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

所以你有两个简单的解决方案:

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

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

于 2012-06-21T06:14:31.320 回答
0

更新的解决方案 对不起,以前的解决方案没有按预期工作。这是我更新的一个:

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

}
于 2012-06-21T02:06:46.993 回答
0

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

添加标志是初始化为假的类字段,并指示您是否正在添加选项卡。对 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);
    }
}

我对代码做了一点改动,使活动选项卡成为新创建的选项卡,并且索引有点偏离。

希望这可以帮助 :)

于 2012-06-21T08:51:02.500 回答