Reputation: 668
I have a singleton pattern class called MyFileChooser which adapts if JFileChooser is FILES_ONLY
or DIRECTORIES_ONLY
according to constructor parameter.
I wish to have the JFileChooser inside JFrame, so I can add additional information above and below JFileChooser frame, so the structure will look:
JFrame
| JLabel
| JFileChooser
| JLabel
// end of JFrame
import javax.swing.JFrame;
import javax.swing.JFileChooser;
public class MyFileChooser {
private JFrame frame;
private boolean isFilesOnly;
private static final MyFileChooser instance_files = new MyFileChooser( true );
private static final MyFileChooser instance_dirs = new MyFileChooser( false );
private JFileChooser dynamicChooser;
private MyFileChooser( boolean filesOnly ) {
this.frame = new JFrame();
this.isFilesOnly = filesOnly;
this.dynamicChooser = new JFileChooser();
this.frameSetup();
this.chooserSetup();
}
public MyFileChooser getInstance( boolean filesOnly ) {
if ( filesOnly ) {
return MyFileChooser.instance_files;
} else {
return MyFileChooser.instance_dirs;
}
}
public void frameSetup() {
// jframe and labels setup code
this.frame.getContentPane().add( this.dynamicChooser );
}
public void chooserSetup() {
if ( this.isFilesOnly ) {
this.dynamicChooser.setFileSelectionMode( JFileChooser.FILES_ONLY );
} else {
this.dynamicChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
}
this.dynamicChooser.setMultiSelectionEnabled(true);
this.dynamicChooser.setDialogType(JFileChooser.CUSTOM_DIALOG);
}
The issue is that I dont know how to attach handler for "Close" and "Open" buttons of JFileChooser. The only thing I've found is:
public void handleSelectedFiles() {
int returnVal = this.dynamicChooser.showDialog(this.frame, "Open");
if (returnVal == JFileChooser.APPROVE_OPTION) {
File[] files = this.dynamicChooser.getSelectedFiles();
// do something
}
}
But, it opens both instances if this method is called and even without JFrame wrap & JLabels from required structure. So my question is how can I get button of "Open" and "Close" from JFileChooser to attach handler (different for instances) or how to handle the selected files by other way.
Upvotes: 1
Views: 1114
Reputation: 347332
Your first problem is here
int returnVal = this.dynamicChooser.showDialog(this.frame, "Open");
It's call the underlying JFileChooser
's showDialog
method, so it's constructing its own window, ignoring yours
A better solution is create a JDialog
on demand and use it to container your file chooser and other controls
Something a little more like...
public class MyFileChooser {
private final boolean isFilesOnly;
private static final MyFileChooser INSTANCE_FILES = new MyFileChooser(true);
private static final MyFileChooser INSTANCE_DIRS = new MyFileChooser(false);
private final JFileChooser dynamicChooser;
private MyFileChooser(boolean filesOnly) {
this.isFilesOnly = filesOnly;
this.dynamicChooser = new JFileChooser();
dynamicChooser.setControlButtonsAreShown(false);
this.chooserSetup();
}
public MyFileChooser getInstance(boolean filesOnly) {
if (filesOnly) {
return MyFileChooser.INSTANCE_FILES;
} else {
return MyFileChooser.INSTANCE_DIRS;
}
}
public void frameSetup(Container parent) {
// jframe setup code
parent.add(this.dynamicChooser);
}
public void chooserSetup() {
if (this.isFilesOnly) {
this.dynamicChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
} else {
this.dynamicChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
}
this.dynamicChooser.setMultiSelectionEnabled(true);
this.dynamicChooser.setDialogType(JFileChooser.CUSTOM_DIALOG);
}
public File[] showOpenDialog(Component parent, String title) {
JDialog dialog = new JDialog(parent == null ? null : SwingUtilities.getWindowAncestor(parent), title);
dialog.setModal(true);
frameSetup(dialog);
dialog.pack();
dialog.setLocationRelativeTo(parent);
dialog.setVisible(true);
return dynamicChooser.getSelectedFiles();
}
}
The intention is to mimic the actions of showDialog
from JFileChooser
. In this example, I've hidden the "normal" control buttons, as I assume you'll be providing your own, through which you can change the return file
Now, if you still want to use the standard button controls, you can attach an ActionListener
to the JFileChooser
dynamicChooser.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
//...
}
});
When I was testing, the Cancel button return CancelSelection
and Choose button return ApproveSelection
Now, because my example uses a dynamic dialog, you may need to create a dynamic ActionListener
which can control the dialog, because you don't want to keep adding ActionListener
s to the FileChooser
without removing them, something like...
public File[] showOpenDialog(Component parent, String title) {
JDialog dialog = new JDialog(parent == null ? null : SwingUtilities.getWindowAncestor(parent), title);
dialog.setModal(true);
frameSetup(dialog);
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
//..
dialog.dispose();
}
};
dynamicChooser.addActionListener(listener);
dialog.pack();
dialog.setLocationRelativeTo(parent);
dialog.setVisible(true);
dynamicChooser.removeActionListener(listener);
return dynamicChooser.getSelectedFiles();
}
as an example
Because I know someone will kick me to curb if I don't...
Sington's in Java are tricky things and there are countless threads on the subject, however, it's generally accepted that the best approach (now) is to use a enum
, which solves all the synchronisation issues of old
So, instead, you might consider using something like..
public static enum MyFileChooser {
INSTANCE_FILES(true),
INSTANCE_DIRS(false);
private final boolean isFilesOnly;
private final JFileChooser dynamicChooser;
private MyFileChooser(boolean filesOnly) {
this.isFilesOnly = filesOnly;
this.dynamicChooser = new JFileChooser();
//dynamicChooser.setControlButtonsAreShown(false);
this.chooserSetup();
}
public void frameSetup(Container parent) {
// jframe setup code
parent.add(this.dynamicChooser);
}
public void chooserSetup() {
if (this.isFilesOnly) {
this.dynamicChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
} else {
this.dynamicChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
}
this.dynamicChooser.setMultiSelectionEnabled(true);
this.dynamicChooser.setDialogType(JFileChooser.CUSTOM_DIALOG);
}
public File[] showOpenDialog(Component parent, String title) {
JDialog dialog = new JDialog(parent == null ? (JDialog)null : SwingUtilities.getWindowAncestor(parent), title);
dialog.setModal(true);
frameSetup(dialog);
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
//..
dialog.dispose();
}
};
dynamicChooser.addActionListener(listener);
dialog.pack();
dialog.setLocationRelativeTo(parent);
dialog.setVisible(true);
dynamicChooser.removeActionListener(listener);
return dynamicChooser.getSelectedFiles();
}
}
Which you can call simply using something like...
File[] files = MyFileChooser.INSTANCE_FILES.showOpenDialog(null, "Open");
"I've mentioned I wish to have JLabels between chooser,"
I had thought that laying out comments was just a matter of reading any one of the thousands of examples which are available, apparently I was mistaken
So, a simple update to the frameSetup
method solves that issue...
public void frameSetup(Container parent) {
// jframe setup code
parent.setLayout(new BorderLayout());
parent.add(new JLabel("I'm on top"), BorderLayout.NORTH);
parent.add(this.dynamicChooser);
parent.add(new JLabel("I'm on bottom"), BorderLayout.SOUTH);
}
Have a look at How to Use BorderLayout for more details
To make sure it works correctly, I updated the showOpenDialog
method to use
frameSetup(dialog.getContentPane());
instead of just passing the instance of the JDialog
, this ensures that we're effecting the correct container
Upvotes: 3