JComboBox setSelectedIndex导致线程崩溃

时间:2015-02-23 11:07:06

标签: java multithreading thread-safety jcombobox

我遇到调用JComboBox.setSelectedIndex(0)导致的问题 我的程序崩溃了。任何帮助将不胜感激!!

在itemStateChanged()上启动一个新的Thread来处理UpdateAllForms。

UpdateAllForms调用updateComboModel(),它查询SQL数据库以更新ComboBoxModel并添加一个附加选项'Select ...'

这一切都正常,但是如果我添加JComboBox.setSelectedIndex(0) 程序崩溃,没有异常等我假设问题是线程?

itemStateChanged()方法:

public void itemStateChanged(ItemEvent e) {

    if (e.getStateChange() == ItemEvent.DESELECTED) {

        Runnable updateRunnable = new UpdateAllForms(e.getSource());
        new Thread(updateRunnable).start();
    }

}

UpdateAllForms类:

// <<=== UpdateAllForms Class ===>>
// Only Updates Forms below the Current Form
// Must be ran as a Separate Thread due to swing concurrency
// ==============================================================================
public class UpdateAllForms implements Runnable {

    Object source = null;

    public UpdateAllForms(Object source) {
        this.source = source;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        boolean shouldUpdate = false;

        Logger.write("PropConfDialog.updateAllForms");

        // Loop through Forms
        for (int formCount = 0; formCount < dataInputForms.get(1).size(); formCount++) {

            Component curForm = dataInputForms.get(1).get(formCount);
            // Update Forms after current form
            if (shouldUpdate) {

                if (curForm instanceof JSQLComboPanel) {
                    JSQLComboPanel panel = (JSQLComboPanel) curForm;
                    // Resets the where String
                    panel.setWhereString(getInputString(panel.getInputID()));
                    panel.updateComboModel();
                    shouldUpdate = true;
                    continue;
                } else if (curForm instanceof JSQLLabelPanel) {
                    JSQLLabelPanel panel = (JSQLLabelPanel) curForm;
                    panel.setWhereString(getInputString(panel.getInputID()));
                    panel.updateLabel();
                    shouldUpdate = true;
                    Logger.write("LABEL CAN CARRY OUT");
                    continue;

                }// End if/else

            } // End should update

            if (source == ((JSQLComboPanel) dataInputForms.get(1).get(formCount)).getComboBox()) {
                shouldUpdate = true;
            }// End if

        }// End Loop

    }// End updateAllCombos()

}// End UpdateAllForms Class

JSQLComboPanel类 - updateComboModel方法!!这就是问题!!!如果我打电话 combo.setSelectedIndex(0)在此方法中程序崩溃。

public void updateComboModel(){

    if(comboType == TYPE_DRIVEN_COMBO){

        ArrayList values = SQLTools.getColValues(lkTable, lkNameCol);
        combo.setModel(new DefaultComboBoxModel(values.toArray(new String[values.size()])));


    }else if(comboType == TYPE_WHERE_COMBO){

        ArrayList values = SQLTools.executeJoin(fkTable, fkIDCol, fkNameCol, lkTable, lkIDCol, lkNameCol, whereString);
        combo.setModel(new DefaultComboBoxModel(values.toArray(new String[values.size()])));

    }else if(comboType == TYPE_WHERE_LINKED_COMBO){

        ArrayList values = SQLTools.executeLinkTableJoin(fkTable, fkIDCol, fkNameCol, linkTable, fkIDCol, lkIDCol, lkTable, lkIDCol, lkNameCol,whereString);
        combo.setModel(new DefaultComboBoxModel(values.toArray(new String[values.size()])));

    }//End if/else

    combo.insertItemAt("Select...", 0);
    //combo.setSelectedIndex(0);
    combo.repaint();

}//End updateComboModel()

如果有人可以放弃任何光线,那就太棒了!我是Java的新手,特别是线程!

再次感谢

1 个答案:

答案 0 :(得分:0)

问题(几乎可以肯定)与您在错误的线程上修改Swing组件的状态有关。

一般规则是:

  

依赖于或修改Swing组件状态的代码应该在Event Dispatch Thread上执行

违反此规则有时可能难以检测 - 特别是当仅修改模型时,它不一定与GUI组件有连接!

然而,在你的情况下,主要问题更明显,因为(至少)有问题的电话

combo.setModel(new DefaultComboBoxModel(values.toArray(new String[values.size()])));

发生在自己的线程上,并直接修改Swing组件。

正如评论中所建议的那样,您应该明确考虑使用SwingWorker。有关SwingWorker(以及一般Swing中的线程)的更多详细信息,请参阅有关Concurrency In Swing的文章


您的问题的快速解决方法可能如下:

...
// Remove this line
//combo.setModel(new DefaultComboBoxModel(values.toArray(new String[values.size()])));

// Replace it with this line
setModelOnEDT(combo, new DefaultComboBoxModel(values.toArray(new String[values.size()]));

并创建一个这样的方法:

private static void setModelOnEDT(
    final JComboBox comboBox, final ComboBoxModel model)
{
    SwingUtilities.invokeLater(new Runnable() 
    {
        @Override
        public void run()
        {
            comboBox.setModel(model);
        }
    });
} 

这肯定不是最漂亮的解决方案,但最简单,直到您修改代码以使用SwingWorker