如何在 Java 中的自定义 JFrame 中附加 JFileChooser 按钮的处理程序
How to attach handler for JFileChooser buttons inside custom JFrame in Java
我有一个名为 MyFileChooser 的单例模式 class,如果 JFileChooser 是 FILES_ONLY
或 DIRECTORIES_ONLY
,它会根据构造函数参数进行调整。
我希望在 JFrame 中包含 JFileChooser,这样我就可以在 JFileChooser 框架的上方和下方添加附加信息,因此结构如下所示:
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);
}
问题是我不知道如何为 JFileChooser 的 "Close" 和 "Open" 按钮附加处理程序。我唯一发现的是:
public void handleSelectedFiles() {
int returnVal = this.dynamicChooser.showDialog(this.frame, "Open");
if (returnVal == JFileChooser.APPROVE_OPTION) {
File[] files = this.dynamicChooser.getSelectedFiles();
// do something
}
}
但是,如果调用此方法,即使没有来自所需结构的 JFrame 包装和 JLabel,它也会打开这两个实例。
所以我的问题是如何从 JFileChooser 获取 "Open" 和 "Close" 的按钮以附加处理程序( 实例不同 )或如何处理其他选择的文件方式。
你的第一个问题就在这里
int returnVal = this.dynamicChooser.showDialog(this.frame, "Open");
它调用底层 JFileChooser
的 showDialog
方法,因此它正在构建自己的 window,忽略你的
更好的解决方案是按需创建 JDialog
并将其用于包含文件选择器和其他控件
有点像...
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();
}
}
目的是模仿JFileChooser
中showDialog
的动作。在此示例中,我隐藏了“普通”控制按钮,因为我假设您将提供自己的按钮,通过它您可以更改 return 文件
现在,如果您仍想使用标准按钮控件,可以将 ActionListener
附加到 JFileChooser
dynamicChooser.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
//...
}
});
当我测试时,取消按钮 return CancelSelection
和选择按钮 return ApproveSelection
现在,因为我的示例使用动态对话框,您可能需要创建一个可以控制对话框的动态 ActionListener
,因为您不想继续添加 ActionListener
到FileChooser
不删除它们,比如...
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();
}
举个例子
观察
因为我知道如果我不这样做,有人会踢我来遏制...
Java 中的 Sington 是棘手的事情,关于这个主题有无数的线程,但是,人们普遍认为(现在)最好的方法是使用 enum
,它解决了所有问题旧
的同步问题
因此,您可以考虑使用类似...
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();
}
}
您可以简单地使用类似...
File[] files = MyFileChooser.INSTANCE_FILES.showOpenDialog(null, "Open");
“我已经提到我希望在选择器之间使用 JLabel,”
我原以为布置评论只是阅读数以千计可用示例中的任何一个的问题,显然我错了
因此,对 frameSetup
方法进行简单更新即可解决该问题...
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);
}
查看 How to Use BorderLayout 了解更多详情
为确保其正常工作,我更新了 showOpenDialog
方法以使用
frameSetup(dialog.getContentPane());
而不是仅仅传递 JDialog
的实例,这确保我们正在影响正确的容器
我有一个名为 MyFileChooser 的单例模式 class,如果 JFileChooser 是 FILES_ONLY
或 DIRECTORIES_ONLY
,它会根据构造函数参数进行调整。
我希望在 JFrame 中包含 JFileChooser,这样我就可以在 JFileChooser 框架的上方和下方添加附加信息,因此结构如下所示:
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);
}
问题是我不知道如何为 JFileChooser 的 "Close" 和 "Open" 按钮附加处理程序。我唯一发现的是:
public void handleSelectedFiles() {
int returnVal = this.dynamicChooser.showDialog(this.frame, "Open");
if (returnVal == JFileChooser.APPROVE_OPTION) {
File[] files = this.dynamicChooser.getSelectedFiles();
// do something
}
}
但是,如果调用此方法,即使没有来自所需结构的 JFrame 包装和 JLabel,它也会打开这两个实例。 所以我的问题是如何从 JFileChooser 获取 "Open" 和 "Close" 的按钮以附加处理程序( 实例不同 )或如何处理其他选择的文件方式。
你的第一个问题就在这里
int returnVal = this.dynamicChooser.showDialog(this.frame, "Open");
它调用底层 JFileChooser
的 showDialog
方法,因此它正在构建自己的 window,忽略你的
更好的解决方案是按需创建 JDialog
并将其用于包含文件选择器和其他控件
有点像...
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();
}
}
目的是模仿JFileChooser
中showDialog
的动作。在此示例中,我隐藏了“普通”控制按钮,因为我假设您将提供自己的按钮,通过它您可以更改 return 文件
现在,如果您仍想使用标准按钮控件,可以将 ActionListener
附加到 JFileChooser
dynamicChooser.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
//...
}
});
当我测试时,取消按钮 return CancelSelection
和选择按钮 return ApproveSelection
现在,因为我的示例使用动态对话框,您可能需要创建一个可以控制对话框的动态 ActionListener
,因为您不想继续添加 ActionListener
到FileChooser
不删除它们,比如...
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();
}
举个例子
观察
因为我知道如果我不这样做,有人会踢我来遏制...
Java 中的 Sington 是棘手的事情,关于这个主题有无数的线程,但是,人们普遍认为(现在)最好的方法是使用 enum
,它解决了所有问题旧
因此,您可以考虑使用类似...
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();
}
}
您可以简单地使用类似...
File[] files = MyFileChooser.INSTANCE_FILES.showOpenDialog(null, "Open");
“我已经提到我希望在选择器之间使用 JLabel,”
我原以为布置评论只是阅读数以千计可用示例中的任何一个的问题,显然我错了
因此,对 frameSetup
方法进行简单更新即可解决该问题...
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);
}
查看 How to Use BorderLayout 了解更多详情
为确保其正常工作,我更新了 showOpenDialog
方法以使用
frameSetup(dialog.getContentPane());
而不是仅仅传递 JDialog
的实例,这确保我们正在影响正确的容器