JMenuItem, azione

di il
3 risposte

JMenuItem, azione

Salve,
studiando Java, in particolar modo Swing, mi trovo di fronte ad un problema che qui di seguito Vi espongo.
Volevo gentilmente chiederVi come caricare, se possibile, una nuova classe all'interno di un'azione di un JMenuItem, ovvero, da un menù a tendina, cliccando col mouse su una voce del menù, caricare di seguito una nuova classe che andrà a popolare una nuova pagina composta da vari elementi di swing, quali JPanel, JLabel, JTextField, JButton ecc...

La logica che sto seguendo è la seguente:
1) ho creato una prima classe, Main(), Che contine un JFrame ed un Container con layout di tipo BorderLayout(). Di seguito istanzio una prima pagina, pagina_1, passandogli come parametri il riferimento sia del JFrame che del Container.

package gui;

import java.awt.BorderLayout;
import java.awt.Container;

import javax.swing.JFrame;

public class Main {
	static JFrame myjframe;
	static Container mycontainer;
	
	public static void main(String[] args) {
		myjframe = new JFrame("PROVA MENU");
		myjframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		myjframe.setSize(800, 600);
		
		mycontainer = myjframe.getContentPane();
		mycontainer.setLayout(new BorderLayout());
		
		Pagina_1 p1 = new Pagina_1(myjframe, mycontainer);

		myjframe.setVisible(true);
	}
}
2) Nella classe Pagina_1, di segutio, creo un menu a tendina, tramite: JMenuBar; JMenu; e JMenuItem.
Con le voci: Pagina_2, Pagina_3, Pagina_4.
E lo inserisco all'interno di un JPanel, panel_1, posizionandolo nel Nord del Container.
Al Centro del Container, carico, infine, una JLabel (new JLabel("Pagina_1");) all'interno di un JPanel, panel_2.

package gui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class Pagina_1 {

	public Pagina_1(JFrame myjframe, Container mycontainer) {
		
		JPanel panel_1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
		
		JMenuBar menuBar = new JMenuBar();
		
		JMenu menuFile_1 = new JMenu("Menu_1");
		menuBar.add(menuFile_1);
		
        JMenuItem menu_item_1 = new JMenuItem("Pagina_2");
        JMenuItem menu_item_2 = new JMenuItem("Pagina_3");
        JMenuItem menu_item_3 = new JMenuItem("Pagina_4");
        menuFile_1.add(menu_item_1);
        menuFile_1.add(menu_item_2);
        menuFile_1.add(menu_item_3);

		JPanel panel_2 = new JPanel(new FlowLayout(FlowLayout.LEFT));
		JLabel label_1 = new JLabel("Pagina_1");
		panel_2.add(label_1);
        
		/* MENU LISTENERS */
		menu_item_1.addActionListener(new Nuovepagine());
		menu_item_2.addActionListener(new Nuovepagine());
		menu_item_3.addActionListener(new Nuovepagine());
		
        mycontainer.add(menuBar, BorderLayout.NORTH);
        mycontainer.add(panel_2, BorderLayout.CENTER);
        mycontainer.setVisible(true);
	}
	class Nuovepagine implements ActionListener {		  
		public void actionPerformed(ActionEvent e) {
		    System.out.println("Selected: " + e.getActionCommand());
		  }
		}
}
3) Ho creato infine, i Listeners, per ogni voce del menù.

Ora, però, non capisco come poter istanziare nuove classi, ovvero creare nuove pagine (come ad esempio, pagina_2, pagina_3, ecc...) cliccando sulle varie voci dei menù. E' possibile fare ciò? cambiare pagina tramite l'uso di un menù?

