2009-02-27 37 views
9

Tôi đang viết một trình soạn thảo sơ đồ trong java. Ứng dụng này có tùy chọn xuất sang các định dạng hình ảnh chuẩn khác nhau như .jpg, .png, v.v. Khi người dùng nhấp vào Tệp-> Xuất, bạn nhận được một số JFileChooser có một số FileFilter s trong đó, cho .jpg, .png v.v.điều chỉnh Tệp đã chọn thành FileFilter trong một JFileChooser

Bây giờ, đây là câu hỏi của tôi:

Có cách nào để mở rộng điều chỉnh mặc định cho bộ lọc tệp đã chọn không? Ví dụ. nếu tài liệu được đặt tên là "lolcat" thì tùy chọn mặc định phải là "lolcat.png" khi bộ lọc png được chọn và khi người dùng chọn bộ lọc tệp jpg, mặc định sẽ tự động thay đổi thành "lolcat.jpg".

Điều này có khả thi không? Tôi làm nó như thế nào?

chỉnh sửa: Dựa trên câu trả lời bên dưới, tôi đã viết một số mã. Nhưng nó vẫn chưa hoạt động. Tôi đã thêm một propertyChangeListener vào FILE_FILTER_CHANGED_PROPERTY, nhưng có vẻ như trong phương thức này getSelectedFile() trả về giá trị rỗng. Đây là mã.

package nl.helixsoft; 

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.io.File; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.JButton; 
import javax.swing.JFileChooser; 
import javax.swing.JFrame; 
import javax.swing.filechooser.FileFilter; 

public class JFileChooserTest { 
    public class SimpleFileFilter extends FileFilter { 
     private String desc; 
     private List<String> extensions; 
     private boolean showDirectories; 

     /** 
     * @param name example: "Data files" 
     * @param glob example: "*.txt|*.csv" 
     */ 
     public SimpleFileFilter (String name, String globs) { 
      extensions = new ArrayList<String>(); 
      for (String glob : globs.split("\\|")) { 
       if (!glob.startsWith("*.")) 
        throw new IllegalArgumentException("expected list of globs like \"*.txt|*.csv\""); 
       // cut off "*" 
       // store only lower case (make comparison case insensitive) 
       extensions.add (glob.substring(1).toLowerCase()); 
      } 
      desc = name + " (" + globs + ")"; 
     } 

     public SimpleFileFilter(String name, String globs, boolean showDirectories) { 
      this(name, globs); 
      this.showDirectories = showDirectories; 
     } 

     @Override 
     public boolean accept(File file) { 
      if(showDirectories && file.isDirectory()) { 
       return true; 
      } 
      String fileName = file.toString().toLowerCase(); 

      for (String extension : extensions) { 
       if (fileName.endsWith (extension)) { 
        return true; 
       } 
      } 
      return false; 
     } 

     @Override 
     public String getDescription() { 
      return desc; 
     } 

     /** 
     * @return includes '.' 
     */ 
     public String getFirstExtension() { 
      return extensions.get(0); 
     } 
    } 

