JFileChooser.showSaveDialog()没有显示出来

use*_*681 7 java file-io swing jfilechooser file

我正在使用Eclipse IDE,我正试图showSaveDialog(null)从另一个方法调用,而这个方法又是从main调用的,但是当我调用它时没有任何反应.

主要:

public static void main(String[] args) {
    Main main = new Main();
    main.pt = main.new PlayThread();
    main.generateSound(getSamples(2), 500);
    main.play(main.sound, 1);
    if(new Scanner(System.in).nextLine().equals("save")){
        System.out.println(main.save());
    }
}
Run Code Online (Sandbox Code Playgroud)

调用之前的所有代码都main.save()可以正常工作,并且main.save()像这样开始:

public boolean save(){
    System.out.println("Calling save");
    try{
    String saveName = getSaveTo("C:/");
    System.out.println("I'm here now");
Run Code Online (Sandbox Code Playgroud)

虽然getSaveTo()看起来像:

public String getSaveTo(String def){
    JFileChooser chooser = new JFileChooser();
    System.out.println("Save called");
    //chooser.setCurrentDirectory(new File(def));
    int resp = chooser.showSaveDialog(null);
    if(resp == JFileChooser.APPROVE_OPTION){
        return chooser.getSelectedFile() + ".wav";
    }else return null;
}
Run Code Online (Sandbox Code Playgroud)

在执行前几个函数后main,我输入'save',然后控制台打印:

Calling save
Save called
Run Code Online (Sandbox Code Playgroud)

但对话从未打开过,它从未说"我现在在这里".为什么?另外,当我输入

new JFileChooser().showSaveDialog(null)

这显示很好,但在我的save()方法中,它不会.有什么想法吗?

编辑:

这是一个具有相同问题的精简程序:

package com.funguscow;

import java.util.Scanner;

import javax.swing.JFileChooser;

import com.funguscow.Main.PlayThread;

public class Test {
public static void main(String[] args) {
    Test main = new Test();
    Scanner scan = new Scanner(System.in);
    boolean should = scan.nextLine().equals("save");
    scan.close();
    if(should){
        System.out.println(main.save());
    }
}

public String getSaveTo(String def){
    JFileChooser chooser = new JFileChooser();
    System.out.println("Save called");
    //chooser.setCurrentDirectory(new File(def));
    int resp = chooser.showSaveDialog(null);
    System.out.println("Save called");
    if(resp == JFileChooser.APPROVE_OPTION){
        return chooser.getSelectedFile() + ".wav";
    }else return null;
}

public boolean save(){
    System.out.println("Calling save");
    try{
    String saveName = getSaveTo("C:/");
    System.out.println("I'm here now");
    if(saveName == null)return false;
    }catch(Exception e){}
    return false;
}
}
Run Code Online (Sandbox Code Playgroud)

如果您想更多地检查它,可以自己运行.


此MCVE可能足以重现该问题,并且似乎初始化的扫描程序System.in干扰了JFileChooser显示打开文件对话框的能力,即使在采取谨慎措施以便在Swing事件线程上运行文件选择器时也是如此. :

import java.util.Scanner;    
import javax.swing.JFileChooser;
import javax.swing.SwingUtilities;

public class Test3 {
   public static void main(String[] args) {
      Scanner scan = new Scanner(System.in);
      System.out.print("Enter something and press Enter: ");
      scan.nextLine();
      scan.close();

      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            JFileChooser fileChooser = new JFileChooser();
            int result = fileChooser.showOpenDialog(null);
         }
      });
      // JFileChooser fileChooser = new JFileChooser();
      // int result = fileChooser.showOpenDialog(null);
   }
}
Run Code Online (Sandbox Code Playgroud)

vax*_*uis 5

On Windows, Scanner interferes w/ JFileChooser -- why?

tl;严格来说,是用户JFileChooser通过使用Scanner来自系统控制台(System.in)的期望输入来干扰.无论哪种方式,它只是关于窗口焦点和Java的Dialog模态.

说明

该错误发生是因为对话框出现在后台,因为需要nextLine()on Scanneron System.in实际上强制用户将焦点切换到控制台.应用程序失去焦点,因此会Dialog出现在后台.代码本身不会"挂起",只是等到用户选择文件或执行任何其他对话框选项 - 直到他这样做,它什么都不做.如果有某种操作系统问题阻止后台窗口显示/正常工作(例如某些"总是在前台"窗口阻碍它) - 好吧,那么你的应用程序就在闲逛,等待由于这种情况不太可能发生的输入事件事实上没有人可以使用输入对话框本身.

对于受影响的人-的Dialog 那里.我已经在Windows XP上的Java 8,Windows 7上的Java 8和其他一些配置上测试了这段代码 - 在所有情况下创建了Dialog ,由于焦点丢失,可能隐藏在桌面背景中.它没有显示在任务栏中,但确实显示在Alt+ Tab列表中.尝试 IDE 之外运行它,当需要控制台输入时(由于"真正的"控制台被重定向到IDE输出窗口等),它们倾向于使用应用程序焦点做一些奇怪的事情.通过<管道而不是使用"真正的"控制台来提供数据将可以防止这种行为发生.

就我的想象而言,变通方法需要将焦点强制到应用程序的框架或创建一个动态的永远在顶部的框架,以保持焦点在应有的位置(在对话框上).由于DialogJFileChooser(或任何其他类似的对话可言)本身就是一种发射后不管的对象,这是一种很难用它强制前景不指定父.因此,我认为最简单的方法是,对于无父类Dialogs,只需使用如下代码:

示例解决方案

    Scanner scan = new Scanner( System.in );
    System.out.print( "Enter something and press Enter: " );
    scan.nextLine();
    scan.close();

    SwingUtilities.invokeLater( new Runnable() {
        public void run() {
            JFrame jf = new JFrame( "Dialog" ); // added
            jf.setAlwaysOnTop( true ); // added
            JFileChooser fileChooser = new JFileChooser();
            int result = fileChooser.showOpenDialog( jf );  // changed
            //System.out.print( "result: " + result );
            jf.dispose(); // added
        }
    } );
Run Code Online (Sandbox Code Playgroud)

或者,如果你喜欢干扰Dialog它本身,通过继承它并setAlwaysOnTop(true)createDialog()调用中应用上述内容(注意createDialog()protected访问权限JFileChooser,使得无法在不扩展类的情况下改变行为,类似于那里的所有Dialog相关内容),例如

int result = new JFileChooser() {
  @Override
  protected JDialog createDialog( Component parent ) throws HeadlessException {
    JDialog jDialog = super.createDialog( parent );
    jDialog.setAlwaysOnTop( true );
    return jDialog;
  }
}.showOpenDialog( null );
Run Code Online (Sandbox Code Playgroud)

或者甚至通过创建一个常规的实用程序类JFileChooser来实现这一点.

NB切换往返EDT在这里没有任何作用,因为这不是线程本身相关的(尽管UI的多线程是问题的根源,有点).