Usando un JFileChooser con clases y oyentes de GUI Swing

Este es mi menú actual:

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

Tiene dos opciones para Load y Save . enter image description here

Ahora, ¿cómo puedo adjuntar JFileChooser al método actionPerformed , aquí?

 /** * 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 } 

Con el código inicial del menu y el Jpanel , ¿qué creé en main ?

Saludos

————————

EDITAR:

El “nuevo” código:

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

El problema es que ahora, cuando pulso Load File , no ocurre nada. Por qué ?

Agregué el oyente, pero nada.

Como regla general, no debe tener sus clases de GUI, como la clase que extiende JPanel, implementar interfaces de escucha y, de hecho, debe esforzarse por todo lo contrario: separar las funciones de control del progtwig (los oyentes y el me gusta) de las funciones de vista del progtwig (la GUI). Así que mi respuesta a su pregunta de “cómo puedo adjuntar el JFileChooser al método actionPerformed … [a mi clase DrawingPanel que extiende JPanel], es esforzarme para no hacer esto.

En cambio, las clases de vista deben implementar interfaces que permitan que las clases de control interactúen más fácilmente con ellas.

Edición 1 : su nuevo código nunca muestra el cuadro de diálogo JFileChooser. Necesitas mostrar el diálogo abierto:

 // 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 } 

Editar 2

Ejemplo de Swing Model-View-Control:

Por ejemplo, aquí hay una implementación MVC o Model-View-Control que muestra la vista, el modelo y el control. Todo esto es muy simplista, y todo lo que hace en este momento es abrir un archivo de texto y mostrarlo en un JTextField, eso es todo, e intenta separar las funciones de control de la vista.

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

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

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

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

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

Clase 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 { 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()); } } } 

En este ejemplo, he combinado clases de Java en un archivo para abreviar, pero en la aplicación, estarían en sus propios archivos, pero todos compartirían el mismo paquete. Tenga en cuenta que si bien esto puede ser “exagerado” para esta sencilla aplicación, he utilizado este tipo de estructura con varias aplicaciones Swing muy grandes con buen éxito. El principal beneficio para mí viene cuando necesito depurar o mejorar un progtwig meses después de la creación, ya que esta separación de preocupaciones e información y comportamiento hace que sea mucho más fácil para mí hacer cambios en una parte del progtwig sin ofender o molestar a otra parte de el progtwig.

Además, la razón para las interfaces es para que pueda crear nuevas o diferentes GUI que se vean de manera diferente, pero que pueden responder de la misma manera. También los he usado con frecuencia para ayudar a crear clases simuladas que me permiten probar mejor mis módulos de forma aislada.

Yo recomendaría usar Acción (s) para usar allí. En cada acción tiene un oyente de acción específico, configure su panel como un oyente si desea hacerlo:

Acción explicada

Para dar más detalles sobre lo que dijo Kitesurfer, usaría una Acción porque la mayoría de las veces tengo botones de la barra de herramientas u otros componentes que realizan las mismas acciones que los elementos del menú. Para evitar el código duplicado o innecesario en algún lugar de la clase (o en cualquier lugar donde pueda acceder a él desde la clase actual) creo un campo Action que puedo volver a utilizar si es necesario o moverme si decido refactorizar mi código. Aquí hay un ejemplo.

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

Definitivamente eche un vistazo a la API para ver qué parámetros se pueden pasar a la clase AbstractAction , utilicé una String para que JMenuItem muestre la cadena, también puede establecer el Icon , no recuerdo todos los constructores por lo que valdría la pena echando un vistazo. Ah, y pasar JMenuItems al constructor de la clase DrawingPanel no es necesariamente una mala idea, pero si hereda de JPanel , no creo que puedas agregar una barra de menú a un JPanel así que asegúrate de que también se agregue a tu JFrame . Espero que ayude.

La solución rápida para su problema es proporcionar un controlador para que pueda adjuntar el ActionListener. Usted hace los JMenus en main() , pero no tiene visibilidad para ellos en su DrawingPanel . Una manera económica de hacer esto sería pasar JMenuItems en su constructor DrawingPanel. Modifique el constructor a algo como:

 DrawingPanel(JMenuItem save, JMenuItem open) { // the stuff you already got this.save = save; this.open = open; save.addActionListener(this); open.addActionListener(this); } 

Luego los pasarás a tu DrawingPanel en main :

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

Desde una perspectiva de estilo Java, no está claro si DrawingPanel es el mejor lugar para manejar las acciones de guardar y cargar. Como han mencionado otros, la creación de Acciones (separadas) para cada JMenuItem a menudo es un mejor patrón. En su caso, es posible que pueda proporcionar otros métodos de acceso o ayuda dentro de DrawingPanel que darían a los trabajadores de ahorro / cargadores la información que necesitarían para realizar su Acción.


Editar: (para abordar el “código nuevo” del OP) Editar

Creo que el problema con el “código nuevo” es que está creando un new JFileChooser en el método actionPerformed y no está utilizando el existente que creó anteriormente y lo agregó al marco. Si hace la primera final , puede usar el mismo JFileChooser en el método actionPerformed .

Intereting Posts