Newsgroup: it.comp.java
Titolo: Passare da un JPanel ad un altro...

Ciao a tutti, vorrei creare un'applicazione così strutturata :
 
All'avvio dell'applicazione ho un JFrame che viene visualizzato con al suo interno un JPanel (creato in una classe a parte ma dichiarato all'interno della classe del JFrame).
Da questa schermata si effettua il login e se tutto va a buon fine vorrei sostituire il pannello attuale utilizzato per il login, inizializzandone uno nuovo (creato in un'altra classe) senza utilizzare il CardLayout... voglio gestire tutto io manualmente.
 
Quindi ho 3 classi... :
- 1 classe che estende JFrame (che sarebbe quella principale)
- 1 classe che estende JPanel (che sarebbe quella di Login contenuta nel JFrame)
- 1 classe che estende JPanel (che sostituisce il JPanel utilizzato nella fase di Login, contenuto nel JFrame principale)
 
In parole povere vorrei fare in modo che il JFrame abbia sempre e solo 1 JPanel da gestire... che deve essere creato di volta in volta con il seguente comando:
panel = new (Nome della classe creata che estende JPanel)();
 
Questo comunque è il JFrame che ho creato :
 
--------------------------------------------------------------------------------
public class Main extends JFrame {
 
	private JPanel panel;
 
	public static void main(String[] args) {
		try {
			Main window = new Main();
			window.setVisible(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	public Main() {
		this.setTitle("Prova");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setBounds(100, 100, 260, 300);
		this.setResizable(false);
		panel = new Login();
		this.setContentPane(panel);
	}
}
--------------------------------------------------------------------------------
 
Questo è il codice del JPanel di Login che viene visualizzato all'inizio :
 
--------------------------------------------------------------------------------
public class Login extends JPanel {
	private JTextField jUserField;
	private JPasswordField jPasswordField;
 
	public Login() {
		this.setLayout(null);
		this.setBorder(new EmptyBorder(5,5,5,5));
 
		JButton btnLogin = new JButton("Login");
		btnLogin.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
 
			}
		});
		btnLogin.setBounds(96, 192, 89, 23);
		add(btnLogin);
 
		JLabel lblUser = new JLabel("Username");
		lblUser.setBounds(21, 96, 74, 14);
		add(lblUser);
 
		JLabel lblPassword = new JLabel("Password");
		lblPassword.setBounds(21, 129, 74, 14);
		add(lblPassword);
 
		jUserField = new JTextField();
		jUserField.setBounds(105, 93, 122, 20);
		add(jUserField);
		jUserField.setColumns(10);
 
		jPasswordField = new JPasswordField();
		jPasswordField.setBounds(105, 126, 122, 20);
		add(jPasswordField);
	}
}
--------------------------------------------------------------------------------
 
Questo è il codice del JPanel che deve essere visualizzato al posto del vecchio, a login avvenuto :
 
--------------------------------------------------------------------------------
public class SecurityContainer extends JPanel {
 
	public SecurityContainer() {
		this.setLayout(null);
		this.setBorder(new EmptyBorder(5,5,5,5));
 
		JButton btnSalva = new JButton("Salva");
		btnSalva.setBounds(102, 253, 89, 23);
		add(btnSalva);
 
	}
}
--------------------------------------------------------------------------------
 
Come faccio a sostituire il panel contenuto nella classe Main (JFrame) con quello nuovo (SecurityContainer) quando dalla classe Login (JPanel) clicco sul pulsante "Login" ?
 
Ho provato con il getParent() ma non è che ci abbia capito molto... stavo pensando anche di passare la classe Main nel costruttore della classe Login come parametro "final"....
Help me :)

il 05.11.2012 14:57, Scrive Daniele Volpe 96485068:

Per quanto possa aver capito, dovresti utilizzare di nuovo il metodo 
setContentPane ad esempio nel corpo del metodo actionPerformed in questo 
modo;
  final JPanel p = this;
  public void actionPerformed(ActionEvent e) {
	boolean validLogin = // qui occorre validare il login
	if (validLogin) {
		// il metodo getParent() ritorna null finche'
		// il panel non e' stato aggiunto ad un contenitore
		Container c = p.getParent();
		if (c != null && (c instanceof JFrame)
		((JFrame)c).setContentPane(new SecurityContainer();
	}
  }
 

Grazie per la risposta.
 
Si è proprio quello che vorrei fare, ho provato a modificare il codice all'interno dell'evento, ma non mi entra nell'if in quanto il container non è un'istanza di JFrame.
 
Mettendo le seguenti 2 righe di stampa :
System.out.println(c.getComponentCount());
System.out.println(c.getName());
 
Mi stampa rispettivamente :
1
null.layeredPane

 non è un'istanza di JFrame.
Hai ragione, sono stato frettoloso. In effetti il JPanel non viene 
aggiunto al JFrame ma al suo root container, per cui dovresti rimuovere 
  il vecchio JPanel ed aggiungere il nuovo probabilmente così:
 
  final JPanel p = this;
  public void actionPerformed(ActionEvent e) {
     boolean validLogin = // qui occorre validare il login
     if (validLogin) {
         // il metodo getParent() ritorna null finche'
         // il panel non e' stato aggiunto ad un contenitore
         Container c = p.getParent();
         if (c != null) {
		c.remove(p);
		c.add(new SecurityContainer());
	}
     }
  }
 
 
Un'altra cosa che mi era sfuggita: utilizzando il metodo setContentPane, 
e' opportuno che il JComponent utilizzato sia opaque, per rispettare 
l'architettura di painting dei componenti swing che pretende che almeno 
un componente opaque nella gerarchia dei contenitori , quindi nella 
costruzione dei tuoi oggetti Login e SecurityContainer dovresti 
utilizzare setOpaque(true).
 
In definitiva invece di utilizzare setContentPane(panel), utilizzerei 
invece getContentPane().add(panel), rimanendo il resto invariato.
In pratica utilizzando il content pane creato dal costruttore di JFrame.

Ho apportato le ultime modifiche, il programma non va in errore ma cliccando sul pulsante di Login non mi cambia il pannello.
Sto provando a fare un po di prove :)

Ho risolto, dovevo dare il "revalidate()" :)
Grazie ancora per l'aiuto.

Ciao a tutti , 
Ho creato un classe principale 
 
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import java.io.File;
import java.io.IOException;
import java.net.URL;
 
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
 
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
 
 
 
 
 
 
public class fantasy1 extends JFrame {
public static  Clip audio;
 
    public static void main(String[] args) {
 
 
 
     colonnasonora("./sound/storia.wav");
 
       JFrame myFrame = new JFrame("Fantasy 1");
 
 
     //Se larghezza 768 --> 16 *48 (Muro) --> 768 - Altezza 576 --> 48 *12 
 
        myFrame.setSize(728, 455); // 768 * 576 -> risoluzione dell'immagine oelemento 
        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        myFrame.setLocationRelativeTo(null);
       myFrame.setResizable(false);
// vorrei scrivere se premo la barra spaziatrice carichi l'immagine statica 1
      la seconda volta immagine 2 la terza  immagine 3
 La 4 volta entra  nel gioco e carico la classe dedicata GameFrame
GameFrame prende il controllo della tastiera programmata per il player
        myFrame.add(new cover()); // Copertina
        //myFrame.add(new GameFrame()); // Gioco
 
        myFrame.setIconImage(new ImageIcon("./img/ico.png").getImage());
        myFrame.setVisible(true); 
 
 
 
 
    }
 
    public static void colonnasonora ( String musica){
 
 
        try {
             audio = AudioSystem.getClip();
 
            audio.open(AudioSystem.getAudioInputStream(new File(musica)));
            audio.loop(Clip.LOOP_CONTINUOUSLY);
            audio.start();
        } catch (Exception e) {
            System.out.println(e);
        }
    } 
 
 
}
 
 
Ho la necessità il programma parte con il panello definito sulla classe cover
questa deve rimanere in ascolto dei tasti.
se non viene premuto nulla la cover carica slide immagini a ripetizione.
Alla pressione del tasto "Space"
Viene caricata un immagine statica 1
la seconda volta un immagine statica 2
alla terza un immagine statica 3
alla quarta volta il programma passa dal panello definito nella classe cover alla classe GameFrame.
Questa classe rimane in ascolto dei tasti a seconda del tasto premuto muove il player
ecco un seudo codice
 
usa cosa del genere
      myFrame.add(new cover()); // Copertina caricata all'avvio dell'applicazione
cont= 0;
if (e.event =='space' ) {
if ( cont ==0) {
loadimage1;
cont= cont+1;
} esle if ( cont ==1) {
loadimage2;
cont= cont+1;
}  esle if ( cont ==2) {
loadimage3;
cont= cont+1;
}  else
myFrame.add(new GameFrame()); //Modifico il panello e prendo controllo dei tasti
// attiva tasti gestione player
}
 
Come faccio a cambiare il panello in fase di avvio e gestire i tasti in modo che all'inizio vengono rilevati dalla classe cover è successivamente viene caricata la classe  GameFrame cambiando evento tasti dedicati al player?
 
Grazie mille