为什么单击是/否按钮确认JOptionPane对话框没有采取措施?

时间:2015-12-26 12:57:37

标签: java swing comparison joptionpane

首先看我的GUI:

enter image description here

背景

我试图通过GUI使用MongoDB集合的一些功能(CRUD)。

首先,用户必须从第一个ComboBox中选择现有数据库。当用户选择选项private void jComboBoxDBNamePopupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt)时,函数将加载该数据库下的所有集合。这里选择了博客

然后,用户将从第二个ComboBox的现有集合中选择一个集合。当用户选择集合private void jComboBoxCollectionNamePopupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt)时,函数将调用名为refreshTable()的函数来加载该集合下的所有文档。选择 posts 集合。

从第二个ComboBox中选择选项时,如果所选集合有超过一千个文档,它会要求用户确认他是否确实要加载文档,因为它可能需要时间或可能是内存问题。 确认将通过JOptionPane.showConfirmDialog(...)完成。

问题:

选择收藏帖子时,会显示对话框。但是单击不会给出任何响应。但为什么呢?

图片中的按钮带有红色下划线。

代码:

我的public boolean refreshTable()功能是:

public boolean refreshTable() {
    collections = db.getCollection((String) jComboBoxCollectionName.getSelectedItem());
    if(collections.count()>1000){
        int ret = JOptionPane.showConfirmDialog(this, "The table contains more than thousand row.\nThis may slow down the process and could cause Memory error.Are you sure to continue?","Too Large Collection ("+collections.count()+" Rows)",YES_NO_OPTION, INFORMATION_MESSAGE);
        if(ret!=YES_OPTION) return true;
    }
    //Some irrelevant codes
    return false;
}

研究:

我在Google上搜索过它并无法解决问题。以下是StackOverflow的一些问题,但我无法从中找出解决方案。

  1. JOptionPane Confirm Dialog Box
  2. JOptionPane YES/No Options Confirm Dialog Box Issue -Java
  3. JoptionPane ShowConfirmDialog
  4. 项目存储库:

    我的项目资源库是here。如果需要你可以看看。

2 个答案:

答案 0 :(得分:3)

这可能是因为当你在另一个线程上对它进行动态调用时,应该在Swing的事件派发线程(EDT)上调用JOptionPane方法。

您应该尝试使用SwingUtilities实用程序方法调用refreshTable,例如:

SwingUtilities.invokeLater(() -> refreshTable());

答案 1 :(得分:2)

猜测只是因为我们没有你的最小示例程序 - 但是如果在长期运行或CPU密集型代码中调用此JOptionPane,并且如果代码在Swing事件线程上运行,它将冻结Swing事件线程,从而冻结您的GUI。如果您不打算在后台线程中调用长时间运行或CPU密集型代码,则需要这样做,例如使用SwingWorker。

我查看了您的代码,并且您在EDT上启动了GUI:

    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            // this will be run on the EDT
            new UserInterface().setVisible(true);
        }
    });

所以杰克的推荐是不必要的,但是您在EDT上进行所有数据库调用并且没有遵循Swing线程规则,这会冻结您的计划,所以我的推荐就是你的需要遵循。您首先需要学习Swing线程的基础知识,因此我建议您查看本教程:Lesson: Concurrency in Swing

你可以使用两个SwingWorkers和两个JPropertyChangeListeners:

  • 一个名为GetCollectionsWorker的SwingWorker,它扩展了SwingWorker<Collections, Void>。我不知道第一个通用参数应该是什么,除了它应该是您的collections变量的任何类型。该工作人员只需从db.getCollection(selection);方法返回doInBackground()
  • 一个名为CreateTableModelWorker的SwingWorker,它扩展SwingWorker<DefaultTableModel, Void>并将集合传递到其构造函数中,并根据集合所持有的数据创建DefaultTableModel。
  • 一个名为GetCollectionsListener的PropertyChangeListener,它监听CreateTableModelWorker,当它完成时,换句话说它的newValue是SwingWorker.StateValue.DONE,然后询问用户是否要继续,如果是,这称为第二个SwingWorker。
  • 一个名为CreateTableModelWorker的PropertyChangeListener,它在完成后侦听CreateTableModelWorker,并将表模型放入JTable中。

