Двойной вызов JFileChooser в invokelater приводит к тому, что программа не завершается

Я пишу программу для сбора информации из двух текстовых файлов для добавления в таблицы в базе данных. Чтобы позволить пользователю выбирать свои собственные файлы, я создал нестатический метод с именем chooseFile(), который использует класс JFileChooser для представления showOpenDialog (я также пробовал его как статический метод с теми же результатами. Если это звучит так, как будто я' полагаю, вы правы - я так себе с программированием).

Насколько я понимаю, вызовы классов Swing в main() должны выполняться с использованием invokelater. Все это работало нормально (JVM успешно завершает работу) для одного вызова chooseFile(), но когда я добавил второй вызов chooseFile(), JVM продолжает работать бесконечно. Однако программа завершается нормально с обоими вызовами chooseFile(), если я делаю это без использования invokelater. Добавление System.exit(0) после второго вызова в invokelater также позволяет программе завершиться нормально.

Из того, что мне удалось собрать, программа не завершится, пока все потоки (не демона) не будут закрыты. Тем не менее, я думал, что цель использования invokelater заключалась в том, чтобы передать все действия, связанные с Swing, не связанные с потоками, в EDT. Является ли использование System.exit(0) лучшей практикой или есть что-то еще, о чем мне следует знать?

Вот мой SSCCE:

package ptMngr;

import java.io.IOException;
import java.nio.file.Path;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;

public class ParticipantManager {

    private Path chooseFile() throws IOException{
        JFileChooser chooser = new JFileChooser();
        FileNameExtensionFilter filter = new FileNameExtensionFilter("Text Files", "txt","csv");
        chooser.setFileFilter(filter);
        int returnVal = chooser.showOpenDialog(null);
        if(returnVal == JFileChooser.APPROVE_OPTION) {
            System.out.println("You chose to open this file: " +
                chooser.getSelectedFile().getName());
        }
        Path path = chooser.getSelectedFile().toPath();
        return path;
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args){
    //        ParticipantManager pm =  new ParticipantManager();
    //        try {
    //            pm.chooseFile();
    //            pm.chooseFile();
    //
    //        } catch (IOException ex) {
    //            Logger.getLogger(ParticipantManager.class.getName()).log(Level.SEVERE, null, ex);
    //        }

        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                ParticipantManager pm =  new ParticipantManager();
                try {

                    pm.chooseFile();
                    pm.chooseFile();
                    System.exit(0);
                } catch (IOException ex) {
                    Logger.getLogger(ParticipantManager.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }
}

person John Jones    schedule 18.11.2015    source источник
comment
@Ram Спасибо, что починили подвесной кронштейн.   -  person John Jones    schedule 19.11.2015
comment
@Andrew Эндрю Я вызываю этот метод во второй раз, потому что хочу, чтобы пользователь мог открывать два отдельных файла. Я предполагаю, что для общего программирования приложений что-то вроде JFileChooser() будет вызываться всякий раз, когда пользователь хочет открыть/сохранить файл, и что будет обрабатываться любой дополнительный поток (если это правильный термин), созданный классом. Отсюда мой вопрос о System.exit(0).   -  person John Jones    schedule 19.11.2015
comment
Я вызываю этот метод во второй раз, потому что хочу, чтобы пользователь мог открыть два отдельных файла Спасибо, что прояснили ситуацию. Обратите внимание, что если два файла находятся в одном каталоге, пользователю легко предложить средство выбора одного файла, которое позволяет выбирать более одного файла одновременно (выбор нескольких файлов). Конечно, эта стратегия может не соответствовать этому требованию пользователя (только вы можете сказать это наверняка).   -  person Andrew Thompson    schedule 19.11.2015
comment
«Дизайн» не моя сильная сторона; Я собираю его вместе, когда я иду. Функционал этой программы будет заключаться только в открытии этих двух файлов и создании БД с двумя таблицами. У меня есть другая программа, которая запрашивает у пользователя идентификационный номер, а затем запрашивает БД. Я избегал JFrame и использовал JOptionPane, поэтому мне не нужно возиться с макетом. Однако одним недостатком этого подхода является то, что пользователю не сообщается, что программа все еще работает, поэтому мне в любом случае может понадобиться JFrame, который должен устранить проблему. Но я думаю, что вопрос остается в силе.   -  person John Jones    schedule 19.11.2015


Ответы (1)


В вашем вызове showOpenDialog(null) вы передаете null в качестве родительского компонента для JFileChooser. Прошло некоторое время с тех пор, как я работал с JFileChooser, но я, кажется, помню, что "магический" JFrame может быть создан, когда передается null. Возможно, что в этом случае использования создаются два "магических" JFrame и они предотвращают завершение.

Вы можете попытаться создать JFrame, который служит родителем для обоих JFileChooser, чтобы он не создавал автоматические фреймы.

РЕДАКТИРОВАТЬ:

Мой первый прием будет таким:

public static class ParticipantManager {
    JFrame frame;

    private JFrame getFrame() {
        if (frame==null) {
            frame = new JFrame();
            frame.setSize(600, 400);
            frame.setLocationRelativeTo(null);
            // frame.setVisible(true); // <---- worked for me without this call too
        }
        return frame;
    }

    private void close() {
        frame.dispose();
    }

    private Path chooseFile() throws IOException{
        JFrame f = getFrame();
        ...
        int returnVal = chooser.showOpenDialog(f);
    ...

    ...
                pm.chooseFile();
                pm.chooseFile();
                pm.close(); // <----- close the frame
    ...
person Rainer Schwarze    schedule 18.11.2015
comment
Я сталкивался с подобными предложениями в качестве ответов на связанные вопросы. Я пробовал это двумя разными способами. Прежде чем публиковать этот вопрос, я попытался сделать класс расширением JComponent и вызвал chooser.showOpenDialog(ParticipantManager.this), который компилируется, но не решает проблему. Основываясь на вашем сообщении, я создал JFrame в блоке invokelater и передал его с помощью pm.chooseFile(frame), а затем использовал этот фрейм в качестве родителя с теми же результатами. Я правильно интерпретирую ваши предложения? System.exit(0) кажется более простым решением. - person John Jones; 19.11.2015
comment
Я скорректировал свой ответ. Я бы создал JFrame, использовал его и удалил, когда средства выбора файлов больше не нужны. В моем тесте это работало, не делая рамку видимой (в Mac OS X El Capitan). - person Rainer Schwarze; 19.11.2015