Newsgroup: it.comp.java
Titolo: setContentPane()

Ieri sera, per imparare un po' di Java, mi sono sciroppato 100 righe di
codice relativo ad una maschera con JFrame, JLabel, JTextField, Jpanel ecc.
Il programma funziona ma non mi è chiaro, anche per evidenti limiti nella
traduzione dall'inglese, il concetto di "riquadro del contenitore" e, in
particolare, non capisco cosa faccia la funzione setContentPane. Negli
esempi del libro, talvolta la usano, talvolta no, in contesti apparentemente
simili.
Mi potete aiutare?
Grazie

setContentPane() va usato obbligatoriamente se stai facendo un'applicazione,
altrimenti a video nn vedresti niente (serve a indicare qual è il
"contenitore").
In un'Applet, invece, puoi anche evitare di settare il Content Pane, in
quanto l'Applet in questo caso viene considerata il contenitore stesso
(quindi non c'è bisogno, ad esempio, di creare un JPanel e aggiungervi un
JButton con JPanel.add(JButton), ma basta semplicemente add(JButton) e lo
aggiungi nel pannello principale, ovvero l'Applet).
Ciaps :)

Allora ..............
Turing, oltre a qualche spiegazione, ti consiglio dei manuali che possano
andare più nel dettaglio e farti più chiarezza.
Prima di arrivare agli strumenti e a quello che hai chiesto in dettaglio tu,
ti devo fare alcuni chiarimenti.
Le librerie grafiche (intese come collezione di oggetti grafici: aree di
testo, label, combobox, etc.) che Java mette a disposizione, sono 2.
La prima : AWT, è meno bella (si dice che sià più performante, ma
onestamente non lo posso giurare, anzi a me pare il contrario con gli ultimi
jdk) ed è legata al Kernel grafico del sistema operativo che la ospita. Il
fatto che sia molto meno ricca di componenti, è motivato dalle differenze
tra i kernel grafici dei diversi sistemi operativi. Windows ha molti più
elementi grafici di un'altro S.O. come potrebbe essere BeOs, quindi si è
limitato il numero di strumenti a quelli basilari dei vari S.O. supportati
da Java.
La seconda: SWING (quella che hai utilizzato tu, riconoscibili, perchè i
nomi degli oggetti sono preceduti da una J es: TextField (AWT)
JTextField(SWING)) è ricca di strumenti grafici, è slegata dal sistema
operativo, gli oggetti sfruttano interfacce per renderizzare e per
memorizzare i dati, rendendo questi strumenti estremamente plastici.
A differenza di AWT gli oggetti non inglobano i dati, quindi basta cambiare
i model (quelli che inglobano i dati) per cambiare comportamento e dati di
un oggetto.
Gli oggetti vengono disegnati e quindi il loro aspetto può essere variato
mediante l'interfaccia di rendering dell'oggetto stesso.
Ma veniamo alla tua richiesta.
Le applicazioni Java possono essere quindi SWING o AWT (anche ibride, ma a
volte le due non si amano totalmente, quindi se vedi qualche stranezza
grafica, sai dove andare riparare).
La finestra che vedi a video può essere un Frame o un JFrame, ma quali sono
le differenze oltre quelle che ti ho detto prima?
Entrambe derivano da Container (un Container è un oggetto che come dice il
suo nome è in grado di CONTENERE altri oggetti), in realtà JFrame deriva da
Frame, solo che Frame può contenere direttamente dei componenti, JFrame no.
Cosa significa questo?
Frame può fare questo : frame.add(new Label("pippo")); JFrame deve delegare
questo compito al suo ContentPane.
Un JFrame non è così banale come sembra, in realtà è la sovrapposizione di
alcune strutture.
Una sorta di livelli di lastre trasparenti.
Contiene :
    - un ContentPane : che serve a contenere gli oggetti. in sostanza è e
che contine, quello che realmente vedi nella tua finestra dell'applicazione
    - una RootPane    : discorso lungo per questo, accettalo ti prego
altrimenti non ne usciamo +
    - un glassPane     : stesso discorso del RootPane
