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

时间:2013-03-31 10:47:46

标签: java swing model-view-controller actionlistener 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有两个选项。 enter image description here

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

}

我在menu创建了Jpanelmain的初始代码?

此致

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

编辑:

“新”代码:

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

}

问题是,现在,当我在LoadFile时,没有任何事情发生。为什么?

我添加了听众,但没有。

4 个答案:

答案 0 :(得分:16)

作为一般规则,你不应该有你的GUI类,比如扩展JPanel的类,实现任何监听器接口,实际上你应该争取恰恰相反 - 分离程序的控制功能(从程序的视图功能(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模型 - 视图 - 控制示例:

例如,这是一个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,但可以以相同的方式响应。我也经常使用它们来帮助创建模拟类,使我能够更好地单独测试我的模块。

答案 1 :(得分:1)

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

Action Explained

答案 2 :(得分:1)

您的问题的快速解决方法是提供一个处理程序,以便您可以附加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创建(单独)Actions通常是一种更好的模式。在您的情况下,您可能能够在DrawingPanel中提供其他访问者或帮助程序方法,这些方法将为保护程序/加载程序工作人员提供他们执行操作所需的信息。


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

我认为“新代码”的问题在于您在new方法中创建了actionPerformed JFileChooser,而没有使用您之前创建并添加到框架中的现有版本。如果您创建第一个final,则可以在actionPerformed方法中使用相同的JFileChooser。

答案 3 :(得分:1)

详细说明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显示字符串,您也可以设置{ {1}},我不记得所有的构造函数,所以值得一看。哦,并将Icon传递给JMenuItems类的构造函数不一定是个坏主意,但如果它继承自DrawingPanel我不相信你可以添加菜单栏到一个JPanel,所以请确保它也会添加到您的JPanel。希望有所帮助。