简体   繁体   中英

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

At first see my GUI:

在此处输入图片说明

Background:

I am trying to use some functions (CRUD) of MongoDB collection by a GUI.

At first user has to choose an existing Database from the very first ComboBox. When user chooses an option private void jComboBoxDBNamePopupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) function would load all the collections under that database. Here blog is chosen.

Then user would choose a collection among the existing collections from second 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. 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. It confirmation would be done through a 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() {
    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. The followings are some questions on StackOverflow, but I could not figure out solution from them.

  1. JOptionPane Confirm Dialog Box
  2. JOptionPane YES/No Options Confirm Dialog Box Issue -Java
  3. 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.

You should try calling refreshTable by using SwingUtilities utility methods, eg:

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. 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.

I looked at your code, and you're starting your GUI on the EDT:

    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. 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

You could get by with two SwingWorkers and two JPropertyChangeListeners:

  • A SwingWorker, say called GetCollectionsWorker, that extends 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); from its doInBackground() method.
  • 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.
  • 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.
  • A PropertyChangeListener, say called CreateTableModelWorker, that listens to the CreateTableModelWorker for when it is done, and that puts the table model into the 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:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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