使用带有Swing GUI类和侦听器的JFileChooser

这是我目前的菜单:

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); } } 

它有两个选项用于LoadSave在这里输入图像描述

现在,我如何将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 } 

menuJpanel的初始代码,我在main创build?

问候

————————

编辑:

“新”代码:

 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 ,什么也没有发生。 为什么?

我添加了监听器,但没有。

作为一般规则,你不应该让你的GUI类(比如扩展JPanel的类)实现任何监听器接口,实际上你应该努力做到相反 – 把程序的控制function(监听器和像)从程序的视图function(GUI)。 所以我回答你的问题:“我怎样才能将JFileChooser附加到actionPerformed方法… [对我的DrawingPanel类扩展JPanel],是努力不要这样做。

而是让你的视图类实现接口,使控制类更容易与他们交互。

编辑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 Model-View-Control示例:

例如,下面是一个MVC或模型 – 视图 – 控制实现,显示视图,模型和控件。 这是非常简单的,目前所做的只是打开一个文本文件并将其显示在JTextField中,就是这样,它试图从视图中分离出控制function。

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应用程序,取得了很好的成功。 对于我来说,主要好处是在创build后几个月内需要debugging或增强程序时,因为这种关注,信息和行为hading的分离使我更容易在程序的某个部分进行更改,而不会冒犯或破坏另一部分该程序。

此外,接口的原因是,您可以创build新的或不同的GUI,但可以以相同的方式进行响应。 我也经常使用它们来帮助创build模拟类,使我能够更好地testing我的模块。

我会build议使用Action(s)在那里使用。 在每个动作中你都有一些特定的actionlistener,如果你愿意,可以将你的面板设置为一个监听器:

行动解释

详细说明什么Kitesurfer说我会使用一个动作,因为大多数情况下,我有工具栏button或其他组件执行菜单项相同的行动。 为了避免重复或不必要的代码在类的任何地方(或任何我可以从当前类访问它)我创build一个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会显示string,也可以设置Icon ,我不记得所有的构造函数,所以这是值得的看看。 哦,并将JMenuItems传递给DrawingPanel类的构造函数不一定是一个坏主意,但是如果它inheritance自JPanel我不相信你可以添加一个菜单栏到JPanel所以确保它也被添加到你的JFrame 。 希望有所帮助。

您的问题的快速解决scheme是提供一个处理程序,以便您可以附加ActionListener。 你在main()创build了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); } 

然后你将它们传入你的DrawingPanel中:

 JMenuItem loadMenuItem = new JMenuItem("Load"); JMenuItem saveMenuItem = new JMenuItem("Save"); ... frame.getContentPane(new DrawingPanel(saveMenuItem, loadMenuItem)); 

从Java风格的angular度来看, DrawingPanel是否是处理保存和加载操作的最佳位置还不清楚。 正如其他人所提到的,为每个JMenuItem创build(单独的)操作通常是一个更好的模式。 在你的情况下,你可以在DrawingPanel中提供其他的访问器或者辅助方法,这样可以为保存者/加载者提供他们需要的信息。


编辑:(解决OP的“新代码”编辑)

我认为“新代码”的问题在于,您在actionPerformed方法中创build了一个new JFileChooser,而不是使用之前创build的并添加到框架中的现有JFileChooser。 如果你做了第一个final那么你可以在actionPerformed方法中使用相同的JFileChooser。