【发布时间】:2010-05-21 15:34:20
【问题描述】:
我觉得应该有一个简单的方法来做到这一点,但我想不通。我有一个允许用户选择目录的 JFileChooser。我想显示目录中的所有文件以给用户一些上下文,但只有目录应该被接受为选择(可能在选择文件时打开按钮将被禁用)。有没有简单的方法可以做到这一点?
【问题讨论】:
标签: java swing jfilechooser
我觉得应该有一个简单的方法来做到这一点,但我想不通。我有一个允许用户选择目录的 JFileChooser。我想显示目录中的所有文件以给用户一些上下文,但只有目录应该被接受为选择(可能在选择文件时打开按钮将被禁用)。有没有简单的方法可以做到这一点?
【问题讨论】:
标签: java swing jfilechooser
我的解决方案是合并camickr和trashgod的答案:
final JFileChooser chooser = new JFileChooser() {
public void approveSelection() {
if (getSelectedFile().isFile()) {
return;
} else
super.approveSelection();
}
};
chooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES );
【讨论】:
JFileChooser.FILES_AND_DIRECTORIES 很重要!没有它,(如camickr 的回答),正如我测试的那样,解决方案无用。
见setFileSelectionMode()How to Use File Choosers:
setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY)
附录:取消注释这个FileChooserDemo的第73行可以看到效果,但它似乎是平台相关的。
附录:如果使用FILES_AND_DIRECTORIES,请考虑相应更改按钮文本:
chooser.setApproveButtonText("Choose directory");
由于效果取决于 L&F,请考虑在已经满足您的 UI 要求的平台上使用 DIRECTORIES_ONLY:
if (System.getProperty("os.name").startsWith("Mac OS X")) {
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
} else {
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
}
【讨论】:
覆盖approveSelection() 方法。比如:
JFileChooser chooser = new JFileChooser( new File(".") )
{
public void approveSelection()
{
if (getSelectedFile().isFile())
{
// beep
return;
}
else
super.approveSelection();
}
};
【讨论】:
覆盖approveSelection 的解决方案可能会让某些用户感到厌烦。
有时,用户会无缘无故地单击目录中的文件(即使她想选择目录而不是文件)。如果发生这种情况,用户将(种类)卡在JFileChooser 中,因为approveSelection 将失败,即使她取消选择该文件。为了避免这种烦恼,这就是我所做的:
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(
JFileChooser.FILES_AND_DIRECTORIES);
int option = fileChooser.showDialog(null,
"Select Directory");
if (option == JFileChooser.APPROVE_OPTION) {
File f = fileChooser.getSelectedFile();
// if the user accidently click a file, then select the parent directory.
if (!f.isDirectory()) {
f = f.getParentFile();
}
System.out.println("Selected directory for import " + f);
}
在我看来,即使用户选择了文件,选择目录也会导致更好的可用性。
【讨论】:
AFAIK JFileChooser 将文件过滤(可以查看的内容,非常可配置)与选择过滤(可以选择的内容)分开。
选择过滤的配置受到更多限制,但 AFAIK 你可以选择只允许使用setFileSelectionMode() 选择目录或文件
【讨论】:
保留fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY) 并使用:
File[] selectedFiles = fileChooser.getSelectedFile().listFiles();
【讨论】:
JFileChooser 支持三种选择模式:仅文件、仅目录以及文件和目录。在您的情况下,您需要的是:
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
【讨论】:
Select Multiple Folders But Show All Included files
import javax.swing.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
public class MultipleFilesAndDirectoryChooserButDisplayFiles {
public static void main(String[] args) {
ArrayList<File> tempFiles = new ArrayList<>();
ArrayList<File> finalFiles = new ArrayList<>();
ArrayList<String> relativeFiles = new ArrayList<>();
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("Choose File To Transfer");
fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
fileChooser.setMultiSelectionEnabled(true);
int returnVal = fileChooser.showOpenDialog(null);
fileChooser.approveSelection();
if (returnVal == JFileChooser.APPROVE_OPTION) {
fileChooser.approveSelection();
var fileAddress = fileChooser.getSelectedFiles();
for (var arrElement : fileAddress) {
tempFiles.add(arrElement);
File baseFile;
baseFile = arrElement.getParentFile();
Iterator<File> iterator = tempFiles.iterator();
while (iterator.hasNext()) {
File file = iterator.next();
if (file.isDirectory()) {
var enclosedFiles = file.listFiles();
if (enclosedFiles != null) {
if (enclosedFiles.length != 0) {
var index = tempFiles.indexOf(file);
tempFiles.remove(file);
tempFiles.addAll(index, Arrays.asList(enclosedFiles));
iterator = tempFiles.iterator();
} else {
tempFiles.remove(file);
finalFiles.add(file);
relativeFiles.add(baseFile.toURI().relativize(file.toURI()).getPath());
iterator = tempFiles.iterator();
}
}
} else if (file.isFile()) {
tempFiles.remove(file);
finalFiles.add(file);
relativeFiles.add(baseFile.toURI().relativize(file.toURI()).getPath());
iterator = tempFiles.iterator();
}
}
}
for (var relativeFile : relativeFiles) {
System.out.println(relativeFile);
}
for (var file : finalFiles) {
System.out.println(file);
}
}
}
}
输出:
Folder1/EmptyFolder/
文件夹1/子文件夹1/1.1.txt
文件夹1/子文件夹1/1.2.txt
文件夹1/子文件夹1/1.3.txt
文件夹 1/子文件夹 1/子文件夹 1.1/1.1.1.txt
文件夹1/子文件夹1/子文件夹1.1/1.2.1.txt
文件夹1/子文件夹1/子文件夹1.1/1.3.1.txt
文件夹1/子文件夹2/2.1/2.1.1.txt
文件夹1/子文件夹2/2.1/2.1.2.txt
文件夹1/子文件夹2/2.1/2.1.3.txt
文件夹1/子文件夹3/3.1.txt
文件夹1/子文件夹3/3.2.txt
文件夹1/子文件夹3/3.3.txt
文件夹2/子文件夹/2.1.txt
Folder2/子文件夹/EmptyFolder/
file1.txt
file2.txt
E:\Folder1\EmptyFolder
E:\Folder1\SubFolder1\1.1.txt
E:\Folder1\SubFolder1\1.2.txt
E:\Folder1\SubFolder1\1.3.txt
E:\Folder1\SubFolder1\SubFolder 1.1\1.1.1.txt
E:\Folder1\SubFolder1\SubFolder 1.1\1.2.1.txt
E:\Folder1\SubFolder1\SubFolder 1.1\1.3.1.txt
E:\Folder1\SubFolder2\2.1\2.1.1.txt
E:\Folder1\SubFolder2\2.1\2.1.2.txt
E:\Folder1\SubFolder2\2.1\2.1.3.txt
E:\Folder1\SubFolder3\3.1.txt
E:\Folder1\SubFolder3\3.2.txt
E:\Folder1\SubFolder3\3.3.txt
E:\Folder2\子文件夹\2.1.txt
E:\Folder2\子文件夹\EmptyFolder
E:\file1.txt
E:\file2.txt
【讨论】:
我认为最好的解决方案是允许用户选择文件或目录。如果用户选择一个文件,只需使用该文件所在的目录即可。
【讨论】: