|  
      
     | 
     
       Fins ara (pràctiques 2, 3 
        i 4) coneixem i hem fet GUI's 
        que inclouen quatre tipus de controls: 
      
        - java.awt.Label
 
           
         
        - java.awt.Button
 
           
         
        - java.awt.Checkbox
 
           
         
        - java.awt.CheckboxGroup
 
       
      En aquesta pràctica n'introduirem quatre més:  
      
        - java.awt.List
 
           
         
        - java.awt.TextArea
 
           
         
        - java.awt.TextField
 
           
         
        - java.awt.Choice
 
       
      i, de passada, aprendrem una manera de fer que les nostres GUI's 
      siguin multilingües. Amb més 
      profunditat, això serà la manera de discutir els conceptes 
      de classe final i de mètodes 
      i variables static. 
      (Ja tocava, no?) | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
    Un editor de missatges: | 
  
   
    |   | 
      | 
  
   
      | 
     
       La nostra aplicació será una finestra, la qual contindrá: 
      
        - Dues zones on 
          l'usuari podrà escriure els noms respectius del destinatari i 
          del remitent del missatge
 
            
         
        - Dues llistes, 
          una per a encapçalaments i l'altra per a fórmules de comiat, 
          de les quals l'usuari podrà escollir les que li convinguin.
 
            
         
        - Una zona dedicada 
          a què l'usuari hi escrigui el text del missatge. L'encapçalament 
          i el comiat s'hi escriuen automàticament a partir de les seleccions 
          fetes als controls anteriors.
 
            
         
        - Un botó 
          de conformitat amb les seleccions.
 
            
         
        - Un botó 
          per enviar el missatge.
 
       
     | 
  
   
    |   | 
    L'aspecte en serà 
      aquest:  | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
     
       
        
          - Les etiquetes "Nom 
            del destinatari" i "Nom 
            del remitent" són labels 
            amb justificació java.awt.Label.RIGHT, 
            per tal que estiguin el més enganxades possible als camps 
            de text respectius de la seva dreta. També ho és 
            l'espai a l'esquerra del botó "Enviar". 
            Es tracta d'un label sense text.
 
              
           
          - Els botons "D'acord" 
            i "Enviar" són instàncies 
            de java.awt.Button.
 
              
           
          - TextFields: 
            Els camps de text on ara hi ha escrit 
            "Julieta" i "Romeu" 
            són instàncies de la 
            classe java.awt.TextField.
 
             
            La classe java.awt.TextField 
            representa una línia de text editable. 
            Els mètodes per manipular 
            el text són: 
             
            
              - public String getText(), 
                que retorna el text (cadena, 
                string) que hi hagi escrit al 
                TextField
 
                 
                  
              - public void setText(String 
                t), que situa la cadena 
                (string) t 
                en el TextField.
 
                 
                  
             
            La classe java.awt.TextField 
            és capaç d'emetre esdeveniments 
            java.awt.event.ActionEvent quan hom prem 
            la tecla "Retorn" 
            del teclat. Per tant, té, 
            com era d'esperar, un mètode 
            public void addActionListener(ActionListener l)per 
            poder afegir listeners que l'escoltin. 
            En aquest sentit, es comporta exactament com java.awt.Button, 
            que ja ha estat utilitzat per nosaltres.. 
             
              
          - TextArea: La 
            zona de text destinada a ser escrita 
            per l'usuari són instàncies 
            de la classe java.awt.TextArea.
 
             
            La classe java.awt.TextArea 
            representa una zona de text editable, 
            que pot tenir vàries línies. 
            El text no es justifica. i, 
            si la quantitat de text ho requereix, s'activen scrollbars 
            horitzontals i/o verticals. Els mètodes 
            per manipular el text són iguals que els de java.awt.TextField: 
             
            
              - public String getText(), 
                que retorna el text (cadena, 
                string) que hi hagi escrit al 
                TextField
 
                 
                  
              - public void setText(String 
                t), que situa la cadena 
                (string) t 
                en el TextField.
 
                 
                  
             
            Com que hi ha la possibilitat de canvis 
            de línia, podem incloure a les cadenes 
            de text el caràcter de control 
            "\n" amb garantia que tindrà 
            efecte. 
             
              
          - Llistes: Les 
            dues llistes d'ítems a seleccionar 
            per l'usuari que hi ha a l'esquerra de la zona 
            de text són instàncies 
            de la classe java.awt.List.
 
             
            La classe java.awt.List 
            representa una llista d'ítems per 
            seleccionar, i segons com es construeixi, 
            admet selecció múltiple, 
            és a dir, de més d'un ítem 
            a la vegada. Si els textos o la quantitat d'items 
            ho requereixen, s'activen scrollbars 
            horitzontals i/o verticals. Els mètodes 
            principals per manipular els ítems 
            són: 
             
            
              - public void add(String 
                item), que afegeix un ítem 
                amb el text item al final de la llista.
 
                 
                  
              - public String getSelectedItem(), 
                que retorna la cadena (string) 
                de text que hi hagi a l'ítem 
                seleccionat.
 
                 
                  
              - public void select(int 
                index), que selecciona 
                l'ítem a la posició 
                index (la de dalt de tot és la 
                posició zero). 
 
                 
                  
              - public void removeAll(), 
                que elimina tots els ítems 
                i deixa la llista buida.
 
                 
                  
             
            La classe java.awt.List 
            emet esdeveniments java.awt.event.ItemEvent 
            quan es canvia la selecció. 
            Té, per tant, un mètode 
            public void addItemListener(ItemListener l), 
            per poder afegir listeners que escoltin 
            aquests esdeveniments. 
             
            La classe java.awt.List, 
            a més, és capaç d'emetre 
            esdeveniments java.awt.event.ActionEvent 
            quan hom fa un doble click sobre 
            un dels seus ítems, que queda, 
            a més, seleccionat. Per això, 
            ha de tenir i té, un mètode 
            public void addActionListener(ActionListener l), 
            que permet afegir listeners que l'escoltin. 
         
       
     | 
  
   
    |   | 
     
       Amb aquests elements construirem l'aplicació 
        Missatgeria01 amb el funcionament següent: 
      
        - Als camps de text 
          superiors l'usuari hi posarà (si vol) els noms del destinatari 
          i del remitent del missatge. Els valors quedaran validats 
          en prèmer la tecla "Retorn" 
          o en prèmer el botó "D'acord".
 
           
            
        - De les dues llistes 
          de l'esquerra, l'usuari seleccionarà 
          els tractaments de cortesia tant per la introducció com pel comiat. 
          Les seleccions es validen, 
          o bé per doble click sobre un 
          ítem, o bé mitjançant 
          el botó "D'acord"
 
           
            
        - L'usuari confegeix el text del missatge a l'àrea 
          de text i, després, mitjançant el botó 
          "Enviar", l'"envia" 
          al destinatari. Aquí, "enviar el missatge" consistirà 
          en què aparegui escrit a la sortida 
          standard del sistema.
 
       
     | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
    Creem, doncs, el projecte 
      Missatgeria01 amb aquest fitxer 
      Missatgeria01.java: | 
  
   
    |   | 
      | 
  
   
    |   | 
     
       /* 
        * @(#)Missatgeria01.java 1.0 02/09/28 
        * 
        * 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.missatgeria01; 
      import java.awt.*; 
        import java.awt.event.*; 
      class Missatgeria01 extends Frame { 
         
        public Missatgeria01() { //constructor 
     | 
  
   
    |   | 
             setBackground(Color.LIGHT_GRAY); 
              ElMeuPanel panel=new ElMeuPanel(); 
              add(panel,BorderLayout.CENTER); | 
  
   
    |   | 
             addWindowListener(new 
      WindowAdapter() { 
                  public 
      void windowClosing(WindowEvent e) { 
                      dispose(); 
                      System.exit(0); 
                  } 
              }); 
          } 
           public static void main(String args[]) { 
                System.out.println("Starting 
        Missatgeria01..."); 
                Missatgeria01 mainFrame 
        = new Missatgeria01(); 
     | 
  
   
    |   | 
             mainFrame.setSize(600, 
      300); 
              mainFrame.setTitle("Missatgeria"); | 
  
   
    |   | 
             mainFrame.setVisible(true); 
          } 
      } 
     | 
  
   
    |   | 
    class 
      ElMeuPanel extends Panel implements ActionListener { 
       
          Label labelNomDestinatari; 
          Label labelNomRemitent; 
          TextField fieldNomDestinatari; 
          TextField fieldNomRemitent; 
          Button ok; 
          Button enviar; 
          List listInici; 
          List listFinal; 
          TextArea text; 
           public ElMeuPanel() { //constructor 
                super(); 
                setLayout(new BorderLayout()); 
         
                Panel panelNord=new Panel(); 
                panelNord.setLayout(new 
        BorderLayout()); 
               Panel panelLabels=new 
        Panel(); 
                panelLabels.setLayout(new 
        GridLayout(2,1)); 
         
                labelNomDestinatari=new 
        Label("Nom del destinatari:", 
                                               Label.RIGHT); 
                labelNomRemitent=new Label("Nom 
        del remitent: ", 
                                            Label.RIGHT); 
                panelLabels.add(labelNomDestinatari); 
                panelLabels.add(labelNomRemitent); 
         
                panelNord.add(panelLabels,BorderLayout.WEST); 
               Panel panelNoms=new 
        Panel(); 
                panelNoms.setLayout(new 
        GridLayout(2,1)); 
         
                fieldNomDestinatari=new 
        TextField(); 
                fieldNomDestinatari.addActionListener(this); 
         
                fieldNomRemitent=new TextField(); 
                fieldNomRemitent.addActionListener(this); 
         
                panelNoms.add(fieldNomDestinatari); 
                panelNoms.add(fieldNomRemitent); 
         
                panelNord.add(panelNoms,BorderLayout.CENTER); 
               ok=new Button("D'acord"); 
                ok.addActionListener(this); 
         
                panelNord.add(ok,BorderLayout.EAST); 
         
                add(panelNord,BorderLayout.NORTH); 
               text=new TextArea(""); 
                add(text,BorderLayout.CENTER); 
         
                Panel panelCortesia=new 
        Panel(); 
                panelCortesia.setLayout(new 
        GridLayout(2,1)); 
               listInici=new List(9); 
                listInici.add(""); 
                listInici.add("Apreciat 
        "); 
                listInici.add("Apreciada 
        "); 
                listInici.add("Benvolgut 
        "); 
                listInici.add("Benvolguda 
        "); 
                listInici.add("Estimat 
        "); 
                listInici.add("Estimada 
        "); 
                listInici.add("Caríssim 
        "); 
                listInici.add("Caríssima 
        "); 
                listInici.select(1); 
                listInici.addActionListener(this); 
         
                panelCortesia.add(listInici); 
               listFinal=new List(7); 
                listFinal.add(""); 
                listFinal.add("Cordialment"); 
                listFinal.add("Una 
        abraçada"); 
                listFinal.add("Teu"); 
                listFinal.add("Teva"); 
                listFinal.add("Sempre 
        teu"); 
                listFinal.add("Sempre 
        teva"); 
                listFinal.select(1); 
                listFinal.addActionListener(this); 
         
                panelCortesia.add(listFinal); 
               add(panelCortesia,BorderLayout.WEST); 
         
                Panel panelSur=new Panel(); 
                panelSur.setLayout(new 
        GridLayout(1,2)); 
         
                panelSur.add(new Label("")); 
         
                enviar=new Button("Enviar"); 
                enviar.addActionListener(this); 
         
                panelSur.add(enviar); 
         
                add(panelSur,BorderLayout.SOUTH); 
            } 
         
            public void actionPerformed(ActionEvent e) { 
                Object objAction=e.getSource(); 
                    if 
        (objAction instanceof TextField || 
                        objAction 
        instanceof List) { 
                        preparaText(); 
                    } 
        else if (objAction instanceof Button) { 
                        if(objAction==ok) 
        { 
                            preparaText(); 
                        } 
        else if(objAction==enviar) { 
                            enviaMissatge(); 
                        } 
                    } 
            } 
         
            public void preparaText () { 
                text.setText(listInici.getSelectedItem()+ 
                             
        fieldNomDestinatari.getText()+ 
                             
        ",\n\n<text de la nota>\n\n"+ 
                             
        listFinal.getSelectedItem()+ 
                             
        ",\n "+ 
                             
        fieldNomRemitent.getText()); 
            } 
         
            public void enviaMissatge() { 
                System.out.println(text.getText()); 
            } 
      } 
     | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
    Observem: | 
  
   
    |   | 
      | 
  
   
      | 
     
      
        - L'estructura de contenidors 
          (panels) niuats amb els seus layout 
          managers: 
 
           
          
            - mainFrame, instància 
              de java.awt.Frame
 
               
               
            - panel, instància 
              de ElMeuPanel, classe 
              filla de java.awt.Panel
 
               
               
            - panelNord, instància 
              de java.awt.Panel
 
               
               
            - panelLabels, instància 
              de java.awt.Panel
 
               
               
            - panelNoms, instància 
              de java.awt.Panel
 
               
               
            - panelCortesia, instància 
              de java.awt.Panel
 
               
               
            - panelSur, instància 
              de java.awt.Panel
 
               
               
           
          Convindrà ara que ara fem un mapa d'aquesta estructura 
          dels contenidors i controls 
          que hi ha a cadascun d'aquests contenidors... 
           
           
        - Tots els controls, 
          excepte els labels i l'àrea 
          de text, veuen els esdeveniments 
          que emeten capturats per un únic 
          listener, que és la classe 
          ElMeuPanel. Això és així 
          perquè per a cadascun d'aquests controls 
          hem executat el mètode control.addActionListener(this).(Qüestió: 
          a què es refereix la clàusula 
          "this"?).
 
           
          Com que s'emetran esdeveniments java.awt.ActionEvent, 
          la classe ElMeuPanel 
          ha d'implementar la interface 
          java.awt.event.ActionListener i, en conseqüència, 
          el mètode public 
          void actionPerformed(ActionEvent e). 
           
           
        - Quan es produeix l'esdeveniment, 
          llavors s'executa el mètode 
          public void actionPerformed(ActionEvent e) 
          i per determinar quines accions cal fer, és necessari saber quin 
          control n'és l'emissor. Aquí 
          n'hem fet una primera identificació 
          per tipus (la clàusula 
          "instanceof") i, després, 
          com que hi ha dos botons, els 
          hem distingit simplement per referència 
          als seus noms (l'operador relacional 
          "==").
 
           
           
        - En lloc de descriure les accions a fer dintre del 
          mateix mètode public 
          void actionPerformed(ActionEvent e), és molt millor cridar 
          a d'altres mètodes especialitzats: 
          public void preparaText () per a la incorporació 
          de les opcions escollides per l'usuari i public void 
          enviaMissatge() per "enviar" efectivament el 
          missatge. Això fa guanyar intel·ligibilitat al codi i 
          permet facilitar-ne la modificació i millora.
 
       
     | 
  
   
    |  
      
     | 
     
         
     | 
  
   
    |  
      
     | 
    Un altre control: la 
      classe java.awt.Choice: | 
  
   
    |   | 
      | 
  
   
      | 
     
       La classe java.awt.Choice 
        representa un menú desplegable amb una 
        llista d'ítems per seleccionar. L'item 
        seleccionat apareix com a títol 
        del choice. Els mètodes 
        principals per manipular els ítems 
        són: 
       
      
        - public void add(String item), 
          que afegeix un ítem amb el text 
          item al final de la llista.
 
           
           
        - public String getSelectedItem(), 
          que retorna la cadena (string) 
          de text que hi hagi a l'ítem seleccionat.
 
           
           
        -  public int getSelectedIndex(), 
          que retorna la posició (index) 
          de l'ítem seleccionat (la de 
          dalt de tot és la posició zero). 
 
           
           
        - public void select(int index), 
          que selecciona l'ítem 
          a la posició index 
 
           
           
        - public void removeAll(), 
          que elimina tots els ítems i 
          deixa el choice buit.
 
           
       
      La classe java.awt.Choice 
      emet esdeveniments java.awt.event.ItemEvent 
      quan es canvia la selecció. Naturalment, 
      per poder afegir listeners que escoltin 
      aquests esdeveniments, té un mètode 
      public void addItemListener(ItemListener l). | 
  
   
    |   | 
     
         
     | 
  
   
    |  
      
     | 
    Per tal de fer funcionar 
      un choice, ara farem una petita variació 
      del nostre gestor de missatges. Afegirem un choice 
      a la dreta del botó "enviar" 
      que ens ha de permetre seleccionar l'idioma 
      en el qual se'ns presentaran els títols, les etiquetes i les opcions 
      entre català, castellà i anglès. Aquí el teniu 
      en l'"estat llengua anglesa": | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
  
   
    |   | 
      | 
  
   
    |   | 
    La funcionalitat ha de 
      consistir en què, quan seleccionem 
      un idioma determinat, inmediatament quedaran traduïts a aquesta nova 
      llengua tots els textos dels labels, botons, 
      lists i els del propi choice. | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
    Com hem fet abans,podríem 
      incloure els textos traduïbles en algun lloc del 
      fitxer Missatgeria01 (en aquest fitxer 
      els textos són a cadascuna de les definicions 
      dels controls, al mètode constructor 
      de la classe ElMeuPanel) 
      , però és molt més elegant i pràctic situar 
      tots aquests textos en un fitxer *.java 
      apart, i procurar que el funcionament dels mètodes 
      al fitxer principal sigui independent de 
      la quantitat d'idiomes i d'eleccions que hi hagi al fitxer 
      de textos. Això vol dir que per afegir noves opcions o nous 
      idiomes, només caldrà manipular aquest fitxer 
      de textos tot deixant intacte el fitxer 
      principal. | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
    Fem ara un nou 
      projecte, Missatgeria02, com a "Basic 
      Java Application" i, després de comprovar que, com sempre, 
      s'ha creat el fitxer Missatgeria02.java, 
      que és el fitxer principal, hem 
      d'afegir aquest fitxer, "Etiquetes.java", 
      al projecte que en serà el fitxer 
      de textos: | 
  
   
    |   | 
      | 
  
   
    |   | 
    public 
      final class Etiquetes { 
          public static int idiomaInicial=0; 
       
          public static String[] titolFrame={"Missatgeria", 
                                             "Mensajería", 
                                             "Messages"}; 
       
          public static String[] nomTo={"Nom del destinatari: 
      ", 
                                        "Nombre 
      del destinatario: ", 
                   
                           "To 
      "}; 
       
          public static String[] nomFrom={"Nom del remitent: 
      ", 
                                          "Nombre 
      del remitente: ", 
                                          "From 
      "}; 
       
          public static String[][] hi={{" ","Apreciat 
      ", 
                                        "Apreciada 
      ","Benvolgut ", 
                                        "Benvolguda 
      ","Estimat ", 
                                        "Estimada 
      ","Caríssim ", 
                                        "Caríssima 
      "}, 
                                       {" 
      ","Apreciado ", 
                                        "Apreciada 
      ","Querido ", 
                                        "Querida 
      ","Estimado ", 
                                        "Estimada 
      ","Carísimo ", 
                                        "Carísima 
      "}, 
                                       {" 
      ","Dear "}}; 
       
          public static String[] espaiText={"text de 
      la nota", 
                                            "texto 
      de la nota", 
                                            "message 
      text"}; 
       
          public static String[][] bye={{" ","Cordialment", 
                                         "Una 
      abraçada","Teu", 
                                         "Teva","Sempre 
      teu", 
                                         "Sempre 
      teva"}, 
                                        {" 
      ","Cordialmente", 
                                         "Un 
      abrazo","Tuyo", 
                                         "Tuya","Siempre 
      tuyo", 
                                         "Siempre 
      tuya"}, 
                                        {" 
      ","Greetings", 
                                         "Yours","My 
      best wishes"}};  
           public 
        static String[] ok={" D'acord "," Sí "," 
        Ok "}; 
         
            public static String[][] 
        idiomes={{"Català","Castellà", 
                                               "Anglès"}, 
                                              {"Catalán","Español", 
                                               "Inglés"}, 
                                              {"Catalan","Spanish", 
                                               "English"}}; 
         
            public static String[] 
        enviar={"Enviar","Enviar","Send"}; 
        } 
     | 
  
   
    |   | 
      | 
  
   
      | 
    Public, static, final, 
      arrays...  | 
  
   
    |   | 
      | 
  
   
    |   | 
     
       Bé. Ha arribat el moment de repassar alguns conceptes... 
      
        - La classe Etiquetes 
          ha estat definida mitjançant les clàusules 
          "public" i "final". 
          Què vol dir això?
 
           
          
            - La clàusula 
              public implica que allò 
              a què s'aplica (classes, 
              variables o mètodes) 
              és accessible pels mètodes 
              de qualsevol altre objecte de l'aplicació 
              en funcionament. Si no definim la classe 
              Etiquetes amb la clàusula 
              "public", el seu contingut resultaria 
              inaccessible per qualsevol dels mètodes 
              de les classes del fitxer 
              M4p5_02.java!
 
               
              Respecte a la visibilitat/accessibilitat 
              de classes, variables 
              i mètodes, Java 
              ens ofereix tres possibilitats, expressades en les corresponents 
              tres clàusules: 
               
              
                - public: (classes, 
                  variables i mètodes) 
                  L'element corresponent és visible 
                  i accessible des de qualsevol 
                  altre element de l'aplicació.
 
                   
                   
                - protected: (variables 
                  i mètodes) L'element 
                  definit així només és visible 
                  i accessible des de la pròpia 
                  classe i des de les classes 
                  filles.
 
                   
                   
                - private: (variables 
                  i mètodes) L'element 
                  definit així definit és visible 
                  i accessible des de la pròpia 
                  classe, però no des 
                  de les classes filles.
 
               
               
              Si no s'especifica cap d'aquestes tres cláusules, 
              llavors l'element només és visible 
              i accessible pels objectes 
              el codi dels quals és al mateix fitxer 
              *.java que el de l'element en qüestió. 
               
              Ara ja podeu veure que hem estat força generosos repartint 
              clàusules "public" 
              als mètodes de les classes 
              definides a M4p5_02.java, les quals són 
              totes supèrflues. Però és una bona pràctica 
              posar-les sempre que preveiem que algun objecte 
              voldrà accedir a 
              aquesta classe, variable 
              o mètode. 
               
               
            - Si una classe es 
              defineix com a "public", llavors 
              ha de ser la primera de les classes 
              definides en el fitxer *.java, 
              el qual ha de tenir exactament el mateix 
              nom que la classe. (Qüestió: 
              un fitxer *.java pot contenir més 
              d'una classe pública?)
 
               
               
            - La clàusula 
              "static" s'aplica a variables 
              i mètodes. Significa que 
              aquests variable o mètode 
              de la classe mare 
              són accessibles i/o executables 
              sense necessitat que aquesta classe 
              hagi estat instanciada en un objecte. 
              Les variables static 
              venen a jugar el paper de les constants 
              de C (a Java 
              no hi ha precompilació i 
              per tant, no existeix la clàusula 
              #define) i els mètodes 
              static venen a ser les 
              funcions de llibreries de C 
              (a java tampoc hi ha la fitxers 
              de capçalera i, per tant, no hi ha la clàusula 
              #include).
 
               
              Observeu que, a diferència de la crida 
              a mètodes no static, 
              en la qual es fa: 
               
              
                 
                  | <nom de l'objecte>.elMetodeQue 
                    Sigui( ... ) | 
                 
               
               
              a la crida a mètodes 
              static es fa: 
               
              
                 
                  | <nom de la classe>.elMetodeQue 
                    Sigui( ... ) | 
                 
               
               
              Ara ja podem entendre una mica perquè el mètode 
              main(String[] args); és, precisament, 
              static: quan l'aplicació comença 
              a executar-se, encara no s'ha construït 
              cap objecte. Com que el 
              primer mètode que crida 
              la Màquina Virtual és 
              main(String[] args); és clar que 
              aquest ha de ser static per força! 
              Observeu que main(String[] args); una 
              de les primeres coses que fa és construir 
              una instància de la seva 
              mateixa classe (mainFrame 
              en els nostres exemples) i, a partir d'aquí, tots els altres 
              mètodes es criden 
              com a pertanyents a l'objecte (mainFrame), 
              no pas a la classe (M2px_xx). 
               
               
            - A vegades convé que, d'una classe,no 
              en puguem derivar classes filles 
              (això n'augmenta l'eficiència). Llavors es defineix 
              mitjançant la clàusula 
              "final", la qual prohibeix que 
              poguem construir-ne classes filles. 
              Normalment, una classe final 
              no té mètodes constructors 
              i totes les variables i mètodes 
              accessibles són static.
 
               
               
           
          El nostre fitxer de textos, que té 
          la única funcionalitat d'emmagatzemar els textos de la GUI 
          de l'aplicació, es defineix 
          doncs com a public (per tal que sigui accessible) 
          i final (per tal que no se'n puguin fer 
          instàncies ni fer-ne subclasses 
          o classes filles). El seu paper en 
          la nostra aplicació, comparat amb la construcció equivalent 
          de C, és el d'un fitxer 
          de capçalera amb definició de constants. 
          Totes les variables (constants 
          si fós C) són static. 
           
           
        - Com que per a cadascun dels 
          idiomes hi ha una possibilitat per a cada text, els textos s'enmagatzemen 
          en matrius (arrays). 
          No oblidem que, a Java, totes les variables es passen als mètodes 
          per referència i no per valor (no hi ha apuntadors!). En consequència, 
          al declarar les variables segons el tipus, cal especificar si ens referim 
          a un sol valor o a un array de valors:
 
           
          
            - nom_de_tipus: 
              declarem un sol valor.
 
               
               
            - nom_de_tipus[]: 
              declarem un array simple (lineal) 
              de valors. Els índexos 
              comencen per 0.
 
               
               
            - nom_de_tipus[][]: 
              declarem un array rectangular de 
              valors, que no és més 
              que un array lineal d'arrays 
              lineals. Els respectius índexos 
              comencen per 0.
 
               
               
            - nom_de_tipus[][][]: 
              declarem un array cúbic 
              de valors.
 
               
               
            - etc.
 
               
               
           
          Els valors continguts a nom_de_tipus[] 
          elMeuArray es criden mitjançant 
          elMeuArray[index], els valors 
          continguts a nom_de_tipus[][] elMeuArray es 
          criden mitjançant 
          elMeuArray[index_0][index_1], etc. 
       
     | 
  
   
    |  
      
     | 
    Ara ja ha de quedar clar 
      el codi del fitxer 
      Etiquetes.java. La variable 
      idiomaInicial és un enter 
      (int) posat inicialment a 0, 
      que representa els tres idiomes: 0 pel català, 
      1 pel castellà i 2 
      per l'anglès. idiomaInicial actuarà 
      com a índex dels arrays 
      de textos (fixeu-vos en l'ordenació a cada array!) | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
    I ja podem escriure el 
      fitxer principal (projecte 
      Missatgeria02) . Consisteix essencialment en el 
      mateix codi de Missatgeria01 amb les variacions 
      que expliquem al final. Només hem marcat amb color groc les parts 
      de codi que difereixen del de Missatgeria01: | 
  
   
    |   | 
      | 
  
   
    |   | 
    /* 
      * @(#)Missatgeria02.java 1.0 02/09/29 
      * 
      * 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.missatgeria02;  
      import java.awt.*; 
        import java.awt.event.*; 
      class Missatgeria02 extends Frame { 
         
            public Missatgeria02() { 
        //constructor 
                setBackground(Color.LIGHT_GRAY); 
     | 
  
   
    |   | 
             ElMeuPanel 
      panel=new ElMeuPanel(this); | 
  
   
    |   | 
             add(panel,BorderLayout.CENTER); 
              addWindowListener(new WindowAdapter() 
      { 
                  public 
      void windowClosing(WindowEvent e) { 
                      dispose(); 
                      System.exit(0); 
                  } 
              }); 
          } 
           public static void main(String args[]) { 
                System.out.println("Starting 
        Missatgeria02..."); 
                Missatgeria02 mainFrame 
        = new Missatgeria02(); 
                mainFrame.setSize(600, 
        300); 
                mainFrame.setVisible(true); 
            } 
        } 
       
     | 
  
   
    |   | 
    class 
      ElMeuPanel extends Panel implements ActionListener, 
                                                ItemListener 
      { 
       
          Missatgeria02 mainFrame;  | 
  
   
    |   | 
         Label 
      labelNomDestinatari; 
          Label labelNomRemitent; 
          TextField fieldNomDestinatari; 
          TextField fieldNomRemitent; 
          Button ok; 
          Button enviar; 
          List listInici; 
          List listFinal; 
          TextArea text; | 
  
   
    |   | 
         int 
      numIdioma=Etiquetes.idiomaInicial; 
          Choice idioma; 
           public ElMeuPanel(Missatgeria02 f) { 
        //constructor 
     | 
  
   
    |   | 
             super(); | 
  
   
    |   | 
             mainFrame=f; | 
  
   
    |   | 
             setLayout(new 
      BorderLayout()); 
       
              Panel panelNord=new Panel(); 
              panelNord.setLayout(new 
      BorderLayout()); 
               Panel panelLabels=new 
        Panel(); 
                panelLabels.setLayout(new 
        GridLayout(2,1)); 
     | 
  
   
    |   | 
             labelNomDestinatari=new 
      Label("",Label.RIGHT); 
              labelNomRemitent=new Label("",Label.RIGHT); | 
  
   
    |   | 
             panelLabels.add(labelNomDestinatari); 
              panelLabels.add(labelNomRemitent); 
              panelNord.add(panelLabels,BorderLayout.WEST); 
               Panel panelNoms=new 
        Panel(); 
                panelNoms.setLayout(new 
        GridLayout(2,1)); 
                fieldNomDestinatari=new 
        TextField(); 
                fieldNomDestinatari.addActionListener(this); 
                fieldNomRemitent=new TextField(); 
                fieldNomRemitent.addActionListener(this); 
                panelNoms.add(fieldNomDestinatari); 
                panelNoms.add(fieldNomRemitent); 
                panelNord.add(panelNoms,BorderLayout.CENTER); 
       
     | 
  
   
    |   | 
             ok=new 
      Button(); | 
  
   
    |   | 
             ok.addActionListener(this); 
              panelNord.add(ok,BorderLayout.EAST); 
              add(panelNord,BorderLayout.NORTH); 
               text=new TextArea(""); 
                add(text,BorderLayout.CENTER); 
         
                Panel panelCortesia=new 
        Panel(); 
                panelCortesia.setLayout(new 
        GridLayout(2,1)); 
       
     | 
  
   
    |   | 
             listInici=new 
      List(); | 
  
   
    |   | 
             listInici.addActionListener(this); 
              panelCortesia.add(listInici); 
     | 
  
   
    |   | 
             listFinal=new 
      List(); | 
  
   
    |   | 
             listFinal.addActionListener(this); 
              panelCortesia.add(listFinal); 
               add(panelCortesia,BorderLayout.WEST); 
         
                Panel panelSur=new Panel(); 
                panelSur.setLayout(new 
        GridLayout(1,2)); 
       
     | 
  
   
    |   | 
             idioma=new 
      Choice(); 
              idioma.addItemListener(this); 
              panelSur.add(idioma); 
       
              enviar=new Button(); | 
  
   
    |   | 
             enviar.addActionListener(this); 
              panelSur.add(enviar); 
       
              add(panelSur,BorderLayout.SOUTH); 
     | 
  
   
    |   | 
             canviaIdioma(); | 
  
   
    |   | 
         } 
       
          public void actionPerformed(ActionEvent e) { 
              Object objAction=e.getSource(); 
                  if 
      (objAction instanceof TextField || 
                      objAction 
      instanceof List) { 
                      preparaText(); 
                  } 
      else if (objAction instanceof Button) { 
                          if(objAction==ok) 
      { 
                              preparaText(); 
                          } 
      else if(objAction==enviar) { 
                              enviaMissatge(); 
                          } 
                  } 
          } 
     | 
  
   
    |   | 
         public 
      void itemStateChanged(ItemEvent e) { 
              numIdioma=idioma.getSelectedIndex(); 
              canviaIdioma(); 
          } 
       
          public void canviaIdioma() { 
              mainFrame.setTitle(Etiquetes.titolFrame[numIdioma]); 
              labelNomDestinatari.setText(Etiquetes.nomTo[numIdioma]); 
              labelNomRemitent.setText(Etiquetes.nomFrom[numIdioma]); 
              ok.setLabel(Etiquetes.ok[numIdioma]); 
              listInici.removeAll(); 
              int totalHis=Etiquetes.hi[numIdioma].length; 
                  for 
      (int i=0;i<totalHis;i++) { 
                      listInici.add(Etiquetes.hi[numIdioma][i]); 
                  } 
              listInici.select(1); 
              listFinal.removeAll(); 
              int totalByes=Etiquetes.bye[numIdioma].length; 
                  for 
      (int i=0;i<totalByes;i++) { 
                      listFinal.add(Etiquetes.bye[numIdioma][i]); 
                  } 
              listFinal.select(1); 
              idioma.removeAll(); 
              int totalIdiomes=Etiquetes.idiomes.length; 
                  for 
      (int i=0;i<totalIdiomes;i++) { 
                      idioma.add(Etiquetes.idiomes[numIdioma][i]); 
                  } 
              idioma.select(numIdioma); 
              enviar.setLabel(Etiquetes.enviar[numIdioma]); 
              preparaText(); 
              mainFrame.validate(); 
          } 
     | 
  
   
    |   | 
         public 
      void preparaText () { 
              text.setText(listInici.getSelectedItem()+ 
                           fieldNomDestinatari.getText()+ | 
  
   
    |   | 
                          ",\n\n 
      < . . . "+ 
                           Etiquetes.espaiText[numIdioma]+ 
                           " 
      . . . >\n\n"+ | 
  
   
    |   | 
                          listFinal.getSelectedItem()+ 
                           ",\n 
      "+ 
                           fieldNomRemitent.getText()); 
          } 
       
          public void enviaMissatge() { 
              System.out.println(text.getText()); 
          } 
       
      } | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
    Observem i entenguem... | 
  
   
    |   | 
      | 
  
   
      | 
     
      
        - Hem mantingut ElMeuPanel 
          com a únic listener de tots 
          els esdeveniments.
 
           
           
        - La finestra mainFrame, 
          que conté el panel ElMeuPanel 
          té un títol que cal que, 
          al demanar canvi d'idioma, també canviï. Per tal que el 
          mètode per canviar l'idioma 
          (public void canviaIdioma()) de ElMeuPanel 
          (que és l'únic listener) 
          pugui referir-se al mainFrame 
          que el conté, cal que ElMeuPanel 
          "sàpiga" qui és aquest Missatgeria02. 
          Per tant, ElMeuPanel ha de tenir una variable 
          de classe (Missatgeria02 mainFrame) 
          que contingui la referència 
          al Missatgeria02 contenidor. 
          Aquesta referència li passa 
          el mètode constructor de ElMeuPanel 
          que ara, en lloc de no tenir paràmetres, 
          té un paràmetre Missatgeria02.
 
           
           
        - La classe ElMeuPanel 
          ha de ser listener d'esdeveniments, 
          tant java.awt.event.ActionEvent com 
          java.awt.event.ItemEvent. Per tant ha de ser definida 
          tot implementant les dues 
          interfaces java.awt.event.ActionListener 
          i java.awt.event.ItemListener. Vegeu la sintaxi 
          de la implementació, a la qual, 
          a la clàusula implements 
          hi segueixen els noms de les interfaces 
          separades per ",".
 
           
           
        - La variable 
          int numIdioma s'inicialitza 
          amb el valor que hi ha definit a Etiquetes.
 
           
           
        - Els controls (labels, 
          camps de text, àrea 
          de text, lists i el choice 
          per a l'idioma) es construeixen sense 
          textos ni ítems d'opció. 
          Igualment, el títol del mainFrame 
          és buit. Es reserva la càrrega dels textos 
          i dels ítems 
          al mètode public 
          void canviaIdioma(), el qual actuarà tant al fer una nova 
          selecció al choice, com 
          en el moment inicial, abans de la presentació de la GUI 
          a la pantalla.
 
           
           
        - Com que mainFrame és 
          ItemListener, ha d'implementar 
          el mètode public 
          void itemStateChanged(ItemEvent e). No cal identificar l'origen 
          dels esdeveniments i només cal 
          fixar el nou valor de numIdioma 
          a partir de la lectura del choice, 
          i cridar al mètode per canviar 
          l'idioma (public void canviaIdioma()).
 
           
           
        - El mètode 
          public void canviaIdioma() consisteix en determinar 
          els textos dels controls a partir del 
          valor de l'índex numIdioma i 
          dels valors de les 
          variables static de la classe 
          Etiquetes:
 
           
          
            - El títol 
              del mainFrame es fixa mitjançant 
              el mètode public 
              void setTitle(String title) (classe 
              java.awt.Frame).
 
               
               
            - El text dels 
              labels es fixa mitjançant el mètode 
              public void setText(String text) (classe 
              java.awt.Label).
 
               
               
            - El text dels 
              botons es fixa mitjançant el mètode 
              public void setLabel(String text) (classe 
              java.awt.Button). 
 
               
               
            - Els lists 
              i el choice tenen un tractament 
              una mica més complicat:
 
               
              
                - Es comença per buidar-los 
                  amb el mètode public 
                  void removeAll() (classes 
                  java.awt.List i java.awt.Choice)
 
                   
                   
                - Ara cal saber el nombre 
                  d'ítems que han de contenir cadascun d'ells. Això 
                  ho fem mitjançant la variable 
                  length que està associada a 
                  qualsevol array. Observeu que 
                  això fa que no sigui necessari tenir el mateix nombre 
                  d'ítems per a cada idioma i que puguem modificar 
                  el nombre d'ítems 
                  al fitxer Etiquetes.java 
                  sense comprometre el funcionament del programa.
 
                   
                   
                - Finalment, només cal omplir els 
                  list i el choice 
                  mitjançant sengles estructures 
                  de control for() { ... }, controlades 
                  pel nombre d'ítems llegit 
                  abans.
 
                   
                   
               
               
            - I, finalment, després de posar el text 
              adequat a l'àrea de text, 
              una línia de codi molt, 
              molt important:
 
               
              
               
              El mètode public 
              void validate() de la classe 
              java.awt.Container (i, per tant, de totes 
              les seves subclasses o classes 
              filles, com ara java.awt.Frame 
              i java.awt.Panel) té, com a efecte, 
              redisposar (to lay out) tots els 
              components d'un container 
              i, si algun o alguns d'aquests components 
              també és un container, 
              redisposar-ne els components) tot 
              adaptant-se a les noves condicions després d'un canvi. En 
              el nostre exemple, hi ha un label amb 
              el text "Nom del destinatari: " (llarg) 
              que, al passar a l'anglès es converteix en "To: 
              " (curt). Si ometem mainFrame.validate(), 
              llavors els textos canvien, però no les dimensions 
              dels controls que els contenen. Això no és 
              greu al passar del català a l'anglès (el label 
              queda massa gros), però sí si hem començat 
              en anglès i passem al català (el label 
              queda petit i el nou text no hi cap. Proveu-ho! 
           
           
       
     | 
  
   
    |   | 
      | 
  
   
    |  
      
     | 
    Déu n'hi dó, 
      oi?  | 
  
   
    |   | 
      | 
  
   
    |   | 
      | 
  
   
    |   | 
      | 
  
   
    |   | 
     
      
     | 
  
   
      | 
  
  
    |   | 
      | 
  
   
    |   | 
      |