将 JFileChooser 与 Swing GUI 类和侦听器一起使用
Posted
技术标签:
【中文标题】将 JFileChooser 与 Swing GUI 类和侦听器一起使用【英文标题】:Using a JFileChooser with Swing GUI classes and listeners 【发布时间】:2013-03-21 15:39:25 【问题描述】:这是我当前的菜单:
public class DrawPolygons
public static void main (String[] args) throws FileNotFoundException
/**
* Menu - file reader option
*/
JMenuBar menuBar;
JMenu menu;
JMenuItem menuItem;
// Create the menu bar.
menuBar = new JMenuBar();
// Build the first menu.
menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menu.getAccessibleContext().setAccessibleDescription("I have items");
menuBar.add(menu);
// a group of JMenuItems
menuItem = new JMenuItem("Load",KeyEvent.VK_T);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK));
menuItem.getAccessibleContext().setAccessibleDescription("Load your old polygons");
menu.add(menuItem);
menuItem = new JMenuItem("Save",KeyEvent.VK_U);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, ActionEvent.ALT_MASK));
menuItem.getAccessibleContext().setAccessibleDescription("Save the contents of your polygons");
menu.add(menuItem);
// attaching the menu to the frame
JFrame frame = new JFrame("Draw polygons");
frame.setJMenuBar(menuBar);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new DrawingPanel());
frame.pack();
frame.setVisible(true);
它有Load
和Save
两个选项。
现在,我如何将JFileChooser
附加到actionPerformed
方法,这里:
/**
* Main class
* @author X2
*
*/
class DrawingPanel extends JPanel implements MouseListener, MouseMotionListener ,KeyListener
// code
// code
// and more code
static DrawingPanel app ;
private static final Dimension MIN_DIM = new Dimension(300, 300);
private static final Dimension PREF_DIM = new Dimension(500, 500);
public Dimension getMinimumSize() return MIN_DIM;
public Dimension getPreferredSize() return PREF_DIM;
JMenuItem open, save;
JTextArea textArea ;
JFileChooser chooser ;
FileInputStream fis ;
BufferedReader br ;
FileOutputStream fos ;
BufferedWriter bwriter ;
public void actionPerformed( ActionEvent event )
Object obj = event.getSource() ;
chooser = new JFileChooser() ;
if ( chooser.showOpenDialog( app ) == JFileChooser.APPROVE_OPTION )
if ( obj == open )
try
fis = new FileInputStream(
chooser.getSelectedFile() ) ;
br = new BufferedReader(
new InputStreamReader( fis ) ) ;
String read ;
StringBuffer text = new StringBuffer() ;
while( ( read = br.readLine() ) != null )
text.append( read ).append( "\n" ) ;
textArea.setText( text.toString() ) ;
catch( IOException e )
JOptionPane.showMessageDialog( this , "Error in File Operation"
,"Error in File Operation" ,JOptionPane.INFORMATION_MESSAGE) ;
/**
* The constructor
*/
DrawingPanel()
super();
addMouseListener(this);
addMouseMotionListener(this);
addKeyListener(this);
setFocusable(true);
requestFocusInWindow();
// a lot of code more
// and more
// and more
我在 main
中创建的 menu
和 Jpanel
的初始代码?
问候
------------
编辑:
“新”代码:
public class DrawPolygons
public static void main (String[] args) throws FileNotFoundException
// attaching the menu to the frame
JFrame frame = new JFrame("Draw polygons");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// JMenuBar
// Create the menu and JmenuBar
JMenuBar menuBar = new JMenuBar();
// Build the first menu.
JMenu menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menu.getAccessibleContext().setAccessibleDescription("I have items");
menuBar.add(menu);
// menu option - load
// create the load option
final JMenuItem loadItem = new JMenuItem("Load",KeyEvent.VK_T);
// add the shortcut
loadItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK));
// short description
loadItem.getAccessibleContext().setAccessibleDescription("Load your old polygons");
// JFileChooser with filter
JFileChooser fileChooser = new JFileChooser(".");
// apply the filter to file chooser
FileNameExtensionFilter filter = new FileNameExtensionFilter("scn files (*.scn)", "scn");
fileChooser.setFileFilter(filter);
fileChooser.setControlButtonsAreShown(false);
frame.add(fileChooser, BorderLayout.CENTER);
final JLabel directoryLabel = new JLabel(" ");
directoryLabel.setFont(new Font("Serif", Font.BOLD | Font.ITALIC, 36));
final JLabel filenameLabel = new JLabel(" ");
filenameLabel.setFont(new Font("Serif", Font.BOLD | Font.ITALIC, 36));
// add listener to LOAD
loadItem.addActionListener(
new ActionListener()
public void actionPerformed(ActionEvent actionEvent)
JFileChooser theFileChooser = new JFileChooser();
String command = actionEvent.getActionCommand();
if (command.equals(JFileChooser.APPROVE_SELECTION))
File selectedFile = theFileChooser.getSelectedFile();
directoryLabel.setText(selectedFile.getParent());
filenameLabel.setText(selectedFile.getName());
else if (command.equals(JFileChooser.CANCEL_SELECTION))
directoryLabel.setText(" ");
filenameLabel.setText(" ");
// end listener
); // end listener to loadItem
menu.add(loadItem);
// now SAVE
// create the option for save
JMenuItem saveItem = new JMenuItem("Save",KeyEvent.VK_U);
// key shortcut for save
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, ActionEvent.ALT_MASK));
saveItem.getAccessibleContext().setAccessibleDescription("Save the contents of your polygons");
// add the save to the menu
menu.add(saveItem);
frame.setJMenuBar(menuBar);
frame.setContentPane(new DrawingPanel());
frame.pack();
frame.setVisible(true);
问题是,现在,当我在File
下点击Load
时,什么都没有发生。为什么 ?
我添加了监听器,但什么都没有。
【问题讨论】:
为什么要在 JPanel 中添加 ActionListener 而不是 menuItem(load)? 【参考方案1】:我建议使用 Action(s) 在那里使用。在每个动作上,您都有一些特定的动作侦听器,如果您愿意,可以将您的面板设置为侦听器:
Action Explained
【讨论】:
我添加了动作,就像你建议的那样,但现在没有任何东西听Load
,即使我添加了监听器。你能看看编辑后的帖子吗?【参考方案2】:
您的问题的快速解决方法是提供一个处理程序,以便您可以附加 ActionListener。您在main()
中创建了JMenus,但在DrawingPanel
中看不到它们。完成此操作的一种廉价方法是将 JMenuItems 传递到您的 DrawingPanel 构造函数中。将构造函数修改为:
DrawingPanel(JMenuItem save, JMenuItem open)
// the stuff you already got
this.save = save;
this.open = open;
save.addActionListener(this);
open.addActionListener(this);
然后您将它们传递到 main
中的 DrawingPanel:
JMenuItem loadMenuItem = new JMenuItem("Load");
JMenuItem saveMenuItem = new JMenuItem("Save");
...
frame.getContentPane(new DrawingPanel(saveMenuItem, loadMenuItem));
从 Java 风格的角度来看,尚不清楚 DrawingPanel
是否是处理保存和加载操作的最佳位置。正如其他人所提到的,为每个 JMenuItem 创建(单独的)Action 通常是一种更好的模式。在您的情况下,您可能能够在 DrawingPanel 中提供其他访问器或帮助器方法,这些方法将为保存器/加载器工作人员提供执行操作所需的信息。
编辑:(以解决 OP 的“新代码”编辑)
我认为“新代码”的问题在于您在 actionPerformed
方法中创建了 new
JFileChooser,而不是使用您之前创建并添加到框架中的现有代码。如果您创建第一个final
,那么您可以在actionPerformed
方法中使用相同的JFileChooser。
【讨论】:
【参考方案3】:作为一般规则,您不应该让您的 GUI 类(例如扩展 JPanel 的类)实现任何侦听器接口,实际上您应该争取相反的结果——分离程序的控制功能(监听器等)从程序的视图功能(GUI)。因此,我对您的问题“如何将 JFileChooser 附加到 actionPerformed 方法...[附加到扩展 JPanel 的 DrawingPanel 类] 的问题的回答是努力不这样做。
相反,让您的视图类实现允许控件类更轻松地与它们交互的接口。
编辑 1:您的新代码永远不会显示 JFileChooser 对话框。您需要显示打开的对话框:
// first make sure that you've declared the JFrame frame as final
int result = theFileChooser.showOpenDialog(frame);
if (result == JFileChooser.APPROVE_OPTION)
// ... code goes here
编辑 2
Swing 模型-视图-控制示例:
例如,这里有一个 MVC 或 Model-View-Control 实现,它显示了视图、模型和控件。这一切都非常简单,它目前所做的只是打开一个文本文件并将其显示在一个 JTextField 中,就是这样,它试图从视图中分离出控制功能。
MvcMain 类
import javax.swing.SwingUtilities;
public class MvcMain
private static void createAndShowGui()
MvcView view = new ShowTextView("Show Text");
MvcModel model = new ShowTextModel();
ShowTextControl control = new ShowTextControl(view, model);
control.showView(true);
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
public void run()
createAndShowGui();
);
MvcModel 接口
import java.beans.PropertyChangeListener;
public interface MvcModel
static final String TEXT = "text";
static final String STATUS = "STATUS";
String getText();
String getStatus();
void setText(String text);
void setStatus(String text);
void addPropertyChangeListener(PropertyChangeListener listener);
void removePropertyChangeListener(PropertyChangeListener listener);
MvcView 界面
import java.awt.Window;
import javax.swing.Action;
public interface MvcView
void setVisible(boolean visible);
void setFileAction(Action fileAction);
void setOpenFileAction(Action openFileAction);
void setSaveToFileAction(Action saveToFileAction);
void setExitAction(Action exitAction);
void setStatusText(String string);
String getTextAreaText();
void setTextAreaText(String text);
Window getTopWindow();
ShowTextView 类
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Window;
import javax.swing.*;
public class ShowTextView implements MvcView
private JFrame frame = new JFrame();
private JMenuBar menuBar = new JMenuBar();
private JMenu fileMenu = new JMenu();
private StatusBar statusBar = new StatusBar();
private ViewDisplayText displayText = new ViewDisplayText();
public ShowTextView(String title)
menuBar.add(fileMenu);
frame.setTitle(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(displayText.getMainComponent(), BorderLayout.CENTER);
frame.getContentPane().add(statusBar.getComponent(), BorderLayout.PAGE_END);
frame.setJMenuBar(menuBar);
@Override
public void setVisible(boolean visible)
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
@Override
public void setOpenFileAction(Action action)
displayText.setOpenFileButtonAction(action);
fileMenu.add(new JMenuItem(action));
@Override
public void setSaveToFileAction(Action action)
displayText.setSaveToFileAction(action);
fileMenu.add(new JMenuItem(action));
@Override
public void setExitAction(Action exitAction)
displayText.setExitAction(exitAction);
fileMenu.add(new JMenuItem(exitAction));
@Override
public void setFileAction(Action fileAction)
fileMenu.setAction(fileAction);
@Override
public String getTextAreaText()
return displayText.getTextAreaText();
@Override
public void setTextAreaText(String text)
displayText.setTextAreaText(text);
@Override
public Window getTopWindow()
return frame;
@Override
public void setStatusText(String text)
statusBar.setText(text);
class ViewDisplayText
private static final int TA_ROWS = 30;
private static final int TA_COLS = 50;
private static final int GAP = 2;
private JPanel mainPanel = new JPanel();
private JButton openFileButton = new JButton();
private JButton saveToFileButton = new JButton();
private JButton exitButton = new JButton();
private JTextArea textArea = new JTextArea(TA_ROWS, TA_COLS);
public ViewDisplayText()
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
buttonPanel.add(openFileButton);
buttonPanel.add(saveToFileButton);
buttonPanel.add(exitButton);
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.setLayout(new BorderLayout());
mainPanel.add(new JScrollPane(textArea), BorderLayout.CENTER);
mainPanel.add(buttonPanel, BorderLayout.PAGE_END);
public void setExitAction(Action exitAction)
exitButton.setAction(exitAction);
public JComponent getMainComponent()
return mainPanel;
public void setOpenFileButtonAction(Action action)
openFileButton.setAction(action);
public void setSaveToFileAction(Action action)
saveToFileButton.setAction(action);
public String getTextAreaText()
return textArea.getText();
public void setTextAreaText(String text)
textArea.setText(text);
class StatusBar
private static final String STATUS = "Status: ";
private JLabel label = new JLabel(STATUS);
public StatusBar()
label.setBorder(BorderFactory.createLineBorder(Color.black));
public JComponent getComponent()
return label;
public void setText(String text)
label.setText(STATUS + text);
ShowTextModel 类
import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
public class ShowTextModel implements MvcModel
private String text;
private String status;
private SwingPropertyChangeSupport propChangeSupport =
new SwingPropertyChangeSupport(this);
@Override
public String getText()
return text;
@Override
public void setText(String text)
String newValue = text;
String oldValue = this.text;
this.text = newValue;
propChangeSupport.firePropertyChange(TEXT, oldValue, newValue);
@Override
public void setStatus(String status)
String newValue = status;
String oldValue = this.status;
this.status = newValue;
propChangeSupport.firePropertyChange(STATUS, oldValue, newValue);
@Override
public void addPropertyChangeListener(PropertyChangeListener listener)
propChangeSupport.addPropertyChangeListener(listener);
@Override
public void removePropertyChangeListener(PropertyChangeListener listener)
propChangeSupport.removePropertyChangeListener(listener);
@Override
public String getStatus()
return status;
ShowTextControl 类
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class ShowTextControl
private MvcView view;
private MvcModel model;
public ShowTextControl(MvcView view, MvcModel model)
this.view = view;
this.model = model;
view.setFileAction(new FileAction("File", KeyEvent.VK_F));
view.setOpenFileAction(new OpenFileAction(view, model, "Open File",
KeyEvent.VK_O));
view.setSaveToFileAction(new SaveToFileAction(view, model,
"Save to File", KeyEvent.VK_S));
view.setExitAction(new ExitAction(view, model, "Exit", KeyEvent.VK_X));
model.addPropertyChangeListener(new ModelListener(view, model));
public void showView(boolean visible)
view.setVisible(visible);
@SuppressWarnings("serial")
class OpenFileAction extends AbstractAction
private MvcView view;
private MvcModel model;
public OpenFileAction(MvcView view, MvcModel model, String name, int keyCode)
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.view = view;
this.model = model;
@Override
public void actionPerformed(ActionEvent evt)
JFileChooser fileChooser = new JFileChooser();
fileChooser.setMultiSelectionEnabled(false);
int result = fileChooser.showOpenDialog(view.getTopWindow());
if (result == JFileChooser.APPROVE_OPTION)
File file = fileChooser.getSelectedFile();
if (file.exists())
if (file.getName().endsWith(".txt"))
model.setStatus("Opening file \"" + file.getName() + "\"");
OpenFileWorker openFileWorker = new OpenFileWorker(file);
openFileWorker.addPropertyChangeListener(
new OpenFileWorkerListener(model));
openFileWorker.execute();
else
model.setStatus("File \"" + file.getName()
+ "\" is not a text file");
else
model.setStatus("File \"" + file.getName() + "\" does not exist");
class OpenFileWorker extends SwingWorker<String, Void>
private File file;
public OpenFileWorker(File file)
this.file = file;
public File getFile()
return file;
@Override
protected String doInBackground() throws Exception
StringBuilder stringBuilder = new StringBuilder();
Scanner scan = null;
try
scan = new Scanner(file);
while (scan.hasNextLine())
stringBuilder.append(scan.nextLine() + "\n");
catch (FileNotFoundException e)
e.printStackTrace();
finally
if (scan != null)
scan.close();
return stringBuilder.toString();
class OpenFileWorkerListener implements PropertyChangeListener
private MvcModel model;
public OpenFileWorkerListener(MvcModel model)
this.model = model;
@Override
public void propertyChange(PropertyChangeEvent evt)
if (SwingWorker.StateValue.DONE == evt.getNewValue())
OpenFileWorker openFileWorker = (OpenFileWorker) evt.getSource();
try
String text = openFileWorker.get();
model.setText(text);
model.setStatus("File \"" + openFileWorker.getFile().getName() + "\" opened");
catch (InterruptedException e)
e.printStackTrace();
catch (ExecutionException e)
e.printStackTrace();
@SuppressWarnings("serial")
class FileAction extends AbstractAction
public FileAction(String name, int keyCode)
super(name);
putValue(MNEMONIC_KEY, keyCode);
@Override
public void actionPerformed(ActionEvent arg0)
// pretty much empty
@SuppressWarnings("serial")
class SaveToFileAction extends AbstractAction
private MvcView view;
private MvcModel model;
public SaveToFileAction(MvcView view, MvcModel model, String name,
int keyCode)
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.view = view;
this.model = model;
@Override
public void actionPerformed(ActionEvent e)
// TODO finish!
@SuppressWarnings("serial")
class ExitAction extends AbstractAction
private MvcView view;
// private MvcModel model; // TODO: may use this later
public ExitAction(MvcView view, MvcModel model, String name, int keyCode)
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.view = view;
// this.model = model; // TODO: may use this later
@Override
public void actionPerformed(ActionEvent e)
view.getTopWindow().dispose();
class ModelListener implements PropertyChangeListener
private MvcView view;
private MvcModel model;
public ModelListener(MvcView view, MvcModel model)
this.view = view;
this.model = model;
@Override
public void propertyChange(PropertyChangeEvent pcEvt)
if (MvcModel.TEXT.equals(pcEvt.getPropertyName()))
view.setTextAreaText(model.getText());
else if (MvcModel.STATUS.equals(pcEvt.getPropertyName()))
view.setStatusText(model.getStatus());
在本例中,为了简洁起见,我将 java 类合并到一个文件中,但在应用程序中,它们将位于各自的文件中,但都共享同一个包。请注意,虽然这对于这个简单的应用程序来说可能是“过度杀伤”,但我已经在几个非常大的 Swing 应用程序中使用了这种结构并取得了很好的成功。当我需要在创建几个月后调试或增强程序时,对我的主要好处是,因为这种关注点、信息和行为的分离使我更容易对程序的一部分进行更改,而不会冒犯或扰乱程序的另一部分。程序。
此外,这些界面的原因是您可以创建新的或不同的 GUI,它们看起来不同,但可以以相同的方式响应。我还经常使用它们来帮助创建模拟类,使我能够更好地单独测试我的模块。
【讨论】:
【参考方案4】:详细说明 Kitesurfer 所说的我会使用 Action,因为大多数情况下我有工具栏按钮或其他组件执行与菜单项相同的操作。为了避免类中某处(或任何我能够从当前类访问它的任何地方)中的重复或不必要的代码,我创建了一个 Action
字段,如果需要,我可以重用它,或者如果我决定重构我的代码,我可以移动它。这是一个例子。
JMenuItem miLoad = new JMenuItem(actionLoad);
Action actionLoad = new AbstractAction("Load")
public void actionPerformed(ActionEvent e)
//your code to load the file goes here like a normal ActionListener
;
一定要查看API,看看哪些参数可以传递给AbstractAction
类,我用了String
所以JMenuItem
会显示字符串,你也可以设置Icon
,我不'不记得所有的构造函数,所以值得一看。哦,将JMenuItems
传递给DrawingPanel
类的构造函数不一定是个坏主意,但如果它继承自JPanel
,我不相信您可以将菜单栏添加到JPanel
,所以让确保它也被添加到您的JFrame
。希望对您有所帮助。
【讨论】:
以上是关于将 JFileChooser 与 Swing GUI 类和侦听器一起使用的主要内容,如果未能解决你的问题,请参考以下文章
如何从 JFileChooser(JAVA Swing) 中禁用文件操作、文件选择和过滤面板?
打开JFileChooser并返回所选文件的Swing ActionListener