When you show an instance of JFileChooser set to DIRECTORIES_ONLY mode, it still allows manually typing filenames in the textfield. It is possible to override the approveSelection()
method to further validate any selection made by the user, however this method isn't even called when a valid file is selected in this mode, because JFileChooser just cancels when you click the Approve button.
How can I change this behaviour? I want to show a warning message when the user selects a file instead of a directory, and keep the dialog open so they have to try again. Similar to how you can override approveSelection()
to show a confirmation dialog when clicking the Approve button before closing the dialog, when saving a file that already exists.
(I don't understand why the default behaviour of JFileChooser in directories-only mode allows file selections to go through anyway)
I have already looked into the FileChooserUI class to check the internal behaviour of what actually calls approveSelection()
and cancelSelection()
, but it looks far too complicated to override for a simple goal such as this.
To make JFileChooser
return an APPROVE_OPTION
state and a file that is selected instead of CANCEL_OPTION
and null
the FILES_AND_DIRECTORIES
selection mode and a custom FileFilter
(matching nothing) can be used.
To show a chooser repeatedly (as already suggested in the comments) a dialog opening can be placed inside a loop (not recursion) which will continue only if user keeps selecting a file that is not valid. It depends on a use case but an additional check can be made to ensure that selected directory exists.
Once a loop ends the chooser return state will be kept in a variable allowing to differentiate between approve, cancel, and error operations.
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
fc.setFileFilter(new FileNameExtensionFilter("Directories", "NON_EXISTENT_EXTENSION"));
fc.setAcceptAllFileFilterUsed(false);
int fcReturnState;
while (true) {
fcReturnState = fc.showOpenDialog(null);
File file = fc.getSelectedFile();
boolean valid = (file != null && file.exists() && file.isDirectory());
if (fcReturnState == JFileChooser.APPROVE_OPTION && !valid) {
String fileErr = (file == null) ? "No file selected." : String.format(
"%s \"%s\" %s.", (file.exists() ? "File" : "Directory"),
file.getAbsolutePath(),
(!file.exists() ? "does not exist" : "is not a directory"));
JOptionPane.showMessageDialog(null, fileErr + " Please try again.",
"Warning", JOptionPane.ERROR_MESSAGE);
} else {
break;
}
}
if (fcReturnState == JFileChooser.APPROVE_OPTION) {
System.out.println("Directory selected: " + fc.getSelectedFile().getAbsolutePath());
} else if (fcReturnState == JFileChooser.CANCEL_OPTION) {
System.out.println("Selection cancelled");
} else if (fcReturnState == JFileChooser.ERROR_OPTION) {
System.out.println("Selection error occurred");
}