JFileChooser 按点击顺序打开多个文件
JFileChooser open multiple files in the order they are clicked
我有一个应用程序需要多个文件并根据它们的顺序应用一些操作(例如,一个接一个地合并它们)。
用户可以通过 Ctrl+单击或 Shift+单击按任意顺序select 文件。
选择器返回的列表文件与用户单击它们的顺序不同。我希望它们按照用户点击它们的相同顺序返回。
免责声明:我是 "the user"
我在 Windows 7 64 位上使用具有 Java 外观的 JFileChooser
class,JDK 7.
这是一个最小的例子
package choosertest;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public class ChooserTest extends JFrame {
JFileChooser chooser;
public ChooserTest() {
chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
testOpen();
}
public static void main(String[] args) {
new ChooserTest();
}
private void testOpen() {
int choice = chooser.showOpenDialog(this);
if (choice == JFileChooser.APPROVE_OPTION) {
File[] inputFiles = chooser.getSelectedFiles();
for (File f: inputFiles) {
System.out.println(f.getName());
}
}
}
}
与其根据 JFileChooser 中的选择顺序对文件进行排序,不如考虑在选择后使用类似 JTable/JList 的方式对文件重新排序。尽管如此,您可以通过向 JFileChooser 添加 PropertyChangeListener 来插入 JFileChooser 的侦听器系统以获取选择顺序。 Whenever a File is selected, the 'SelectedFilesChangedProperty' is fired, and PropertyChangeEvent.getNewValue() should return the selected files
final JFileChooser chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
chooser.addPropertyChangeListener(new PropertyChangeListener(){
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ( evt.getPropertyName().equals("SelectedFilesChangedProperty") ){
System.out.println(Arrays.toString((File[])evt.getNewValue()));
}
}
});
您需要检查由 getNewValue() return 编辑的文件数组,以查看选择(或取消选择)了哪个新文件以维持顺序。
我说到 Ctrl+click 有效,Shift+click selecting files "downwards" 有效。
但是,使用 Shift 键并单击 select 个文件 "upwards" 仍然会以错误的顺序添加文件,这可能会造成混淆。
此外,此解决方案不会更新 "File name" 文本字段以反映 selection 的实际顺序。不过,可能 "fix" 使用反射来做到这一点。
如果您需要按正确顺序快速解决 select 文件,方法是按住 Ctrl 键并单击它们,这很好用(select 和 deselect)。
package choosertest;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public class ChooserTest extends JFrame {
File[] selected;
JFileChooser chooser;
public ChooserTest() {
chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
testOpen();
}
public static void main(String[] args) {
new ChooserTest();
}
private void testOpen() {
chooser.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("SelectedFilesChangedProperty")) {
if (selected == null) {
selected = (File[]) evt.getNewValue();
} else {
File[] newSelection = (File[]) evt.getNewValue();
if (newSelection == null) {
selected = null;
}
// check back and forth to preserve the order of files
// as the user added them
else {
List<File> orderedSel = new LinkedList<>();
// add files that are still selected
for (File f : selected) {
for (File f2 : newSelection) {
if (f.equals(f2)) {
orderedSel.add(f);
break;
}
}
}
Arrays.sort(selected);
// add newly selected files
for (File f : newSelection) {
if (Arrays.binarySearch(selected, f) < 0) {
orderedSel.add(f);
}
}
selected = orderedSel.toArray(
new File[orderedSel.size()]);
}
}
System.out.println(Arrays.toString(selected)); //debug
}
}
});
// copy previous array of selected files
File[] prevSelected = null;
if (selected != null) {
prevSelected = new File[selected.length];
System.arraycopy( selected, 0, prevSelected, 0, selected.length );
}
int choice = chooser.showOpenDialog(this);
// if the user did not cancel the selection
if (choice == JFileChooser.APPROVE_OPTION) {
System.out.println("FINAL selection: " + Arrays.toString(selected)); //debug
} else {
// restore the previous selection
selected = prevSelected;
System.out.println("PREVIOUS selection: " + Arrays.toString(selected)); //debug
}
}
}
修改以上代码以在文本字段中按选择顺序显示
/*
* FileName :SelectedOrderedFileChooser.java
*/
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JTextField;
import javax.swing.plaf.metal.MetalFileChooserUI;
/**
* File Chooser with selection order<br>
* Only work for Ctrl + click selection
*/
public class SelectedOrderedFileChooser extends JFileChooser{
/** Selection order file name list */
private List<String> selectedFileNames = new ArrayList<String>();
boolean isSelectionOrder = false;
/**
* Constructor
*/
public SelectedOrderedFileChooser() {
super();
setSelectionOrder(false);
}
/**
* Constructor
* @param aIsSelectionOrder Selection ordered or not<br>
* true : Selection order, false : File Name order(JFileChooser Default)
*/
public SelectedOrderedFileChooser(boolean aIsSelectionOrder) {
super();
setSelectionOrder(aIsSelectionOrder);
}
/**
* Get selected file names in selection order
* @param fs Selected files
* @return File names in selection order
*/
private List<String> getFileNamesInSelectionOrder(File[] fs) {
List<String> tmpSelectedFileNames = new ArrayList<String>();
List<String> tmpResultFileNames = new ArrayList<String>();
for (File f : fs) {
// Get all current selected file names
tmpSelectedFileNames.add(f.getAbsolutePath());
}
for (String fn : selectedFileNames) {
if (tmpSelectedFileNames.contains(fn)) {
// If ordered selected file name is in current selected file names, add to temporary file name list
tmpResultFileNames.add(fn);
}
}
// If there are current selected file names that is not in temporary file name list, add them
for (String fn : tmpSelectedFileNames) {
if (tmpResultFileNames.contains(fn) == false) {
tmpResultFileNames.add(fn);
}
}
return tmpResultFileNames;
}
/**
* Get selected file names
* @return Selected file names
*/
public List<String> getSelectedFileNames() {
return selectedFileNames;
}
/**
* Is selection order or not?
* @return true : Selection order, false : File Name order(JFileChooser Default)
*/
public boolean isSelectionOrder() {
return isSelectionOrder;
}
/**
* Set whether file selection order or not.
* @param aIsSelectionOrder true : Selection order, false : File Name order(JFileChooser Default)
*/
public void setSelectionOrder(boolean aIsSelectionOrder) {
this.isSelectionOrder = aIsSelectionOrder;
this.addPropertyChangeListener(new PropertyChangeListener(){
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ( evt.getPropertyName().equals("SelectedFilesChangedProperty") ){
File[] fs = (File[])evt.getNewValue();
if (null != fs && fs.length > 0) {
if (isSelectionOrder) {
// If selection order、get file name in selection order and set to selected order file name list
List<String> tmpResultFileNames = getFileNamesInSelectionOrder(fs);
selectedFileNames = tmpResultFileNames;
showTextField();
} else {
// If not selection order、FileChooser default order
selectedFileNames.clear();
for (File f : fs) {
selectedFileNames.add(f.getAbsolutePath());
}
}
}
}
}
});
}
/**
* Get selection ordered files in array
* @return selection ordered files in array
*/
public File[] getSelectedOrderedFiles() {
List<File> ret = new ArrayList<File>();
for (String fName : selectedFileNames) {
File f = new File(fName);
ret.add(f);
}
return ret.toArray(new File[ret.size()]);
}
/**
* Show file names in selection order in text field of JFileChooser
*/
public void showTextField(){
try {
String res = "";
for (File f : getSelectedOrderedFiles()) {
res += "\"" + f.getName() + "\" ";
}
MetalFileChooserUI ui = (MetalFileChooserUI)this.getUI();
Field field;
field = MetalFileChooserUI.class.getDeclaredField("fileNameTextField");
field.setAccessible(true);
JTextField tf = (JTextField) field.get(ui);
tf.setText(res.trim());
} catch (Exception e) {
e.printStackTrace();
}
}
}
我有一个应用程序需要多个文件并根据它们的顺序应用一些操作(例如,一个接一个地合并它们)。
用户可以通过 Ctrl+单击或 Shift+单击按任意顺序select 文件。
选择器返回的列表文件与用户单击它们的顺序不同。我希望它们按照用户点击它们的相同顺序返回。
免责声明:我是 "the user"
我在 Windows 7 64 位上使用具有 Java 外观的 JFileChooser
class,JDK 7.
这是一个最小的例子
package choosertest;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public class ChooserTest extends JFrame {
JFileChooser chooser;
public ChooserTest() {
chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
testOpen();
}
public static void main(String[] args) {
new ChooserTest();
}
private void testOpen() {
int choice = chooser.showOpenDialog(this);
if (choice == JFileChooser.APPROVE_OPTION) {
File[] inputFiles = chooser.getSelectedFiles();
for (File f: inputFiles) {
System.out.println(f.getName());
}
}
}
}
与其根据 JFileChooser 中的选择顺序对文件进行排序,不如考虑在选择后使用类似 JTable/JList 的方式对文件重新排序。尽管如此,您可以通过向 JFileChooser 添加 PropertyChangeListener 来插入 JFileChooser 的侦听器系统以获取选择顺序。 Whenever a File is selected, the 'SelectedFilesChangedProperty' is fired, and PropertyChangeEvent.getNewValue() should return the selected files
final JFileChooser chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
chooser.addPropertyChangeListener(new PropertyChangeListener(){
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ( evt.getPropertyName().equals("SelectedFilesChangedProperty") ){
System.out.println(Arrays.toString((File[])evt.getNewValue()));
}
}
});
您需要检查由 getNewValue() return 编辑的文件数组,以查看选择(或取消选择)了哪个新文件以维持顺序。
我说到 Ctrl+click 有效,Shift+click selecting files "downwards" 有效。
但是,使用 Shift 键并单击 select 个文件 "upwards" 仍然会以错误的顺序添加文件,这可能会造成混淆。
此外,此解决方案不会更新 "File name" 文本字段以反映 selection 的实际顺序。不过,可能 "fix" 使用反射来做到这一点。
如果您需要按正确顺序快速解决 select 文件,方法是按住 Ctrl 键并单击它们,这很好用(select 和 deselect)。
package choosertest;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public class ChooserTest extends JFrame {
File[] selected;
JFileChooser chooser;
public ChooserTest() {
chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
testOpen();
}
public static void main(String[] args) {
new ChooserTest();
}
private void testOpen() {
chooser.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("SelectedFilesChangedProperty")) {
if (selected == null) {
selected = (File[]) evt.getNewValue();
} else {
File[] newSelection = (File[]) evt.getNewValue();
if (newSelection == null) {
selected = null;
}
// check back and forth to preserve the order of files
// as the user added them
else {
List<File> orderedSel = new LinkedList<>();
// add files that are still selected
for (File f : selected) {
for (File f2 : newSelection) {
if (f.equals(f2)) {
orderedSel.add(f);
break;
}
}
}
Arrays.sort(selected);
// add newly selected files
for (File f : newSelection) {
if (Arrays.binarySearch(selected, f) < 0) {
orderedSel.add(f);
}
}
selected = orderedSel.toArray(
new File[orderedSel.size()]);
}
}
System.out.println(Arrays.toString(selected)); //debug
}
}
});
// copy previous array of selected files
File[] prevSelected = null;
if (selected != null) {
prevSelected = new File[selected.length];
System.arraycopy( selected, 0, prevSelected, 0, selected.length );
}
int choice = chooser.showOpenDialog(this);
// if the user did not cancel the selection
if (choice == JFileChooser.APPROVE_OPTION) {
System.out.println("FINAL selection: " + Arrays.toString(selected)); //debug
} else {
// restore the previous selection
selected = prevSelected;
System.out.println("PREVIOUS selection: " + Arrays.toString(selected)); //debug
}
}
}
修改以上代码以在文本字段中按选择顺序显示
/*
* FileName :SelectedOrderedFileChooser.java
*/
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JTextField;
import javax.swing.plaf.metal.MetalFileChooserUI;
/**
* File Chooser with selection order<br>
* Only work for Ctrl + click selection
*/
public class SelectedOrderedFileChooser extends JFileChooser{
/** Selection order file name list */
private List<String> selectedFileNames = new ArrayList<String>();
boolean isSelectionOrder = false;
/**
* Constructor
*/
public SelectedOrderedFileChooser() {
super();
setSelectionOrder(false);
}
/**
* Constructor
* @param aIsSelectionOrder Selection ordered or not<br>
* true : Selection order, false : File Name order(JFileChooser Default)
*/
public SelectedOrderedFileChooser(boolean aIsSelectionOrder) {
super();
setSelectionOrder(aIsSelectionOrder);
}
/**
* Get selected file names in selection order
* @param fs Selected files
* @return File names in selection order
*/
private List<String> getFileNamesInSelectionOrder(File[] fs) {
List<String> tmpSelectedFileNames = new ArrayList<String>();
List<String> tmpResultFileNames = new ArrayList<String>();
for (File f : fs) {
// Get all current selected file names
tmpSelectedFileNames.add(f.getAbsolutePath());
}
for (String fn : selectedFileNames) {
if (tmpSelectedFileNames.contains(fn)) {
// If ordered selected file name is in current selected file names, add to temporary file name list
tmpResultFileNames.add(fn);
}
}
// If there are current selected file names that is not in temporary file name list, add them
for (String fn : tmpSelectedFileNames) {
if (tmpResultFileNames.contains(fn) == false) {
tmpResultFileNames.add(fn);
}
}
return tmpResultFileNames;
}
/**
* Get selected file names
* @return Selected file names
*/
public List<String> getSelectedFileNames() {
return selectedFileNames;
}
/**
* Is selection order or not?
* @return true : Selection order, false : File Name order(JFileChooser Default)
*/
public boolean isSelectionOrder() {
return isSelectionOrder;
}
/**
* Set whether file selection order or not.
* @param aIsSelectionOrder true : Selection order, false : File Name order(JFileChooser Default)
*/
public void setSelectionOrder(boolean aIsSelectionOrder) {
this.isSelectionOrder = aIsSelectionOrder;
this.addPropertyChangeListener(new PropertyChangeListener(){
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ( evt.getPropertyName().equals("SelectedFilesChangedProperty") ){
File[] fs = (File[])evt.getNewValue();
if (null != fs && fs.length > 0) {
if (isSelectionOrder) {
// If selection order、get file name in selection order and set to selected order file name list
List<String> tmpResultFileNames = getFileNamesInSelectionOrder(fs);
selectedFileNames = tmpResultFileNames;
showTextField();
} else {
// If not selection order、FileChooser default order
selectedFileNames.clear();
for (File f : fs) {
selectedFileNames.add(f.getAbsolutePath());
}
}
}
}
}
});
}
/**
* Get selection ordered files in array
* @return selection ordered files in array
*/
public File[] getSelectedOrderedFiles() {
List<File> ret = new ArrayList<File>();
for (String fName : selectedFileNames) {
File f = new File(fName);
ret.add(f);
}
return ret.toArray(new File[ret.size()]);
}
/**
* Show file names in selection order in text field of JFileChooser
*/
public void showTextField(){
try {
String res = "";
for (File f : getSelectedOrderedFiles()) {
res += "\"" + f.getName() + "\" ";
}
MetalFileChooserUI ui = (MetalFileChooserUI)this.getUI();
Field field;
field = MetalFileChooserUI.class.getDeclaredField("fileNameTextField");
field.setAccessible(true);
JTextField tf = (JTextField) field.get(ui);
tf.setText(res.trim());
} catch (Exception e) {
e.printStackTrace();
}
}
}