为了它的价值,我将在下面的代码中沿着这些方向实现某些地方。同样,对我而言,最大的未知数是collections变量所代表的类型,因此,需要修复第一个SwingWorker的通用参数,并将其从Collections更改为任何类型。您正在使用:

// change to a void method
public void refreshTable() {
    String selection = (String) jComboBoxCollectionName.getSelectedItem();

    // SwingWorker to get collections
    GetCollectionsWorker getCollectionsWorker = new GetCollectionsWorker(selection);
    getCollectionsWorker.addPropertyChangeListener(new GetCollectionsListener());
    getCollectionsWorker.execute(); // run worker on background thread
}

// FIXME: Generic type Collections is wrong -- need to use correct type, whatever type collections is
private class GetCollectionsWorker extends SwingWorker<Collections, Void> {
    private String selection;

    public GetCollectionsWorker(String selection) {
        this.selection = selection;
    }

    @Override
    protected Collections doInBackground() throws Exception {
        // do database work here in a background thread
        return db.getCollection(selection);
    }
}

// class that listens for completion of the GetCollectionsWorker worker
class GetCollectionsListener implements PropertyChangeListener {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        // all this is done on the EDT
        if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
            // if worker is done, first get worker from listener
            GetCollectionsWorker worker = (GetCollectionsWorker) evt.getSource();
            try {
                // then extract the data that it's returning
                collections = worker.get();

                // then offer user option of continuing or not
                if (collections.count() > 1000) {
                    int ret = JOptionPane.showConfirmDialog(UserInterface.this,
                            "The table contains more than thousand row.\nThis may slow down the process and could cause Memory error.Are you sure to continue?",
                            "Too Large Collection (" + collections.count() + " Rows)", YES_NO_OPTION, INFORMATION_MESSAGE);
                    if (ret != YES_OPTION) {
                        return;
                    }
                }

                // our next worker, one to create table model
                CreateTableModelWorker createModelWorker = new CreateTableModelWorker(collections);
                // be notified when it is done
                createModelWorker.addPropertyChangeListener(new CreateModelListener());
                createModelWorker.execute(); // run on background thread

            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}

// worker to create table model on background thread
class CreateTableModelWorker extends SwingWorker<DefaultTableModel, Void> {
    private Collections collections;

    public CreateTableModelWorker(Collections collections) {
        this.collections = collections;
    }

    @Override
    protected DefaultTableModel doInBackground() throws Exception {
        documents = collections.find().into(new ArrayList<Document>());

        Set<String> colNames = new HashSet<>();

        for (Document doc : documents) {
            for (String key : doc.keySet()) {
                colNames.add(key);
            }
        }

        columns = colNames.toArray();
        Object[][] elements = new Object[documents.size()][columns.length];
        int docNo = 0;

        for (int i = 0; i < columns.length; i++) {
            if (((String) columns[i]).equalsIgnoreCase("_id")) {
                _idcol = i;
                break;
            }
        }

        for (Document doc : documents) {
            for (int i = 0; i < columns.length; i++) {
                if (doc.containsKey(columns[i])) {
                    elements[docNo][i] = doc.get(columns[i]);
                }
            }
            docNo++;
        }
        DefaultTableModel model = new DefaultTableModel(elements, columns);
        return model;
    }
}

private class CreateModelListener implements PropertyChangeListener {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        // all this is done on the EDT
        if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
            // if worker is done, first get worker from listener
            CreateTableModelWorker worker = (CreateTableModelWorker) evt.getSource();
            try {
                DefaultTableModel model = worker.get();
                jTableResultTable.setModel(model);
                UserInterface.this.model = model;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}