настройка выбранного файла для FileFilter в JFileChooser
Я пишу редактор диаграмм на java. Это приложение имеет возможность экспортировать в различные стандартные форматы изображений, такие как .формат JPG. ,png и др. Когда пользователь нажимает File - >Export, вы получаете JFileChooser
, который имеет ряд FileFilter
s в нем, для .jpg
, .png
etc.
теперь вот мой вопрос:
есть ли способ настроить расширение по умолчанию для выбранного фильтра файлов? Е. Г. если документ назван "lolcat", то опция по умолчанию должна быть "lolcat.формат PNG" когда фильтр png выбран, и когда пользователь выбирает фильтр файлов jpg, значение по умолчанию должно измениться на " lolcat.форматы jpg" автоматически.
это возможно? Как я могу это сделать?
изменить:
Основываясь на приведенном ниже ответе, я написал код. Но пока это не работает. Я добавил propertyChangeListener
до FILE_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();
}
});
}
}
7 ответов
похоже, вы можете слушать JFileChooser
изменить на FILE_FILTER_CHANGED_PROPERTY
свойство, затем измените расширение выбранного файла соответствующим образом, используя setSelectedFile()
.
EDIT: вы правы, это решение не работает. Оказывается, при изменении фильтра файлов выбранный файл удаляется, если его тип не соответствует новому фильтру. Вот почему вы получаете 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));
}
});
вы также можете использовать PropertyChangeListener на SELECTED_FILE_CHANGED_PROPERTY до присоединения суффикса. Когда выбранный файл проверяется на новый фильтр (а затем устанавливается в значение null), событие SELECTED_FILE_CHANGED_PROPERTY фактически запускается до событие FILE_FILTER_CHANGED_PROPERTY.
Если evt.getOldValue ()!= null и evt.getNewValue () = = null, вы знаете, что JFileChooser взорвал ваш файл. Затем вы можете захватить имя старого файла (используя ((File)evt.getOldValue ()).getName () как описано выше), извлеките расширение с помощью стандартных функций синтаксического анализа строк и спрячьте его в именованную переменную-член в своем классе.
таким образом, когда событие FILE_FILTER_CHANGED запускается (сразу после этого, насколько я могу определить), Вы можете вытащить это скрытое корневое имя из именованной переменной-члена, применить расширение для нового типа фильтра файлов и установить выбранный файл JFileChooser соответственно.
вот мое решение, и она отлично работает. Может, это кому-то поможет. Вы должны создать свой собственный класс "MyExtensionFileFilter", иначе вам придется изменить код.
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();
}
}
}
Как насчет этого:
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 );
}
}
}
}
вот метод для получения текущего имени файла (в виде строки). В вашем прослушивателе изменения свойства для 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()
метод javax.swing.plaf.basic.BasicFileChooserUI
(потомок FileChooserUI
возвращено JFileChooser.getUI()
) возвращает содержимое текстового поля диалогового окна, которое используется для ввода имени файла. Кажется, что это значение всегда устанавливается в ненулевую строку (она возвращает пустую строку, если поле пустое). С другой стороны,--6--> возвращает null, если пользователь еще не выбрал существующий файл.
кажется, что дизайн диалога управляется концепцией "выбор файла"; то есть, в то время как диалог виден getSelectedFile()
возвращает только значения, если пользователь уже выбрал существующий файл или программу, под названием setSelectedFile()
. getSelectedFile()
вернет то, что пользователь набрал в после пользователь нажимает кнопку утвердить (т. е. OK).
метод будет работать только для одно-выбора диалоги, однако изменение расширения файла на основе выбранного фильтра также должно иметь смысл только для отдельных файлов ("Сохранить как..."диалоги или аналогичные).
этот дизайн был предметом обсуждения на sun.com еще в 2003 году см. ссылке для сведения.
использование getAbsolutePath () в предыдущем изменении текущего каталога. Я был удивлен, когда диалоговое окно 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));
}
}
});
вот моя попытка. Он использует функцию 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();
}
};