14

Javaでダイアグラムエディタを書いています。このアプリには、.jpg、.png などのさまざまな標準画像形式にエクスポートするオプションがあります。ユーザーが [ファイル] -> [エクスポート] をクリックすると、多数の が含まれる が取得さJFileChooserFileFilterます。.jpg.png

ここに私の質問があります:

デフォルトの拡張子を選択したファイル フィルタに合わせて調整する方法はありますか? たとえば、ドキュメントの名前が「lolcat」の場合、png フィルターが選択されている場合、デフォルトのオプションは「lolcat.png」である必要があり、ユーザーが jpg ファイル フィルターを選択している場合、デフォルトは「lolcat.jpg」に自動的に変更されます。

これは可能ですか?どうすればいいですか?

編集:以下の回答に基づいて、いくつかのコードを書きました。しかし、まだうまくいきません。に を追加しましたpropertyChangeListenerFILE_FILTER_CHANGED_PROPERTY、このメソッド内でgetSelectedFile()null が返されるようです。これがコードです。

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

8 に答える 8

12

JFileChooserプロパティの変更をリッスンしてから、をFILE_FILTER_CHANGED_PROPERTY使用して選択したファイルの拡張子を適切に変更できるようですsetSelectedFile()


編集:その通り、このソリューションは機能しません。ファイルフィルターを変更すると、そのファイルタイプが新しいフィルターと一致しない場合、選択したファイルが削除されることがわかります。nullそれがあなたがしようとしたときにあなたが得ている理由ですgetSelectedFile()

後で拡張機能を追加することを検討しましたか?私が書いているときJFileChooser、私は通常、ユーザーが使用するファイルを選択して「保存」をクリックした後に拡張子を追加します。

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));
  }
});
于 2009-02-27T20:41:58.343 に答える
5

これはどう:

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 );
     }
    }
   }
  }
于 2010-11-25T10:45:38.780 に答える
4

サフィックスを付ける前に、SELECTED_FILE_CHANGED_PROPERTY で PropertyChangeListener を使用することもできます。選択したファイルが新しいフィルターに対してチェックされる (その後 null に設定される) と、実際には SELECTED_FILE_CHANGED_PROPERTY イベントがFILE_FILTER_CHANGED_PROPERTY イベントの前に発生します。

evt.getOldValue() != null および evt.getNewValue() == null の場合、JFileChooser がファイルをブラストしたことがわかります。次に、古いファイルの名前を取得し (上記のように ((File)evt.getOldValue()).getName() を使用)、標準の文字列解析関数を使用して拡張子を取得し、クラス内の名前付きメンバー変数に格納します。 .

そうすれば、FILE_FILTER_CHANGED イベントがトリガーされたときに (その直後、私が判断できる限り)、名前付きメンバー変数からその隠しルート名を取得し、新しいファイル フィルター タイプの拡張子を適用し、JFileChooser の選択したファイルを設定できます。によると。

于 2010-08-12T13:45:17.923 に答える
4

Here is my solution and it works fine. It maybe helps someone. You sould create your own "MyExtensionFileFilter" class, otherwise you have to modify the code.

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();
        }
    }
}
于 2013-01-16T14:45:02.990 に答える
3

現在のファイル名を (文字列として) 取得するメソッドを次に示します。のプロパティ変更リスナーでJFileChooser.FILE_FILTER_CHANGED_PROPERTY、次の呼び出しを行います。

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

(によって返されるの子孫)のgetFileName()メソッドは、ファイル名を入力するために使用されるダイアログのテキスト ボックスの内容を返します。この値は常に null 以外の文字列に設定されているようです (ボックスが空の場合は空の文字列を返します)。一方、ユーザーがまだ既存のファイルを選択していない場合は null を返します。javax.swing.plaf.basic.BasicFileChooserUIFileChooserUIJFileChooser.getUI()getSelectedFile()

ダイアログのデザインは「ファイル選択」の概念に基づいているようです。つまり、ダイアログが表示されている間getSelectedFile()は、ユーザーが既存のファイルまたは呼び出されたプログラムを既に選択している場合にのみ意味のある値を返しますsetSelectedFile()。ユーザーが承認 (つまり OK) ボタンをクリックした後にgetSelectedFile()、ユーザーが入力した内容を返します。

この手法は単一選択ダイアログでのみ機能しますが、選択したフィルターに基づいてファイル拡張子を変更することは、単一ファイル (「名前を付けて保存...」ダイアログなど) に対してのみ有効です。

このデザインは、2003 年に sun.com で議論の対象となりました。詳細については、リンクを参照してください。

于 2013-02-28T15:29:19.540 に答える
0

前の getAbsolutePath() の使用は、現在のディレクトリを変更します。別の FileFilter を選択すると、「マイ ドキュメント」ディレクトリを表示する JFileChooser ダイアログが Netbeans のプロジェクト ディレクトリに変更されて驚いたので、getName() を使用するように変更しました。JDK 6 FileNameExtensionFilter も使用しました。

コードは次のとおりです。

    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));
            }
        }
    });
于 2009-03-29T23:39:19.663 に答える
0

これが私の試みです。accept() 関数を使用して、ファイルがフィルターを通過するかどうかを確認します。ファイル名がそうでない場合、拡張子が末尾に追加されます。

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();
        }
    };
于 2010-06-11T06:13:05.027 に答える