    void export() { 
     String documentTitle = "lolcat"; 

     final JFileChooser jfc = new JFileChooser(); 
     jfc.setDialogTitle("Export"); 
     jfc.setDialogType(JFileChooser.SAVE_DIALOG); 
     jfc.setSelectedFile(new File (documentTitle)); 
     jfc.addChoosableFileFilter(new SimpleFileFilter("JPEG", "*.jpg")); 
     jfc.addChoosableFileFilter(new SimpleFileFilter("PNG", "*.png")); 
     jfc.addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener() { 
      public void propertyChange(PropertyChangeEvent arg0) { 
       System.out.println ("Property changed"); 
       String extold = null; 
       String extnew = null; 
       if (arg0.getOldValue() == null || !(arg0.getOldValue() instanceof SimpleFileFilter)) return; 
       if (arg0.getNewValue() == null || !(arg0.getNewValue() instanceof SimpleFileFilter)) return; 
       SimpleFileFilter oldValue = ((SimpleFileFilter)arg0.getOldValue()); 
       SimpleFileFilter newValue = ((SimpleFileFilter)arg0.getNewValue()); 
       extold = oldValue.getFirstExtension(); 
       extnew = newValue.getFirstExtension(); 
       String filename = "" + jfc.getSelectedFile(); 
       System.out.println ("file: " + filename + " old: " + extold + ", new: " + extnew); 
       if (filename.endsWith(extold)) { 
        filename.replace(extold, extnew); 
       } else { 
        filename += extnew; 
       } 
       jfc.setSelectedFile(new File (filename)); 
      } 
     }); 
     jfc.showDialog(frame, "export"); 
    } 

    JFrame frame; 

    void run() { 
     frame = new JFrame(); 
     JButton btn = new JButton ("export"); 
     frame.add (btn); 
     btn.addActionListener (new ActionListener() { 
      public void actionPerformed(ActionEvent ae) { 
       export(); 
      } 
     }); 
     frame.setSize (300, 300); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     javax.swing.SwingUtilities.invokeLater(new Runnable() {  
      public void run() { 
       JFileChooserTest x = new JFileChooserTest(); 
       x.run(); 
      } 
     });  
    } 
} 

Trả lời

11

Dường như bạn có thể lắng nghe những JFileChooser cho một sự thay đổi trên FILE_FILTER_CHANGED_PROPERTY tài sản, sau đó thay đổi phần mở rộng của tập tin được lựa chọn một cách thích hợp sử dụng setSelectedFile().


EDIT: Bạn nói đúng, giải pháp này không hoạt động. Nó chỉ ra rằng khi bộ lọc tập tin được thay đổi, tập tin được chọn sẽ bị xóa nếu loại tệp của nó không khớp với bộ lọc mới. Đó là lý do tại sao bạn nhận được null khi bạn cố gắng getSelectedFile().

Bạn có cân nhắc thêm tiện ích mở rộng sau này không? Khi tôi đang viết một JFileChooser, tôi thường thêm phần mở rộng sau khi người dùng đã chọn một tập tin để sử dụng và nhấp vào "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

Việc sử dụng getAbsolutePath() trong sự thay đổi trước thư mục hiện tại. Tôi ngạc nhiên khi hộp thoại JFileChooser hiển thị thư mục "Tài liệu của tôi" thay đổi thư mục dự án của Netbeans khi tôi chọn một FileFilter khác, vì vậy tôi đã thay đổi nó để sử dụng getName(). Tôi cũng đã sử dụng JDK 6 FileNameExtensionFilter.

Đây là mã:

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

Đây là nỗ lực của tôi lúc này. Nó sử dụng hàm accept() để kiểm tra xem tệp có vượt qua bộ lọc hay không. Nếu tên tệp không, phần mở rộng sẽ được nối vào cuối.

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

Bạn cũng có thể sử dụng PropertyChangeListener trên SELECTED_FILE_CHANGED_PROPERTY trước khi đính kèm hậu tố. Khi tệp được chọn được kiểm tra đối với bộ lọc mới (và sau đó được đặt thành không), sự kiện SELECTED_FILE_CHANGED_PROPERTY thực sự được kích hoạt trước sự kiện FILE_FILTER_CHANGED_PROPERTY.

Nếu evt.getOldValue()! = Null và evt.getNewValue() == null, bạn biết rằng JFileChooser đã làm hỏng tệp của bạn.Sau đó bạn có thể lấy tên của tệp cũ (bằng cách sử dụng ((File) evt.getOldValue()). GetName() như được mô tả ở trên), kéo phần mở rộng bằng cách sử dụng các hàm phân tích chuỗi tiêu chuẩn và thêm nó vào một biến thành viên có tên trong lớp của bạn . Bằng cách đó, khi sự kiện FILE_FILTER_CHANGED được kích hoạt (ngay sau đó, gần như tôi có thể xác định), bạn có thể kéo tên gốc đã được lưu trữ đó từ biến thành viên được đặt tên, áp dụng phần mở rộng cho loại bộ lọc tệp mới và đặt tệp được chọn của JFileChooser cho phù hợp.

3

Làm thế nào về điều này:

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); 
    } 
    } 
    } 
    } 
