|  | La finestra principal | 
   
    |  |  | 
   
    |  | L'objectiu d'aquesta pràctica és 
        el d'aprendre a crear la finestra principal 
        o finestra arrel d'una aplicació 
        Java. Al mateix temps continuarem amb la discussió d'alguns 
        conceptes i maneres de fer pròpies de la programació 
        Java: 
        Ens dedicarem intensivament a derivar 
          classes filles 
          d'una classe mare 
          i seguirem aprofundint respecte als mecanismes i implicacions del concepte 
          d'herència.
 
Farem més pràctica d'escriptura de 
          mètodes constructors de classes.
 
Començarem a discutir 
          i aplicar el paradigma esdeveniment-oient 
          (event-listener)
 
 Farem ús intensiu de classes 
          que es refereixen a sí mateixes.
 
Aprendrem com crear automàticament el codi per 
          a una finestra bàsica amb JCreator. | 
   
    |  |  | 
   
    |  | Desenvolupament de la pràctica | 
   
    |  |  | 
   
    |  | Començarem per aprendre a crear un frame, 
        és a dir, la finestra principal,l'arrel 
        de tota aplicació Java que implementi 
        l'entorn gràfic del SDK. | 
   
    |  |  | 
   
    |  | Fem la primera finestra: | 
   
    |  |  | 
   
    |  | Obrim el JCreator. 
        Si no és que ja estava creat, creem un Workspace 
        amb el nom Modul_5, 
        la carpeta del qual haurà de penjar de la C:\D110src\D110ws. 
        Recordem la seqüència: File -> New -> Workspaces Ara crearem el projecte. 
        A la finestra de l'esquerra cliquem amb el botó esquerre del ratolí 
        sobre el Workspace 
        Modul_5 i seleccionem 
        "Add new project...". 
        Llavors, seleccionem "Empty project" 
        i li donem el nom "Finestra01". 
        Molta atenció a les majúscules 
        i les minúscules! A continuació, crearem el fitxer font. 
        Comprovem que el projecte Finestra01 
        és actiu (per activar-lo, a la 
        finestra de l'esquerra, cliqueu amb el botó dret sobre el projecte 
        i seleccioneu: "Set as active project". 
        El nom del projecte apareixerà en negreta) i fem File -> New -> Files -> 
        Java File Com a nom, li posem "Finestra01.java". 
        Molta atenció altra vegada a les majúscules 
        i les minúscules! 
        L'extensió ".java" 
        és opcional: JDC 
        ja la posa per defecte. Ara escriurem el codi. És aquest: 
         
          | import java.awt.*; //----------------------------------------------------------------
 class Finestra01 extends Frame {
 
 public static void main (String args[]) {
 Finestra01 
            mainFrame = new Finestra01();
 mainFrame.setSize(350,200);
 mainFrame.setTitle("Primera 
            finestra");
 mainFrame.setVisible(true);
 }
 
 }
 |  | 
   
    |  |  | 
   
    |  | Analitzem aquest codi: | 
   
    |  |   | 
   
    |  | 
        class Finestra01 extends Frame {}  Es 
          defineix la classe Finestra01, 
          tal com havíem fet a les pràctiques del Mòdul 
          4, i la fem derivar de la classe Frame, 
          ja predefinida al paquet (package) 
          java.awt, la qual implementa 
          la funcionalitat necessària per tal que aparegui una finestra 
          gràfica a la pantalla de l'ordinador quan fem córrer l'aplicació.La 
          gent de Sun 
          ja ens ha fet molta de la feina!.
 Recordem: 
          per fer que una classe 
          derivi d'una altra 
          classe cal 
          fer servir la clàusula "extends":
 
 
 
             
              | class ClasseFilla extends ClasseMare { ... } |  
 
        import java.awt.*; Per 
          tal que el compil·lador sàpiga a què ens referim 
          quan escrivim "Frame", 
          és a dir, on és el codi de la classe 
          mare, necessitem començar el fitxer 
          amb aquesta línia. Aquí hi diu que s'importi 
          tot el paquet java.awt, 
          per tal de tenir disponibles totes les classes 
          que l'integren.
 Si es preveu que, del paquet 
          java.awt només 
          en farem servir la classe 
          Frame, llavors aquesta 
          primera línia podria haver estat:
 
 
 però això no és una pràctica 
          corrent.
 
 Encara més; podem no 
          importar el paquet, 
          pero, llavors, la línia de definició 
          de la classe ha de ser:
 
 
 
             
              | class Finestra01 extends 
                java.awt.Frame { |  Recordem: 
          per poder fer servir alguna de les classes 
          del SDK, cal importar 
          el paquet del qual en forma part.
 
 
         public static void main (String args[]) { ... 
          }  El mètode 
          main és el 
          que busca la Màquina Virtual 
          de Java per executar-lo el primer de tots. 
          Recordeu que els paràmetres 
          són una matriu 
          (array) de 
          cadenes, 
          la qual pot estar buida.
 Recordem: una 
          aplicació Java 
          ha de contenir sempre el mètode 
          main, declarat 
          com a:
 
 
 
             
              | public static void 
                main (String args[]) { <el meu codi>
 }
 |  Aquest mètode 
          és el primer que executa la Màquina 
          Virtual de Java.
 
 A dintre d'aquest mètode 
          hi trobem:
 
 
 
            Finestra01 mainFrame = new Finestra01(); 
               Aquesta línia crea l'objecte 
              mainFrame (el nom "mainFrame" 
              és arbitrari, però posem aquest per coherència 
              amb allò que, després, ens farà JCreator) 
              com a fill de la classe 
              Finestra01 (que 
              és, precisament, la classe 
              de la qual n'estem escrivint el codi! Però això no 
              ha de preocupar-nos ara: és perfectament legal). L'objecte 
              mainFrame és 
              allò que es veurà a la pantalla quan fem córrer 
              l'aplicació.
 Finestra01() és 
              el mètode constructor 
              de la classe Finestra01. 
              Un mètode constructor 
              d'una classe 
              és un mètode 
              pensat per a construir objectes 
              derivats d'aquesta classe.
 
 Objecció: però... 
              a la nostra classe Finestra01 
              no hi ha escrit cap mètode 
              constructor, cap mètode 
              Finestra01() !
 
 Resposta: 
              Com que de moment no volem fer que el nostre objecte 
              mainFrame faci més 
              coses que les previstes a la classe 
              mare Frame, 
              simplement aprofitem que a causa de l'herència, 
              la nostra classe 
              ja implementa tots els mètodes 
              de la classe mare Frame, 
              en particular, un mètode 
              constructor.
 
 Conclusió: 
              per tal de construir un objecte 
              derivat d'una certa classe 
              mare, es poden fer servir algun dels mètodes 
              constructors de la classe 
              mare.
 
 
mainFrame.setSize(350,200);  Fixa 
              les dimensions de la finestra en píxels. 
              Consulteu la documentació 
              de la classe 
              java.awt.Component, (de la qual en deriva 
              la classe 
              java.awt.Container, de la qual en deriva 
              la classe java.awt.Window, 
              de la qual en deriva java.awt.Frame) 
              i hi veureu el mètode 
              public void setSize(int width,int height).
 
mainFrame.setTitle("Primera finestra"); 
              Serveix per establir el títol 
              del Frame. 
              La cadena 
              entre cometes hi apareixerà com a títol a la part 
              superior. Consulteu la documentació 
              de la classe 
              java.awt.Frame  i hi veureu el mètode 
              public void setTitle(String title).
 
mainFrame.setVisible(true); Mètode 
              heretat de la classe java.awt.Component.
 Aquest mètode, public 
              void setVisible(boolean b), fa visible 
              o ocult aquest component segons 
              el paràmetre 
              b sigui true 
              o false.
 | 
   
    |  | Compilem i executem, que ja n'és 
        l'hora! | 
   
    |  |  | 
   
    |  | Anem a JCreator, 
        comprovem que hem escrit bé el codi i anem a compilar. 
        Els botons, recordem-ho, són aquests: 
        Tal com us vam indicar a la pràctica 
          4 del mòdul 1, convé acostumar-se a la sana pràctica 
          de programació que consisteix en separar 
          les fonts dels fitxers compilats. Per fer-ho, 
          comencem per crear la carpeta "classes", 
          que ha de penjar de la carpeta C:\D110src\D110ws\Modul_4\Finestra01, i 
          per indicar a JCreator 
          que volem que les classes compilades 
          les posi en aquesta carpeta. (Vegeu la pràctica 
          4 del mòdul 1)
 
Premem el botó 
          de compilació. JCreator 
          ens ha de respondre "Process 
          completed" i no donar-nos cap missatge 
          d'error.
 
Ara premem el botó 
          d'execució. S'obrirà primer 
          una finestra de MSDOS 
          i, a sobre, una finestra 
          amb el títol "Primera finestra", 
          tal com havíem programat. El resultat:
 
 La nostra primera 
          finestra!
 | 
   
    |  |  | 
   
    |  | Bé, bé, però 
      això necessita millores... | 
   
    |  |  | 
   
    |  | En efecte, podem minimitzar aquesta 
      finestra, maximitzar-la... però el botó 
      de tancar-la no respon! 
 Per raons que no vénen al cas ara, la classe 
      java.awt.Frame no està preparada per capturar 
      l'esdeveniment "botó de tancar finestra apretat" 
      i obrar en conseqüència (tancant-se, és clar!)
 | 
   
    |  |  | 
   
    |  | Ara anem a dotar el nostre objecte 
      mainFrame d'aquesta funcionalitat: | 
  
    |  |  | 
   
    |  | 
        Al mateix Workspace 
          Modul_5 que ja tenim, 
          creem un nou projecte amb el nom "Finestra02". 
          Molta atenció a les majúscules 
          i les minúscules i a, 
          com abans, fer servir l'opció "Empty 
          project"!
 
Igualment, creem ara la carpeta "classes" 
          que ha de penjar de la carpeta C:\D110src\D110ws\Modul_4\Finestra02, i 
          indiquem-li a JCreator que volem que 
          les classes compilades les posi en aquesta carpeta. (Vegeu la pràctica 
          4 del mòdul 1)
 
Creem el fitxer 
          font, amb nom "Finestra02.java" 
          (novament: molta atenció a les majúscules 
          i les minúscules!) 
          amb aquest codi:
 
 
             
              | import java.awt.*;import java.awt.event.*;
 //------------------------------------------------------------
 class Finestra02 
                  extends Frame {
 
 public Finestra02 
                  () {  //constructor
 super();
 addWindowListener(new 
                  PWindowAdapter(this));
 }
 
 public static void main (String args[]) 
                  {
 Finestra02 
                  mainFrame = new Finestra02();
 mainFrame.setSize(350,200);
 mainFrame.setTitle("Primera 
                  finestra ja funcional");
 mainFrame.setVisible(true);
 }
 
 }
 //------------------------------------------------------------
 class PWindowAdapter extends WindowAdapter 
                  {
 
 Finestra02 
                  mainFrame;
 
 public PWindowAdapter (Finestra02 
                  mainFrame) {  //cons-
 // 
                  tructor
 super();
 this.mainFrame=mainFrame;
 }
 
 public void windowClosing(WindowEvent 
                  e) {
 mainFrame.dispose();
 System.exit(0);
 }
 
 }
 |  | 
   
    |  |  | 
   
    |  | Analitzem aquest codi: | 
   
    |  |  | 
   
    |  | 
        import java.awt.event.*; 
          com que més avall hi definim la classe 
          PWindowAdapter com a filla 
          de la classe java.awt.event.WindowAdapter, 
          és evident que hem d'importar 
          el paquet java.awt.event.
 
public Finestra02 
          () { ... } és el mètode 
          constructor de la classe 
          Finestra02. Ara, 
          com que hem d'afegir més funcionalitats a la classe 
          java.awt.Frame, 
          ja cal escriure un mètode constructor 
          nou. Observeu-ne la sintaxi!
 Recordem: 
          Un mètode constructor 
          ha de ser declarat 
          public, ha de tenir 
          el mateix nom que la classe 
          que construeix, però no se n'ha de declarar el tipus 
          de variable que retorna, perquè el 
          compilador ja sobreentén que retornarà una instància 
          d'aquesta classe.
 
 
super(); és la 
          crida al mètode constructor 
          de la classe mare. Cal demanar-lo per poder 
          disposar de tota la funcionalitat de la classe 
          mare.
 Conclusió: 
          Un mètode constructor 
          d'una classe 
          filla d'una altra ha de contenir, com a primera línia de codi 
          la crida super() 
          a algun dels mètodes constructors 
          de la classe mare.
 
 
addWindowListener(new PWindowAdapter(this)); 
          El mètode public 
          void addWindowListener(WindowListener l), 
          que java.awt.Frame hereda 
          de java.awt.Window, 
          implementa el primer exemple que veiem en aquest curs del paradigma 
          esdeveniment-oient (event-listener), 
          propi de la programació OOP 
          (Object Oriented 
          Programming). En essència consisteix 
          en què un objecte és 
           "listener" 
          (oient) dels 
          esdeveniments 
          que passen a altres objectes. 
          Cada objecte emissor 
          d'esdeveniments interessants per a d'altres objectes 
          oients té una llista d'aquests objectes 
          oients i així "sap" a qui 
          ha d'avisar. Per afegir objectes oients 
          a aquesta llista hi ha els mètodes 
          addXXXXXListener. 
          En el nostre cas, l'objecte mainFrame 
          emetrà una 
          certa mena d'esdeveniment 
          quan premem el botonet de tancar la finestra i, llavors notificarà 
          aquest esdeveniment 
          als objectes 
          que té a la llista de listeners. 
          La línea que ens ocupa no fa altra cosa que afegir un objecte 
          PWindowAdapter a 
          la llista de listeners de 
          mainFrame. Naturalment, 
          la llista, que era buida en principi, ara tindrá només 
          un objecte. 
          La funció que fa PWindowAdapter en 
          rebre la notificació 
          ho veurem més avall. 
 
public static void main (String args[]) {} 
          és el mètode 
          main que ja hem discutit 
          abans.
 
class PWindowAdapter extends WindowAdapter { ... 
          } és la definició de la classe 
          PWindowAdapter, la qual 
          la definim com a filla de  java.awt.event.WindowAdapter.
 
Finestra02 
          mainFrame; Aquí és declara una 
          (l'única) variable de la classe. 
          El tipus 
          és Finestra02, 
          la classe principal de l'aplicació 
          i el nom, mainFrame, 
          és arbitrari. No hi ha perill de confusió amb la variable 
          mainFrame de la 
          classe Finestra02: 
          l'encapsulació 
          característica de l'OOP 
          garanteix que aquestes variables, malgrat tenir el mateix nom, no s'interferiran 
          mai! 
 
public PWindowAdapter (Finestra02 
          mFrame) { ... } és el mètode 
          constructor de la classe PWindowAdapter 
          i s'ajusta a allò que hem dit en parlar del mètode 
          constructor de la classe Finestra02. 
          En particular, la primera línia és la crida super().
 
this.mainFrame=mainFrame; 
          assigna (per referència, 
          no pas per còpia!) a la variable 
          de la classe mainFrame, 
          que era del tipus 
          Finestra02, l'objecte, 
          també de tipus Finestra02, 
          argument 
          del mètode constructor.
 Si ara tornem a la línia addWindowListener(new 
          PWindowAdapter(this));, podem entendre més 
          bé què fa: "Afegeix 
          a la llista dels qui escolten 
          a Finestra02 
          un nou objecte PWindowAdapter 
          amb l'argument el mateix Finestra02".
 
 Recordem: 
          quan, dins d'una classe, 
          calgui referir-se a la mateixa classe, 
          feu servir "this".
 
 
public void windowClosing(WindowEvent e) { ... 
          } aquest mètode 
          és el que s'executa quan PWindowAdapter 
          rep notificació 
          d'un esdeveniment java.awt.event.WindowEvent, 
          és a dir, quan mainFrame 
          li notifica 
          que li han apretat el botonet de tancar la finestra.
 
mainFrame.dispose(); destrueix 
          l'objecte mainFrame, 
          és a dir, n'esborra tota referència 
          i el passa al la llista del GC 
          per alliberar memòria.
 
System.exit(0); acaba 
          el programa i surt al sistema operatiu. | 
   
    |  |  | 
   
    |  | Compilació i execució | 
   
    |  |  | 
   
    |  | Compilem i executem i obtindrem 
      una finestra com la d'abans, però ara el botonet de tancar la finestra 
      ja respon! No només tanca 
      la finestra, sinó que acaba 
      l'aplicació. | 
   
    |  |  | 
   
    |  | Però... això és 
      d'una complicació de bojos! | 
   
    |  |  | 
   
    |  | Bé. Admetem que és força complicat aconseguir una 
        finestra que es tanqui quan premem, precisament, el botonet de tancar... 
        Però, com que això serà així a totes les finestres 
        arrel de les nostres aplicacions, 
        podem acudir a les habilitats de JCreator, 
        que a partir d'ara ens farà tota aquesta feina per nosaltres. | 
   
    |  |  | 
   
    |  | Automatitzant la feina... | 
   
    |  |  | 
   
    |  | 
        Al nostre  Workspace 
          Modul_5, hi creem 
          un nou projecte, ara amb el nom "Finestra03". 
          Com abans, pareu esmenta les majúscules 
          i les minúscules, 
          però ara farem servir l'opció "Basic 
          Java Application".
 
Llavors, JCreator 
          crea automàticament el fitxer Finestra03.java:
 
 
             
              | /* * @(#)Finestra03.java 1.0 02/09/11
 *
 * You can modify the template of this file in the
 * directory ..\JCreator\Templates\Template_1\Project_Name.java
 *
 * You can also create your own project template by making a new
 * folder in the directory ..\JCreator\Template\. Use the other
 * templates as examples.
 *
 */
 //package myprojects.Finestra03;
 import java.awt.*;import java.awt.event.*;
 class Finestra03 extends 
                  Frame {
 public Finestra03() 
                  {
 addWindowListener(new 
                  WindowAdapter() {
 public 
                  void windowClosing(WindowEvent e) {
 dispose();
 System.exit(0);
 }
 });
 }
      public static void 
                  main(String args[]) {System.out.println("Starting 
                  Finestra03...");
 Finestra03 mainFrame 
                  = new Finestra03();
 mainFrame.setSize(400, 
                  400);
 mainFrame.setTitle("Finestra03");
 mainFrame.setVisible(true);
 }
 }
 |  en el qual heu de comentar 
          la línia 12: package 
          myprojects.Finestra03;. Més endavant 
          ja practicarem a l'organitzar les nostres classes 
          en paquets 
          (packages).
 | 
   
    |  |  | 
   
    |  | Voilà! Jcreator ens ha fet tota 
        la feina! Només cal que, abans de compilar, 
        canviem els paràmetres dels mètodes 
        setSize i setTitle 
        per tal d'aconseguir una finestra com la d'abans! Compileu 
        i executeu...  | 
   
    |  |  | 
   
    |  | I a més ho ha fet de manera més elegant i comprimida: no 
        li ha calgut escriure un codi especial per a una classe 
        derivada de java.awt.event.WindowAdapter. 
        En el fragment de codi 
         
          | new 
            WindowAdapter() { public 
            void windowClosing(WindowEvent e) {
 dispose();
 System.exit(0);
 }
 }
 |  es crea una instància de 
        la classe java.awt.event.WindowAdapter 
        i s'hi sobreescriu el mètode 
        public void windowClosing(WindowEvent e), 
        per tal d'adaptar-lo a les necessitats de mainFrame, 
        encara que, essencialment, fa el mateix que hem fet nosaltres a la classe 
        Finestra02... | 
   
    |  |  | 
   
    |  | De tota manera, encara que ara ja sabem construir 
      la finestra bàsica d'una aplicació 
      de manera automàtica, calia fer la pràctica amb les 
      classes Finestra01 
      i Finestra02 per tal de poder introduir i començar 
      a discutir alguns dels conceptes que són essencials en la programació 
      Java... | 
   
    |  |  | 
   
    |  |  | 
   
    |  |  | 
   
    |  | 
   
    |  |  | 
   
    |  |  |