adjust selected File to FileFilter in a JFileChooser

前端 未结 8 724
死守一世寂寞
死守一世寂寞 2020-12-11 02:22

I\'m writing a diagram editor in java. This app has the option to export to various standard image formats such as .jpg, .png etc. When the user clicks File->Export, you get

相关标签:
8条回答
  • 2020-12-11 02:30

    It looks like you can listen to the JFileChooser for a change on the FILE_FILTER_CHANGED_PROPERTY property, then change the extension of the selected file appropriately using setSelectedFile().


    EDIT: You're right, this solution doesn't work. It turns out that when the file filter is changed, the selected file is removed if its file type doesn't match the new filter. That's why you're getting the null when you try to getSelectedFile().

    Have you considered adding the extension later? When I am writing a JFileChooser, I usually add the extension after the user has chosen a file to use and clicked "Save":

    if (result == JFileChooser.APPROVE_OPTION)
    {
      File file = fileChooser.getSelectedFile();
      String path = file.getAbsolutePath();
    
      String extension = getExtensionForFilter(fileChooser.getFileFilter());
    
      if(!path.endsWith(extension))
      {
        file = new File(path + extension);
      }
    }
    

    fileChooser.addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener()
    {
      public void propertyChange(PropertyChangeEvent evt)
      {
        FileFilter filter = (FileFilter)evt.getNewValue();
    
        String extension = getExtensionForFilter(filter); //write this method or some equivalent
    
        File selectedFile = fileChooser.getSelectedFile();
        String path = selectedFile.getAbsolutePath();
        path.substring(0, path.lastIndexOf("."));
    
        fileChooser.setSelectedFile(new File(path + extension));
      }
    });
    
    0 讨论(0)
  • 2020-12-11 02:35

    The use of getAbsolutePath() in the previous change the current directory. I was surprised when the JFileChooser dialog displaying "My documents" directory change to the Netbeans's project directory when I selected a different FileFilter, so I changed it to use getName(). I also used the JDK 6 FileNameExtensionFilter.

    Here is the code:

        final JFileChooser fc = new JFileChooser();
        final File sFile = new File("test.xls");
        fc.setSelectedFile(sFile);
        // Store this filter in a variable to be able to select this after adding all FileFilter
        // because addChoosableFileFilter add FileFilter in order in the combo box
        final FileNameExtensionFilter excelFilter = new FileNameExtensionFilter("Excel document (*.xls)", "xls");
        fc.addChoosableFileFilter(excelFilter);
        fc.addChoosableFileFilter(new FileNameExtensionFilter("CSV document (*.csv)", "csv"));
        // Force the excel filter
        fc.setFileFilter(excelFilter);
        // Disable All Files
        fc.setAcceptAllFileFilterUsed(false);
    
        // debug
        fc.addPropertyChangeListener(new PropertyChangeListener() {
    
            public void propertyChange(PropertyChangeEvent evt) {
                System.out.println("Property name=" + evt.getPropertyName() + ", oldValue=" + evt.getOldValue() + ", newValue=" + evt.getNewValue());
                System.out.println("getSelectedFile()=" + fc.getSelectedFile());
            }
        });
    
        fc.addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener() {
    
            public void propertyChange(PropertyChangeEvent evt) {
                Object o = evt.getNewValue();
                if (o instanceof FileNameExtensionFilter) {
                    FileNameExtensionFilter filter = (FileNameExtensionFilter) o;
    
                    String ex = filter.getExtensions()[0];
    
                    File selectedFile = fc.getSelectedFile();
                    if (selectedFile == null) {
                        selectedFile = sFile;
                    }
                    String path = selectedFile.getName();
                    path = path.substring(0, path.lastIndexOf("."));
    
                    fc.setSelectedFile(new File(path + "." + ex));
                }
            }
        });
    
    0 讨论(0)
  • 2020-12-11 02:40

    Here's my attempt at this. It uses the accept() function to check whether or not the file passes the filter. If the filename does not, the extension is appended to the end.

    JFileChooser jfc = new JFileChooser(getFile()) {
            public void approveSelection() {
                if (getDialogType() == SAVE_DIALOG) {
                    File selectedFile = getSelectedFile();
    
                    FileFilter ff = getFileFilter();
    
                    // Checks against the current selected filter
                    if (!ff.accept(selectedFile)) {
                        selectedFile = new File(selectedFile.getPath() + ".txt");
                    }
                    super.setSelectedFile(selectedFile);
    
                    if ((selectedFile != null) && selectedFile.exists()) {
                        int response = JOptionPane.showConfirmDialog(
                                this,
                                "The file " + selectedFile.getName() + " already exists.\n" +
                                "Do you want to replace it?",
                                "Ovewrite file",
                                JOptionPane.YES_NO_OPTION,
                                JOptionPane.WARNING_MESSAGE
                        );
                        if (response == JOptionPane.NO_OPTION)
                            return;
                    }
                }
                super.approveSelection();
            }
        };
    
    0 讨论(0)
  • 2020-12-11 02:47

    How about this:

    class MyFileChooser extends JFileChooser {
       public void setFileFilter(FileFilter filter) {
    
        super.setFileFilter(filter);
    
        FileChooserUI ui = getUI();
    
        if( ui instanceof BasicFileChooserUI ) {
         BasicFileChooserUI bui = (BasicFileChooserUI) ui;
    
         String file = bui.getFileName();
    
         if( file != null ) {
          String newFileName = ... change extension 
          bui.setFileName( newFileName );
         }
        }
       }
      }
    
    0 讨论(0)
  • 2020-12-11 02:50

    I recommend using FileNameExtensionFilter instead of FileFilter if your version of Java supports it. Otherwise create your own new similar abstract class that extends from FileFilter and has an added method getExtension (similar to FileNameExtensionFilter.getExtensions). Then override getExtension for every export filter you intend to use.

    public abstract class MyFileFilter extends FileFilter {
        abstract public String getExtension();
    }
    

    Then for an example JPG filter you just need to override one extra method than before:

        MyFileFilter filterJPG = new MyFileFilter () {
            @Override
            public String getDescription() {
                return "A JPEG image (*." + getExtension() + ")";
            }
            @Override
            public boolean accept(File f) {
                String filename = f.getName().toLowerCase();
                return filename.endsWith("."+getExtension());
            }
            @Override
            public String getExtension() { return "jpg"; }
        };
    

    After the user has chosen the file, simply call getFileFilter to determine which filter the user chose:

    jfc.showDialog(frame, "export");
    File file = jfc.getSelectedFile();
    RvFileFilter filter = (RvFileFilter)jfc.getFileFilter();
    String sExt = filter.getExtension(); //The extension to ensure the file has
    

    If you were able to use FileNameExtensionFilter.getExtensions() then you can simply use the first entry in the array.

    0 讨论(0)
  • 2020-12-11 02:51

    Here is a method to obtain the current file name (as a String). In your property change listener for JFileChooser.FILE_FILTER_CHANGED_PROPERTY, you make the following call:

    final JFileChooser fileChooser = new JFileChooser();
    fileChooser.addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener()
    {
        @Override
        public void propertyChange(PropertyChangeEvent e) {
            String currentName = ((BasicFileChooserUI)fileChooser.getUI()).getFileName();
            MyFileFilter filter = (MyFileFilter) e.getNewValue();
    
            // ... Transform currentName as you see fit using the newly selected filter.
            // Suppose the result is in newName ...
    
            fileChooser.setSelectedFile(new File(newName));
        }
    });
    

    The getFileName() method of javax.swing.plaf.basic.BasicFileChooserUI (the descendant of FileChooserUI returned by JFileChooser.getUI()) will return the contents of the dialog's text box that is used to type in the file name. It seems that this value is always set to a non-null String (it returns an empty string if the box is empty). On the other hand, getSelectedFile() returns null if the user has not selected an existing file yet.

    It seems that the dialog's design is governed by the 'file selection' concept; that is, while the dialog is visible getSelectedFile() only returns a meaningful value if the user has already selected an existing file or the program called setSelectedFile(). getSelectedFile() will return what the user typed in after the user clicks the approve (i.e. OK) button.

    The technique will only work for single-selection dialogs, however changing file extension based on selected filter should also make sense for single files only ("Save As..." dialogs or similar).

    This design was a subject of a debate at sun.com back in 2003, see the link for details.

    0 讨论(0)
提交回复
热议问题