4

Đây là giải pháp của tôi và nó hoạt động tốt. Nó có thể giúp ai đó. Bạn có thể tạo lớp "MyExtensionFileFilter" của riêng mình, nếu không bạn phải sửa đổi mã.

public class MyFileChooser extends JFileChooser { 
    private File file = new File(""); 

    public MyFileChooser() { 
     addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener() { 
      public void propertyChange(PropertyChangeEvent e) { 
       String filename = MyFileChooser.this.file.getName(); 
       String extold = null; 
       String extnew = null; 
       if (e.getOldValue() == null || !(e.getOldValue() instanceof MyExtensionFileFilter)) { 
        return; 
       } 
       if (e.getNewValue() == null || !(e.getNewValue() instanceof MyExtensionFileFilter)) { 
        return; 
       } 
       MyExtensionFileFilter oldValue = ((MyExtensionFileFilter) e.getOldValue()); 
       MyExtensionFileFilter newValue = ((MyExtensionFileFilter) e.getNewValue()); 
       extold = oldValue.getExtension(); 
       extnew = newValue.getExtension(); 

       if (filename.endsWith(extold)) { 
        filename = filename.replace(extold, extnew); 
       } else { 
        filename += ("." + extnew); 
       } 
       setSelectedFile(new File(filename)); 
      } 
     }); 
    } 

    @Override 
    public void setSelectedFile(File file) { 
     super.setSelectedFile(file); 
     if(getDialogType() == SAVE_DIALOG) { 
      if(file != null) { 
       super.setSelectedFile(file); 
       this.file = file; 
      } 
     } 
    } 

    @Override 
    public void approveSelection() { 
     if(getDialogType() == SAVE_DIALOG) { 
      File f = getSelectedFile(); 
      if (f.exists()) { 
       String msg = "File existes ..."; 
       msg = MessageFormat.format(msg, new Object[] { f.getName() }); 
       int option = JOptionPane.showConfirmDialog(this, msg, "", JOptionPane.YES_NO_OPTION); 
       if (option == JOptionPane.NO_OPTION) { 
        return; 
       } 
      } 
     } 
     super.approveSelection(); 
    } 

    @Override 
    public void setVisible(boolean visible) { 
     super.setVisible(visible); 
     if(!visible) { 
      resetChoosableFileFilters(); 
     } 
    } 
} 
2

Đây là phương pháp để lấy tên tệp hiện tại (dưới dạng Chuỗi). Trong bạn nghe thay đổi sở hữu cho JFileChooser.FILE_FILTER_CHANGED_PROPERTY, bạn thực hiện cuộc gọi sau đây:

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

Phương pháp getFileName() của javax.swing.plaf.basic.BasicFileChooserUI (hậu duệ của FileChooserUI trả về bởi JFileChooser.getUI()) sẽ trở lại với nội dung của hộp văn bản của hộp thoại được sử dụng để gõ tên tệp. Dường như giá trị này luôn được đặt thành một chuỗi không null (nó trả về một chuỗi trống nếu hộp trống). Mặt khác, getSelectedFile() trả về null nếu người dùng chưa chọn tệp hiện có.

Dường như thiết kế của hộp thoại bị chi phối bởi khái niệm 'lựa chọn tệp'; có nghĩa là, trong khi hộp thoại hiển thị getSelectedFile() chỉ trả lại giá trị có ý nghĩa nếu người dùng đã chọn tệp hiện có hoặc chương trình được gọi là setSelectedFile(). getSelectedFile() sẽ trả về những gì người dùng đã nhập trong sau người dùng nhấp vào nút phê duyệt (tức là OK).

Kỹ thuật này sẽ chỉ hoạt động đối với hộp thoại chọn một, tuy nhiên việc thay đổi tiện ích tệp dựa trên bộ lọc đã chọn cũng chỉ có ý nghĩa đối với các tệp đơn lẻ ("Lưu dưới dạng ..." hoặc tương tự).

Thiết kế này là chủ đề của cuộc tranh luận tại sun.com vào năm 2003, xem link để biết chi tiết.

Các vấn đề liên quan