Para lograr este objetivo existen muchas maneras (como toda cosa en la vida) de lograrlo, pero como mi conocimiento es muy limitado no conozco todas esas maneras x). asi que solamente alcanzaremos ese objetivo mediante 3 formas:
- Patron Singleton
- Utilizando HashMap y una clase de utilidad
- Haciendo modal el JinternalFrame
A mi parecer la mas eficiente y eficaz (Nose cual es la diferencia entre esas dos palabras pero suena como que si en verdad se lo que estoy hablando xD) de las opciones es la #2. Pero mi intencion no es obligar a nadie a usar simplemente las opciones que a mi me gustan, sino mas bien, ampliar el conocimiento de cómo podemos alcanzar el mismo objetivo mediante diferentes medios.
La estructura de estos ejercicios (para mayor claridad) sera: un solo proyecto, el cual tendra 3 Opciones en la barra de menu, en cada opcion se desarrollara cada una de las formas.
mainFrame.java
package Clases; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyVetoException; import java.lang.reflect.Constructor; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.ImageIcon; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; // author McCubo public class mainFrame extends JFrame{ private JDesktopPane desktopPane; private JMenuBar menuBar; private JMenu menuSingleton; private JMenu menuHashMap; private JMenu menuModal; private JMenuItem optionSingleton; private JMenuItem optionHashMap; private JMenuItem optionModal; public mainFrame() { super("SingletonPack"); initComponents(); initMenuListeners(); } private void initComponents(){ setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(new Dimension(800, 500)); setLocationRelativeTo(null); setBackground(Color.WHITE); setLayout(new BorderLayout()); desktopPane = new JDesktopPane(); // setDragMode sirve para indicarle en que forma se visualizaran los JInternalFrames dentro del Componente // OUTLINE_DRAG_MODE: solo se visualiza el borde de los JInternalFrame desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); menuBar = new JMenuBar(); menuSingleton = new JMenu("Singleton"); menuHashMap = new JMenu("HashMap"); menuModal = new JMenu("Modal"); //Creando los Item de los Menu optionSingleton = new JMenuItem("Abrir", new ImageIcon("recursos/gamepad.png")); optionHashMap = new JMenuItem("Abrir", new ImageIcon("recursos/img.jpg")); optionModal = new JMenuItem("Abrir", new ImageIcon("recursos/default.png")); // añadimos esos Items a su correspondiente Menu menuSingleton.add(optionSingleton); menuHashMap.add(optionHashMap); menuModal.add(optionModal); // añadimos los menus al MenuBar menuBar.add(menuSingleton); menuBar.add(menuHashMap); menuBar.add(menuModal); // El JMenuBar y JDesktopPane son agregados al JFrame this.add(menuBar, BorderLayout.NORTH); this.add(desktopPane, BorderLayout.CENTER); setVisible(true); } private void initMenuListeners(){ optionSingleton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { // Obtenemos una instancia (Nueva o la que ya tenemos) de la clase OpcionSingleton OpcionSingleton instance = OpcionSingleton.getInstance(); if(!instance.isVisible() && !instance.isIcon()){ // Si la instancia No esta visible y No esta Minimizada (osea que no existe dentro del MDI) // la agregamos al JDesktopPane desktopPane.add(instance); } instance.setVisible(true); instance.setIcon(false); } catch (PropertyVetoException ex) { Logger.getLogger(mainFrame.class.getName()).log(Level.SEVERE, null, ex); } } }); optionHashMap.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { // Obtenemos el JInternalFrame que deseamos abrir, Null si no existe JInternalFrame jInternal = Util.getJInternal(OpcionHashMap.class.getName()); if (jInternal == null || jInternal.isClosed()) { // Class.forName(OpcionHashMap.class.getName()) = Creamos una Nueva clase partiendo del Nombre, y de esa Clase // obtenemos el contructor .getConstructor() y le indicamos a que clase pertenece el parametro enviado, nuestro // caso un String.class Constructor constructor = (Class.forName(OpcionHashMap.class.getName())).getConstructor(String.class); // dado que nuestro constructor recibe como parametro un String, dicho parametro es enviado en // constructor.newInstance("Opcion del HashMap"); // y hacemos el respectivo Cast al objecto que nos es retornado (JInternalFrame) // jInternal = (JInternalFrame) constructor.newInstance("Titulo del Opcion del HashMap desde mainFrame :O"); desktopPane.add(jInternal); // agregamos el recien creado JInternalframe al HashMap de la clase Util Util.addJInternal(OpcionHashMap.class.getName(), jInternal); } jInternal.setVisible(true); jInternal.setIcon(false); } catch (Exception ex) { Logger.getLogger(mainFrame.class.getName()).log(Level.SEVERE, null, ex); } } }); optionModal.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { OpcionModal opcionModal = new OpcionModal(mainFrame.this); opcionModal.setVisible(true); } }); } public static void main(String ... args){ new mainFrame(); } }
Clase Util.java (necesaria para los el menu de HashMap)
package Clases; import java.util.HashMap; import javax.swing.JInternalFrame; // @author McCubo public class Util { // HashMap el cual almacenara el nombre de la clase y la ventana correspondiente a dicha clase private static HashMap<String , JInternalFrame> JInternalMap = new HashMap<String , JInternalFrame>(); // @param className Nombre de la clase que queremos Obtener // @return si la className se encuentra en el set de Llaves del HashMap, entonces retorna // el objeto correpondiente, de lo contrario retorna null public static JInternalFrame getJInternal(String className){ return JInternalMap.get(className); } // @param className Nombre de la clase // @param JInternal Objeto Correspondiente a esa clase public static void addJInternal(String className, JInternalFrame JInternal){ JInternalMap.put(className, JInternal); } }
Ahora la clase con patron Singleton
Nota: el diseño de los siguentes JInternalFrame lo hice con el IDE Netbeans, asi que el metodo initComponents y la declaracion de campos (JLabel, JTextFields, etc) no los presentos, debido a que es muy extenso. pero no importa mucho, ya que el proyecto esta en un zip al final de la entrada, so dont worry ;)
Nota: el diseño de los siguentes JInternalFrame lo hice con el IDE Netbeans, asi que el metodo initComponents y la declaracion de campos (JLabel, JTextFields, etc) no los presentos, debido a que es muy extenso. pero no importa mucho, ya que el proyecto esta en un zip al final de la entrada, so dont worry ;)
package Clases; // @author McCubo public class OpcionSingleton extends javax.swing.JInternalFrame { private static OpcionSingleton frameOpcion1; // si no se tiene ninguna instancia de esta clase O la instancia que poseemos // el JInternalFrame esta cerrado, siendo asi retornamos una nueva instancia; // caso contrario, retornamos la instancia que ya tenemos public static OpcionSingleton getInstance() { if (frameOpcion1 == null || frameOpcion1.isClosed) { frameOpcion1 = new OpcionSingleton(); } return frameOpcion1; } // Creates new form OpcionSingleton // El Constructor debe ser privado para que ninguna clase pueda crear // nuevas instancias directamente private OpcionSingleton() { initComponents(); } private void initComponents(){ // Codigo Generado por Netbeans } // Variables declaration - do not modify // Mas Codigo Generado por NetBeans }// Fin de la Clase
Ahora la Clase OpcionHashMap.java
package Clases; // @author McCubo public class OpcionHashMap extends javax.swing.JInternalFrame { // Creates new form Opcion2 public OpcionHashMap(String tituloDelJinternal) { initComponents(); setTitle(tituloDelJinternal); } private void initComponents(){ // Codigo Generado por Netbeans } // Variables declaration - do not modify // Mas Codigo Generado por NetBeans }// Fin de la Clase
y por ultimo (lo que dicen "y por ultimo pero no menos importante es mentira")
OpcionModal.java
OpcionModal.java
package Clases; import javax.swing.JDialog; import javax.swing.JFrame; // @author mcubias public class OpcionModal extends JDialog { // Creates new form OpcionModal public OpcionModal(JFrame mainFrame) { super(mainFrame, "Soy modal!!!", true); initComponents(); setLocationRelativeTo(null); } private void initComponents(){ // Codigo Generado por Netbeans } // Variables declaration - do not modify // Mas Codigo Generado por NetBeans }// Fin de la Clase
Finalmente mi opinion
Mientras (como dije arriba) el HashMap me parece ideal, quiza un poco mas complejidad en el codigo pero, las clases que se llaman no se toca su estructura en ningun momento, asi que me parece bastante bueno usarlo, por muchas razones, la cantidad y tipo de parametro pueden variar entre cada clase que mandamos a llamar, y con ese metodo podemos facilmente adaptarlo para dicho funcionamiento (recibir distinto tipos y cantidad de parametros por constructor).
Y Por ultimo: hacer modal la ventana. lo que debemos hacer es simplemente darle un extends de JDialog, enviarle el frame principal y en el parametro del constructor enviarle true para que sea modal... pros: facil de usar. (solo ese creo). contras: aveces necesitamos que la clase descienda de una clase que No se JDialog, y como bien sabemos, una clase solo puede extender de una clase a lo mucho, asi que ahi veriamos problemas, otro contra, en toda la aplicacion solo vas a poder tener una ventana abierta... poco funcinal creo. pero bueno ahi esta si la quieres implementar :D
Enlace descarga
Espero a alguien en el universo le sirva este ejemplo. Obviamente hay formas mucho mejores para la generacion de Menus en Java, generarlo desde un xml, tener una clase ListenerMenuXxx en lugar de tener todos los Listener en la misma clase, nose pueden haber infinitas mejores formas de hacerlo, pero mi objetivo ahora simplemente era mostrar y compartir algunas formas con las cuales es posible la implementar solo un JInternalFrame por instancia.
asi que sin mucho mas que decir, Saludos!!!
podrias dar un tuto de como poder abrir un JInternalFrame desde otro JInternalFrame?
ResponderEliminar@Alex rotten
ResponderEliminarPerdón por no darte una respuesta inmediata (o almenos mas rápida), pero para el próximo Viernes (21/11) es posible que publique la entrada explicando lo que solicitas. Gracias por comentar y visitar el blog :D.
Saludos!
Buen aporte Gracias por compartir
ResponderEliminarMuy bueno, me sirvio mucho para generar menus dinamicamente. Muchas gracias
ResponderEliminar