Questa struttura a livelli, ha obbligato gli sviluppatori della SUN a
impedire una cosa tipo : jframe.add(new JLabel("Jpippo")). o
jframe.setLayOut(layout);
Ma allora come si fa a settare il tipo di layOut e a inserire oggetti?
Per settare il layout dei componeti e per poterli inserire, bisogna
prelevare il contentPane del JFrame, mediante : [ getContentPane() ], il
quale torna un oggetto Container, su cui puoi fare tutto quello che ti pare
(aggiungere togliere oggeti, settare un'altro layOut, etc.).
Ovviamente come c'è un get c'è anche un set.
Se crei una classe che estende ad esempio un Container e che ha delle
caratteristiche particolari (mostra immagini, ha effetti grafici creati da
te, etc.), la puoi passa al JFrame mediante appunto
[setContentPane(Container)].
Scusami se sono stato un tantino prolisso, ma almeno ora dovresti avere un
quadro più chiaro della situazione.
Ah!!! Dimenticavo, Applet, chiedevi perchè non ha il contentPane, indovina?
Applet deriva da java.AWT.Panel. Applet è un oggetto AWT.
Ciao.

Innanzitutto ti ringrazio sentitamente per la diffusa spiegazione che mi hai
fornito. Il fatto che qualcuno spenda del tempo per aiutare gli altri è una
delle cose che mi commuove nella realtà dei NG.
In ogni caso, ti allego il sorgente del file da me copiato e ti dico che, se
cancello l'istruzione setContentPane non succede nulla (tutto funziona
esattamente allo stesso modo).
Se hai tempo dimmi cosa ne pensi.
Ancora grazie
Turing
import java.awt.*;
import javax.swing.*;
public class LottoMadness extends JFrame {
 // impostare la riga 1
 JPanel row1 = new JPanel();
 ButtonGroup option = new ButtonGroup();
 JCheckBox quickpick = new JCheckBox("Quick Pick",false);
 JCheckBox personal = new JCheckBox("Personal",true);
 // impostare la riga 2
 JPanel row2 = new JPanel();
 JLabel numbersLabel = new JLabel ("Your picks: ",JLabel.RIGHT);
 JTextField[] numbers = new JTextField [6];
 JLabel winnersLabel = new JLabel("Winners; ",JLabel.RIGHT);
 JTextField[] winners = new JTextField[6];
 // impostare la riga 3
 JPanel row3 = new JPanel();
 JButton stop = new JButton("Stop");
 JButton play = new JButton("Play");
 JButton reset = new JButton("Reset");
 // impostare la riga 4
 JPanel row4 = new JPanel();
 JLabel got3Label = new JLabel(" 3 of 6: ",JLabel.RIGHT);
 JTextField got3 = new JTextField();
 JLabel got4Label = new JLabel("4 of 6",JLabel.RIGHT);
 JTextField got4 = new JTextField();
 JLabel got5Label = new JLabel("5 of 6: ",JLabel.RIGHT);
 JTextField got5 = new JTextField();
 JLabel got6Label = new JLabel("6 of 6: ",JLabel.RIGHT);
 JTextField got6 = new JTextField(10);
 JLabel drawingsLabel = new JLabel("Drawings: ",JLabel.RIGHT);
 JTextField drawings = new JTextField();
 JLabel yearsLabel = new JLabel("Years: ", JLabel.RIGHT);
 JTextField years = new JTextField();
 public LottoMadness() {
  super("Lotto Madness");
  setSize(550,270);
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  GridLayout layout = new GridLayout(5,1,10,10);
  Container pane = getContentPane();
  pane.setLayout(layout);
  FlowLayout layout1 = new FlowLayout(FlowLayout.CENTER,10,10);
  option.add(quickpick);
  option.add(personal);
  row1.setLayout(layout1);
  row1.add(quickpick);
  row1.add(personal);
  pane.add(row1);
  GridLayout layout2 = new GridLayout(2,7,10,10);
  row2.setLayout(layout2);
  row2.add(numbersLabel);
  for (int i = 0; i < 6; i++) {
   numbers[i] = new JTextField();
   row2.add(numbers[i]);
  }
  row2.add(winnersLabel);
  for(int i = 0; i < 6; i++) {
   winners[i] = new JTextField();
   winners[i].setEditable(false);
   row2.add(winners[i]);
  }
  pane.add(row2);
  FlowLayout layout3 = new FlowLayout(FlowLayout.CENTER,10,10);
  row3.setLayout(layout3);
  stop.setEnabled(false);
  row3.add(stop);
  row3.add(play);
  row3.add(reset);
  pane.add(row3);
  GridLayout layout4 = new GridLayout(2,3,20,10);
  row4.setLayout(layout4);
  row4.add(got3Label);
  got4.setEditable(false);
  row4.add(got3);
  row4.add(got4Label);
  got4.setEditable(false);
  row4.add(got4);
  row4.add(got5Label);
  got5.setEditable(false);
  row4.add(got5);
  row4.add(got6Label);
  got6.setEditable(false);
  row4.add(got6);
  row4.add(drawingsLabel);
  drawings.setEditable(false);
  row4.add(drawings);
  row4.add(yearsLabel);
  years.setEditable(false);
  row4.add(years);
  pane.add(row4);
**********************************************
  setContentPane(pane); // non capisco a cosa serve!!
**********************************************
  setVisible(true);
 }
 public static void main(String[] arguments){
  LottoMadness Frame = new LottoMadness();
 }
}