3 Risposte

  • Re: JMenuItem, azione

    Il modo consueto per fare quello che chiedi è l'utilizzo di un CardLayout (tutorial ufficiale), che consente di scambiare i vari componenti (tipicamente dei pannelli, in questo caso le tue pagine) all'interno di un Container.

    Al content pane del tuo frame potresti quindi settare questo tipo di layout (o anche a una parte del frame se vuoi che una o più parti rimangano fisse anche quando viene impostato un nuovo pannello come visibile), e quando clicchi un item nel menu richiamare il metodo show del CardLayout con il nome del pannello corrispondente.
    I pannelli possono essere aggiunti al container sia in fase di creazione dell'interfaccia, ma anche in modo dinamico se hai bisogno di crearli al volo in base a delle informazioni che non sono disponibili all'inizio/si aggiornano.

    La cosa un po' complicata può essere disegnare le classi in modo da non essere costretti a passare qua e là i riferimenti al frame, o al content pane o al cardlayout, che in generale non è una buona cosa.
    Sicuramente però non hai bisogno di mantenere frame e mycontainer come variabili statiche, dichiarali localmente al metodo, che tu decida di passarli o meno al costruttore di Pagina_1.
    La JMenuBar poi, piuttosto che essere aggiunta all'interno del content pane, sarebbe meglio impostarla direttamente al frame con il metodo setJMenuBar di JFrame.
  • Re: JMenuItem, azione

    Al problema di come creare un'azione ad ogni voce del menù, per poi, come azione, istanziare una classe, ho risolto nel seguente modo:
    L'azione alla voce del menù avviene nel seguente modo:
    
    JMenuItem menu_item_1 = new JMenuItem("Pagina_2");
    
    */
    		menu_item_1.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				System.out.println("Selected: " + e.getActionCommand());
    				mycontainer.removeAll();
    				Pagina_2 p2 = new Pagina_2(myjframe, mycontainer, menuBar);
    			}
    		});
    
    Per il resto, ho seguito il tuo consiglio:
    1) JFrame e Container come variabili locali
    2) Ho sostituito il JMenuBar agganciato al Container con JFrame.setJMenuBar(menuBar);
    
    // mycontainer.add(jmenuBar, BorderLayout.NORTH);
    myjframe.setJMenuBar(menuBar);
    
    Il codice finale è, la classe Main:
    
    package gui;
    
    import java.awt.BorderLayout;
    import java.awt.Container;
    
    import javax.swing.JFrame;
    
    public class Main {
    	
    	public static void main(String[] args) {
    		JFrame myjframe = new JFrame("PROVA MENU");
    		myjframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    		myjframe.setSize(800, 600);
    		
    		Container mycontainer = myjframe.getContentPane();
    		mycontainer.setLayout(new BorderLayout());
    		
    		Pagine p1 = new Pagine(myjframe, mycontainer);
    
    		myjframe.setVisible(true);
    	}
    }
    
    dove all'interno viene istanziata la classe Pagine, con le relative sottoclassi Pagina_2, Pagina_3, Pagina_4, istanziate all'interno dell'Action dei JmenuItem:
    
    package gui;
    
    import java.awt.BorderLayout;
    import java.awt.Container;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.JPanel;
    
    public class Pagine {
    
    	public Pagine(JFrame myjframe, Container mycontainer) {
    		
    		JPanel panel_1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
    		
    		JMenuBar menuBar = new JMenuBar();
    		
    		JMenu menuFile_1 = new JMenu("Menu_1");
    		menuBar.add(menuFile_1);
    		
            JMenuItem menu_item_1 = new JMenuItem("Pagina_2");
            JMenuItem menu_item_2 = new JMenuItem("Pagina_3");
            JMenuItem menu_item_3 = new JMenuItem("Pagina_4");
            menuFile_1.add(menu_item_1);
            menuFile_1.add(menu_item_2);
            menuFile_1.add(menu_item_3);
    
    		JPanel panel_2 = new JPanel(new FlowLayout(FlowLayout.LEFT));
    		JLabel label_1 = new JLabel("Pagina_1");
    		panel_2.add(label_1);
            
    		/* MENU LISTENERS */
    		menu_item_1.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				System.out.println("Selected: " + e.getActionCommand());
    				mycontainer.removeAll();
    				Pagina_2 p2 = new Pagina_2(myjframe, mycontainer, menuBar);
    			}
    		});
    		
    		menu_item_2.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				System.out.println("Selected: " + e.getActionCommand());
    				mycontainer.removeAll();
    				Pagina_3 p3 = new Pagina_3(myjframe, mycontainer, menuBar);
    			}
    		});
    		
    		menu_item_3.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				System.out.println("Selected: " + e.getActionCommand());
    				mycontainer.removeAll();
    				Pagina_4 p4 = new Pagina_4(myjframe, mycontainer, menuBar);
    			}
    		});
    		
            // mycontainer.add(menuBar, BorderLayout.NORTH);
    		myjframe.setJMenuBar(menuBar);
            mycontainer.add(panel_2, BorderLayout.CENTER);
            mycontainer.setVisible(true);   
    	}
    	
    	public class Pagina_2 {
    
    		public Pagina_2(JFrame myjframe, Container mycontainer, JMenuBar menuBar) {
    
    			JPanel panel_1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
    			JLabel label_1 = new JLabel("Pagina_2");
    			panel_1.add(label_1);
    			myjframe.setJMenuBar(menuBar);
    			mycontainer.add(panel_1, BorderLayout.NORTH);
    			mycontainer.revalidate();
    		}
    	}
    	
    	public class Pagina_3 {
    
    		public Pagina_3(JFrame myjframe, Container mycontainer, JMenuBar menuBar) {
    
    			JPanel panel_1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
    			JLabel label_1 = new JLabel("Pagina_3");
    			panel_1.add(label_1);
    			myjframe.setJMenuBar(menuBar);
    			mycontainer.add(panel_1, BorderLayout.NORTH);
    			mycontainer.revalidate();
    		}
    	}
    	
    	public class Pagina_4 {
    
    		public Pagina_4(JFrame myjframe, Container mycontainer, JMenuBar menuBar) {
    
    			JPanel panel_1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
    			JLabel label_1 = new JLabel("Pagina_4");
    			panel_1.add(label_1);
    			myjframe.setJMenuBar(menuBar);
    			mycontainer.add(panel_1, BorderLayout.NORTH);
    			mycontainer.revalidate();
    		}
    	}
    }
    
    Il problema, per ora, sembra risolto, spero, in maniera corretta
    Grazie!
  • Re: JMenuItem, azione

    Può anche funzionare, io ti consiglio comunque di provare a utilizzare il CardLayout, che è il modo "tradizionale" (oserei dire quello "corretto", in base a quanto ho visto in questi anni in giro per i forum) per scambiare i pannelli di un Container.
    Il fatto di rimuovere tutti i componenti e ricreare tutto da capo è meno performante e più "rischioso" a livello di bug.

    Anche i costruttori che ricevono frame, container e menubar sarebbero da rivedere, io limiterei davvero al minimo il passaggio dei componenti tra metodi, senza contare che stai fondamentalmente ripetendo sempre lo stesso codice e avresti quantomeno bisogno di generalizzare il tutto per avere un codice più pulito, corto e mantenibile.

    Dico questo solo per non farti credere che la soluzione sia del tutto "corretta", il resto viene con il tempo, quando ho iniziato a lavorare con swing scrivevo codice ben peggiore di questo ... Intanto magari prova a risolvere con il CardLayout
Devi accedere o registrarti per scrivere nel forum
3 risposte