简体   繁体   English

为什么单击“是/否”按钮后JOptionPane的“确认对话框”不起作用?

[英]Why Confirm Dialog Box of JOptionPane is not taking action on clicking Yes/No button?

At first see my GUI: 首先看到我的GUI:

在此处输入图片说明

Background: 背景:

I am trying to use some functions (CRUD) of MongoDB collection by a GUI. 我试图通过GUI使用MongoDB集合的某些功能(CRUD)。

At first user has to choose an existing Database from the very first ComboBox. 首先,用户必须从第一个ComboBox中选择一个现有的数据库。 When user chooses an option private void jComboBoxDBNamePopupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) function would load all the collections under that database. 当用户选择一个选项时, private void jComboBoxDBNamePopupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt)函数将加载该数据库下的所有集合。 Here blog is chosen. 在这里选择博客

Then user would choose a collection among the existing collections from second ComboBox. 然后,用户可以从第二个ComboBox的现有集合中选择一个集合。 When user chooses a collection private void jComboBoxCollectionNamePopupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) function would call a function named refreshTable() to load all the Documents under that collection. 当用户选择一个集合时, private void jComboBoxCollectionNamePopupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt)函数将调用一个名为refreshTable()的函数来加载该集合下的所有Document。 Here posts collection is chosen. 在这里选择帖子集合。

While choosing option from second ComboBox, if the chosen collection have more than thousand Documents, it would ask user to confirm whether he actually wants to load the Documents or not as it might take time or could be a memory issue. 从第二个ComboBox中选择选项时,如果所选择的集合具有超过千个Document,它将要求用户确认他是否确实要加载Document,因为这可能需要时间,或者可能是内存问题。 It confirmation would be done through a JOptionPane.showConfirmDialog(...) . 确认将通过JOptionPane.showConfirmDialog(...)

Problem: 问题:

While choosing collection posts , it shows the Dialog Box. 选择收藏集帖子时 ,它会显示对话框。 But clicking on Yes or No does not gives any response. 但是,单击“ 是”或“ ”不会给出任何响应。 But why? 但为什么?

The buttons are red underlined in the picture. 这些按钮在图片中带有红色下划线。

Code: 码:

My public boolean refreshTable() function is: 我的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;
}

Study: 研究:

I have searched it on Google and could not solve the issue. 我已经在Google上搜索了它,但无法解决问题。 The followings are some questions on StackOverflow, but I could not figure out solution from them. 以下是有关StackOverflow的一些问题,但我无法从中找出解决方案。

  1. JOptionPane Confirm Dialog Box JOptionPane确认对话框
  2. JOptionPane YES/No Options Confirm Dialog Box Issue -Java JOptionPane是/否选项确认对话框问题-Java
  3. JoptionPane ShowConfirmDialog JoptionPane ShowConfirmDialog

Project Repository: 项目资料库:

My Project repository is here . 我的项目存储库在这里 You could have a look if needed. 如果需要,可以看看。

This is probably because JOptionPane methods should be called on the event dispatch thread (EDT) of Swing while you are inovoking it on a different thread. 这可能是因为在其他JOptionPane上调用JOptionPane方法时,应在Swing的事件分配线程(EDT)上调用它。

You should try calling refreshTable by using SwingUtilities utility methods, eg: 您应该尝试使用SwingUtilities实用程序方法来调用refreshTable,例如:

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

A guess only since we don't have a minimal example program from you -- but if this JOptionPane is called amidst long-running or CPU-intensive code, and if the code is run on the Swing event thread, it will freeze the Swing event thread and thus freeze your GUI. 只是一个猜测,因为我们没有从您提供的最小示例程序开始,但是,如果在长时间运行或占用大量CPU的代码中调用此JOptionPane,并且该代码在Swing事件线程上运行,它将冻结Swing事件线程,从而冻结您的GUI。 If you're not taking care to call long-running or CPU-intensive code within background threads, you will want to do so, such as by use of a SwingWorker. 如果您不希望在后台线程中调用长时间运行的代码或占用大量CPU的代码,则可以这样做,例如使用SwingWorker。

I looked at your code, and you're starting your GUI on the EDT: 我查看了您的代码,然后您在EDT上启动GUI:

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

and so Jack's recommendation is unnecessary, but you're making all your database calls on the EDT and are not following Swing threading rules, something that will freeze your pogram, and so my recommendations are what you need to follow. 因此,杰克的建议是不必要的,但是您正在EDT上进行所有数据库调用,并且没有遵循Swing线程规则,这会使您的图表冻结,因此我的建议就是您需要遵循的建议。 You will first need to learn the basics of Swing threading, and so I recommend that you look at this tutorial: Lesson: Concurrency in Swing 首先,您需要学习Swing线程的基础知识,因此,我建议您看一下本教程: 课程:Swing中的并发性

You could get by with two SwingWorkers and two JPropertyChangeListeners: 您可以通过两个SwingWorkers和两个JPropertyChangeListeners来解决:

  • A SwingWorker, say called GetCollectionsWorker, that extends SwingWorker<Collections, Void> . 一个SwingWorker,称为GetCollectionsWorker,它扩展了SwingWorker<Collections, Void> I have no idea what the first generic parameter should be other than it should be whatever type your collections variable is. 我不知道第一个通用参数应该是什么,而应该是集合变量的类型。 This worker would simply return db.getCollection(selection); 该工作人员只需返回db.getCollection(selection); from its doInBackground() method. 从其doInBackground()方法。
  • A SwingWorker, say called CreateTableModelWorker, that extends SwingWorker<DefaultTableModel, Void> and that is passed collections into its constructor and that creates your DefaultTableModel from the data held by Collections. 一个SwingWorker,称为CreateTableModelWorker,它扩展了SwingWorker<DefaultTableModel, Void>并将集合传递到其构造函数中,并根据Collections持有的数据创建DefaultTableModel。
  • A PropertyChangeListener, say called GetCollectionsListener, that listens on the CreateTableModelWorker, for when it is done, in other words its newValue is SwingWorker.StateValue.DONE , and then that asks the user if he wants to continue, and if so, this calls the second SwingWorker. 一个名为ChangeCollectionListener的PropertyChangeListener,它侦听CreateTableModelWorker何时完成,换句话说,它的newValue是SwingWorker.StateValue.DONE ,然后询问用户是否要继续,如果这样,则调用第二个SwingWorker。
  • A PropertyChangeListener, say called CreateTableModelWorker, that listens to the CreateTableModelWorker for when it is done, and that puts the table model into the JTable. 一个PropertyChangeListener,称为CreateTableModelWorker,它侦听CreateTableModelWorker完成的时间,并将表模型放入JTable中。

For what it's worth, I'd implement somewhere along these lines in the code below. 对于它的价值,我将在以下代码中的这些地方实现。 Again, the big unknown for me is what type the collections variable represents, and for that reason, the first SwingWorker's generic parameter would need to be fixed and changed from Collections to whatever it is that you're using: 同样,对我来说,最大的未知数是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();
            }
        }
    }
}

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

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