Allora....... analiziamo il codice :
// Come prima cosa quella J dice che stai creando un'Applicazione basata su
una
// finestra SWING.
public class LottoMadness extends JFrame {
[CUT]
    public LottoMadness() {
        // Eccola!!!!!!
        // Il programmatore si è memorizzato dentro una variabile
        // di appoggio il ContentPane del JFrame.
        // Questo evita di dover stare a scrivere sempre getContentPane()
        Container pane = getContentPane();
        // Come ti dicevo sopra.
        pane.setLayout(layout);
        [CUT]
        // Ecco quello che tanto ti infastidisce.
        // Non capisco per quale motivo il programmatore abbia
        // fatto questa cosa.
        // E' assolutamente inutile.
        // Leggi sotto* che ti spiego alcune cose.
        /**********************************************/
           setContentPane(pane); // non capisco a cosa serve!!
        /**********************************************/
        setVisible(true);
    }
* Questo è : SOTTO
Senza entrare nello specifico, i dati risiedono nella memoria, quindi sono
composti da un valore (il dato vero e proprio) e un indirizzo (cioè la
posizione nella memoria in cui sono immagazzinati), necessario a poterli
rintracciare.
In Java non esistono i puntatori (tipi di dati che puntano ad indirizzi di
memoria), per fortuna di molti (quelli che non hanno mai lavorato in
C/C++/Assembly o che li odiano) e disgrazia di altri (quelli che hanno
lavorato in C/C++/Assembly e che gli sono ancora molto affezionati).
I puntatori ti permettono di accedere ai diversi dati, cambiando
semplicemente l'indirizzo in essi contenuti, senza dover spostare i dati.
Immagina di avere 10 Oggetti che occupano in memoria 1MB ciascuno e un
puntatore ad Oggetto (un puntatore su sistemi intel occupa sotto windows 32
bit = 8 byte), puoi usare ognuno di quei 10 dinamicamente, senza doverlo
copiare prima o spostarlo, ma semplicemnte cambiando l'indirizzo di memoria.
es
    Oggetto 1 [blocco dati = 1MB] indirizzo 1231
    Oggetto 2 [blocco dati = 1MB] indirizzo 1232
    ........................
    .....
    Oggetto 10 [blocco dati = 1MB] indirizzo 1240
    puntatore p = 1231
    se faccio un'oprazione su [p] ne risentirà l'Oggetto 1.
    se cambio il puntatore e lo metto : p=1240
    e faccio un'altra operazione su [p] ne risentirà l'Oggetto 10
Immagina di avere delle case, invece di spostare le 10 case, se vuoi
visitare un'altra casa, basta cambiare l'indirizzo.
Ma che centra questo con il problema da te riscontrato?
Semplice.
getContentPane() non ti torna un oggetto Container, ma il suo indirizzo di
memoria, quindi qualunque operazione che tu fai su quell'oggetto, la fai
direttamente sull'oggetto memorizzato dentro il JFrame.
Il fatto di rifare setContentPane(...) a quel punto è totalmente inutile.
Hai solo ripassato al Container dalla JFrame il suo stesso indirizzo.
Mentre DEVI utilizzare setContentPane(....), se per esempio tu crei un NUOVO
Container e lo vuoi impostare dentro il tuo JFrame, sovrascrivendo quello
esistente.
In fondo, pensaci.
Com'è possibile che tu, mediante il metodo add(...) di un Container,
attacchi ad esempio un bottone alla tua applicazione (es
pane.add(bottone);), poi basta variare il colore di quel bottone
(bottone.setForeground(Color.red);) che in autometico cambia anche a video?
Quando hai fatto pane.add(bottone), il Container, non si è memorizzato
l'oggetto (pensa che spreco di memoria ci sarebbe con tutti questi duplicati
e che casino andarli ad aggiornare tutti), ma il suo riferimento (in java i
puntatori non esistono, ma esistono i riferimenti ad un oggetto che poi è la
stessa cosa), quindi la tua modifica viene vista anche dal Container, perchè
lui ha un riferimento (quindi punta alla zona di memoria dove risiede il tuo
oggetto) al tuo oggetto, la modifica l'hai fatta sul tuo oggetto, ma lui
mediante il puntatore la vedrà automaticamente.
Spero di non averti confuso le idee.
Ciao.

Grazie infinite. Mi č stato utilissimo.
Alessandro Minazzato