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

    


它有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


我在 main 中创建的 menuJpanel 的初始代码?

问候

------------

编辑:

“新”代码:

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 类和侦听器一起使用的主要内容,如果未能解决你的问题,请参考以下文章

Swing-JFileChooser的使用

如何从 JFileChooser(JAVA Swing) 中禁用文件操作、文件选择和过滤面板?

JFileChooser 中文API

打开JFileChooser并返回所选文件的Swing ActionListener

将 JFileChooser 添加到 Eclipse Window Builder

《Java Swing》第8节:选择器