簡體   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