Le Immaggini

 

 

Passo1 Passo2 Passo3

 

Obiettivo: Ruotare un'immagine intorno al suo centro

 

 

Documentazione:

Inserire immagini o disegnare con ImageIcon
Tutorial GRAFICA BI-DIMENSIONALE IN JAVA 

 

Ora eseguiremo un'altro passetto avanti, faremo in modo che la manopola dell'esercizio precedente possa ruotare intorno al suo centro, cambiare il senso e la velocità di rotazione, girare in continuo o passo passo, impostare il passo in gradi centesimali.

 

Classe principale eseguibile

Classe: ManV1

  1 package manov1;
  2 
  3   import java.awt.*;
  4   import java.awt.event.ActionEvent;
  5   import java.awt.event.ActionListener;
  6   import java.awt.event.ItemEvent;
  7   import java.awt.event.ItemListener;
  8   import javax.swing.event.ChangeListener;
  9   import javax.swing.event.ChangeEvent; 
 10   import java.util.Locale;
 11   import javax.swing.*;
 12   
 13   public class ManoV1 extends JFrame{
 14       private JButton jb,jx;
 15       private JToggleButton jg;
 16       private JSpinner jt,js;
 17       private JLabel jv,jgra,jval;
 18       private int flg=0,lx,ly,lw,mx,my,cox,coy,vel=10;
 19       private double gra=0,inc=0.5;
 20       private Timer tm;
 21       private String val;
 22       private MyIcon mn;
 23       
 24       public ManoV1() {
 25           Locale.setDefault(Locale.Category.FORMAT, Locale.ENGLISH); 
 26           
 27           setTitle("Visualizzazione Immagine");
 28           setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); 
 29           getContentPane().setBackground(Color.white); 
 30           setLayout(null);
 31           setSize(550, 500);
 32           setLocationRelativeTo(null);
 33   
 34           //Avanza Passo Passo       
 35           jb = new JButton("Passo");
 36           jb.addActionListener(new ActionListener() {
 37               public void actionPerformed(ActionEvent evt) {                              
 38                   tm.stop();
 39                   jg.setText("Start");
 40                   jg.setSelected(false);
 41                   varia();
 42                   mn.setGra(gra); 
 43               }
 44           });
 45           jb.setBounds(15, 10, 80, 23);
 46           add(jb);//--------
 47 
 48           //Cambio di direzione              
 49           jx = new JButton("Direzione");
 50           jx.addActionListener(new ActionListener() {
 51               public void actionPerformed(ActionEvent evt) {                              
 52                   if(flg==1)flg=0; else flg=1;                
 53               }
 54           });
 55           jx.setBounds(100, 10, 80, 23);
 56           add(jx);//--------
 57 
 58           //Spinner Incrementa il passo in gradi
 59           js = new JSpinner();
 60           js.setLocale(Locale.ENGLISH);
 61           js.setModel(new SpinnerNumberModel(inc,0.0d,360.0d,0.1d));        
 62           js.setFont(new java.awt.Font("Tahoma", 1, 14)); 
 63           js.addChangeListener(new ChangeListener() {
 64               public void stateChanged(ChangeEvent evt) {
 65                   inc = Double.parseDouble (""+js.getValue());              
 66               }
 67           });
 68           js.setBounds(240, 9, 60, 25);
 69           add(js);//--------
 70 
 71            //Spinner incrementa la velocità in millisecondi
 72           jt = new JSpinner(new SpinnerNumberModel(vel,1,2000,5));
 73           jt.setFont(new java.awt.Font("Tahoma", 1, 14)); 
 74           jt.addChangeListener(new ChangeListener() {
 75               public void stateChanged(ChangeEvent evt) {
 76                   vel = Integer.parseInt(""+jt.getValue());
 77                   tm.setDelay(vel);
 78                   tm.start(); 
 79               }
 80           });
 81           jt.setBounds(360, 9,75, 25);
 82           add(jt);//--------                         
 83 
 84           //Start/Stop  
 85           jg = new JToggleButton("Start");
 86           jg.addItemListener(new ItemListener() {
 87               public void itemStateChanged(ItemEvent evt) {
 88                  int status = evt.getStateChange();
 89                   if(status == ItemEvent.SELECTED){ 
 90                       jg.setText("Stop");
 91                       tm.start();
 92                   }else{
 93                       jg.setText("Start");
 94                       tm.stop();
 95                   }              
 96               }
 97           });
 98           jg.setBounds(440, 10, 80, 23);
 99          add(jg);//--------
100 
101          //etichetta inc-gra 
102          jgra = new JLabel("inc-gra");
103          jgra.setFont(new Font("Tahoma", 1, 14)); // NOI18N
104          jgra.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
105          add(jgra);
106          jgra.setBounds(188, 10, 50, 20);
107 
108          //etichetta inc-val
109          jval = new JLabel("inc-val");
110          jval.setFont(new Font("Tahoma", 1, 14)); // NOI18N
111          jval.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
112          add(jval);
113          jval.setBounds(308, 10, 50, 20);
114          
115          //etichetta che visualizza i gradi
116          jv = new JLabel("0");
117          jv.setFont(new Font("Digital-7Mono", 1, 50));
118          jv.setForeground(Color.RED);
119          jv.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
120          jv.setText("0");
121          add(jv);
122                     
123          //Disegna la manopola         
124          mn = new MyIcon();
125          mn.setLocation(103, 86);
126          add(mn);
127          
128          setVisible(true);
129          //centra la manopola
130          cox=getContentPane().getSize().width;
131          coy=getContentPane().getSize().height;
132          mx=(cox-(mn.getWp()))/2;
133          my=(coy-(mn.getHp()))/2;
134          mn.setLocation(mx, my);
135          mn.setLocation(mx, my);
136          
137          //centra l'etichetta
138          lw=200;
139          lx=(cox-lw)/2;
140          ly=(coy-60); 
141          jv.setBounds(lx, ly, 200, 40);   
142          
143          //Imposta il Timer        
144          tm = new Timer(vel,new ActionListener() {
145              public void actionPerformed(ActionEvent evt) {
146                  varia();
147              }
148          });
149      }
150      
151      //controllo della posizione
152      private void varia(){        
153          if(flg==0){          
154              gra=gra+inc;
155              if(gra>360){
156                 gra=gra-360;                    
157              }                                  
158          }else{
159              if(gra==0){
160                  gra=360-inc;
161              }else{
162                  gra=gra-inc;
163                  if(gra<0){
164                  gra=gra+360;                    
165                  } 
166              }
167          }
168         
169          mn.setGra(gra);
170          val=String.format(new Locale("en"),"%1$.2f",gra);
171          jv.setText(val);    
172      }
173      
174      public static void main(String [] args){
175          
176          new ManoV1();
177      }
178   }

 

Classe esterna che disegna la manopola

Classe: MyIcon

 1 package manov1;
 2 
 3  import java.awt.Graphics;
 4  import java.awt.Graphics2D;
 5  import java.net.*;
 6  import javax.swing.*;
 7  
 8  class MyIcon extends JComponent{
 9     private double gra=0;
10     private ImageIcon icon;
11     private int wP,hP,xC,yC;
12 
13     public MyIcon(){        
14         icon = createImageIcon("/image/mano1.png");
15         wP = icon.getIconWidth();
16         hP = icon.getIconHeight();
17         setSize(wP, hP);
18     }
19     public void paintComponent(Graphics g) {
20         super.paintComponent(g);
21         Graphics2D g2d =(Graphics2D)g;
22         
23         xC =wP/2;
24         yC =hP/2;
25 
26         g2d.translate(xC,yC); 
27         g2d.rotate(Math.toRadians(gra)); 
28         g2d.translate(-xC,-yC);
29 
30        icon.paintIcon(this, g2d, 0, 0);
31     }
32     public void setGra(double gr){
33         gra=gr;
34         repaint();
35     }
36     public int getWp(){        
37         return(wP);
38     }
39     
40     public int getHp(){        
41         return(hP);
42     }
43     
44     private ImageIcon createImageIcon(String path) {
45         URL imgURL = getClass().getResource(path);
46         if (imgURL != null) {
47            return new ImageIcon(imgURL);
48         } else {
49             System.err.println("Non è possibile trovare il file: " + path);
50             return null;
51         }
52     }
53 }

 

Discussione:

 

Occupiamici della classe MyIcon a parte le considerazioni riguardanti il caricamento e la visualizzazione già trattate qui passiamo direttamente alla sezione di codice che si interessa della rotazione 19-31. Si prelevano le dimensioni dell'immagine (wP e hP) 15-16, nella 17 si assegnano le stesse dimenzioni a MyIcon (il componente).Poi si calcolano le coordinate xC e yC del centro dell'immagine righe 23-24. Dalla 26 alla 28 realizziamo la rotazione. Importante rispettare questo preciso ordine, il codice verrà eseguito in realtà al contrario ossia prima la 28 poi la 27 ed infine la 26. Con la 28 il centro della nostra immagine (la manopola) viene spostato all'origine degli assi del JComponent MyIcon, intorno al quale avviene sempre la rotazione. Una volta in questa posizione la 27 esegue la rotazione dell'angolo desiderato (notare la conversione da angolo centesimale (gradi,centesimi) a radianti (360=2Pi)) poi l'immagine viene riportata alla posizione originale ossia il centro di MyIcon. Alla riga 30 avviene il miracolo icon.paintIcon(this, g2d, x, y); ciò che avviene all'interno dovrebbe essere questo: il metodo paintIcon della nostra immagine andrà per prima cosa a disegnarla dove? all'interno del contenitore this (MyICon) nella posizione x=0 e y=0 (l'angolo in alto a sinistra di MyIcon) poi darà via al contesto grafico g2d con le relative trasformazioni. Ultima considerazione il metodo setGra che riceve come parametro l'angolo a cui ruotare la manopola che verrà inserito nella variabile privata gra, dopo di che lancia il metodo repaint che prima cancellerà la vecchia manopola per ripetere poi di nuovo il disegno ma con il nuovo angolo.

 

Ora ci dedichiamo alla classe principale:

 

Questa è la sezione delle dichiarazioni delle variabili

 14       private JButton jb,jx;
 15       private JToggleButton jg;
 16       private JSpinner jt,js;
 17       private JLabel jv,jgra,jval;
 18       private int flg=0,lx,ly,lw,mx,my,cox,coy,vel=10;
 19       private double gra=0,inc=0.5;
 20       private Timer tm;
 21       private String val;
 22       private MyIcon mn;

 

Creazione del Frame.

interessanti sono le righe 31 e 32 perché ci permettono in modo sintetico di collocare la nostra finestra (JFrame) al centro dello schermo. Però attenzione, affinchè funzioni bisogna prima impostare le dimensioni poi setLocationRelativeTo(null); non viceversa. Questo perchè fino a che non viene dimensionata la finestra non ha dimensioni.

 27           setTitle("Visualizzazione Immagine");
 28           setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); 
 29           getContentPane().setBackground(Color.white); 
 30           setLayout(null);
 31           setSize(550, 500);
 32           setLocationRelativeTo(null);

 

Notare la linea 25:

25           Locale.setDefault(Locale.Category.FORMAT, Locale.ENGLISH); 

Questa imposta la formattazione dei numeri, date ecc. nel formato inglese ad es. i numeri vengono rappresentati così 12,345.00 mentre in europa siamo abituati a 12.345,00.

 

  • Blocco 34-44 Spingendo il pulsante Passo
  • 38 fermiamo il movimento della manopola
  • 39-40 resettiamo l'interruttore Start, etichetta a "Start" e lo rendiamo inattivo
  • 41 eseguiamo il metodo varia() che si preoccupa di gestire la posizione corretta degli angoli. Con un po di pazienza sarete in grado di capire l'algoritmo.
  • 42 preparato il giusto angolo gra lo si da in pasto al metodo setGra() che penserà a ridisegnare la manopola nella nuova posizione.

 

 34           //Avanza Passo Passo       
 35           jb = new JButton("Passo");
 36           jb.addActionListener(new ActionListener() {
 37               public void actionPerformed(ActionEvent evt) {                              
 38                   tm.stop();
 39                   jg.setText("Start");
 40                   jg.setSelected(false);
 41                   varia();
 42                   mn.setGra(gra); 
 43               }
 44           });

 

Spingendo il pulsante direzione non facciamo altro che invertire il flag che nel metodo varia() srà responsabile del senso di rotazione:

 

 48           //Cambio di direzione              
 49           jx = new JButton("Direzione");
 50           jx.addActionListener(new ActionListener() {
 51               public void actionPerformed(ActionEvent evt) {                              
 52                   if(flg==1)flg=0; else flg=1;                
 53               }
 54           });
 55           jx.setBounds(100, 10, 80, 23);
 56           add(jx);//--------

 

Nel nostro caso lo spinner viene usato per incrementare o decrementare dei valori numerici. Ma è possibile utilizzarlo per altri scopi vedi approfondimento qui. Per impostarlo bisogna settare il relativo spinnerModel e trattandosi di valori numerici lo SpinnerNumberModel che ha 4 parametri. Usiamo per i gradi il costruttore con parametri Double, dove il primo indica il valore di partenza, il secondo il valore minimo, il terzo il valore massimo e l'ultimo l'incremento/decremento che deve avere. Ogni qual volta clicchiamo sulle freccette viene lanciato un evento del tipo ChangeEvent che l'ascoltatore associato processera nel metodo stateChanged . Qui non si fa altre che leggere il valore impostato nel textField e dopo averlo convertito in double inserirlo nella variabile inc.

 

 58           //Spinner Incrementa il passo in gradi
 59           js = new JSpinner();
 60           js.setLocale(Locale.ENGLISH);
 61           js.setModel(new SpinnerNumberModel(inc,0.0d,360.0d,0.1d));        
 62           js.setFont(new java.awt.Font("Tahoma", 1, 14)); 
 63           js.addChangeListener(new ChangeListener() {
 64               public void stateChanged(ChangeEvent evt) {
 65                   inc = Double.parseDouble (""+js.getValue());              
 66               }
 67           });
 68           js.setBounds(240, 9, 60, 25);
 69           add(js);//--------
 70 
 71            //Spinner incrementa la velocità in millisecondi
 72           jt = new JSpinner(new SpinnerNumberModel(vel,1,2000,5));
 73           jt.setFont(new java.awt.Font("Tahoma", 1, 14)); 
 74           jt.addChangeListener(new ChangeListener() {
 75               public void stateChanged(ChangeEvent evt) {
 76                   vel = Integer.parseInt(""+jt.getValue());
 77                   tm.setDelay(vel);
 78                   tm.start(); 
 79               }
 80           });
 81           jt.setBounds(360, 9,75, 25);
 82           add(jt);//--------                 

 

Questo interruttore se schiacciato fa partire il timer, se rilasciato lo fermerà:

 

 84           //Start/Stop  
 85           jg = new JToggleButton("Start");
 86           jg.addItemListener(new ItemListener() {
 87               public void itemStateChanged(ItemEvent evt) {
 88                  int status = evt.getStateChange();
 89                   if(status == ItemEvent.SELECTED){ 
 90                       jg.setText("Stop");
 91                       tm.start();
 92                   }else{
 93                       jg.setText("Start");
 94                       tm.stop();
 95                   }              
 96               }
 97           });
 98           jg.setBounds(440, 10, 80, 23);
 99          add(jg);//--------

 

  • 101 - 121 vengono definite le etichette. Osservare ta tecnica di centratura di quello che visualizza i valori dell'angolo in variazione.
  • 123 - 126 si disegna la manopola istanziando la classe MyIcom.
  • 129 - 135 centra la manopola
  • 137 - 141 centra l'etichetta
  • 143 - 149 il timer.

Un'ultima considerazione. La formattazione degli spinner si basa su un formato europeo ossia i decimali vengono rappresentati con la virgola e le migliaia con il punto. Il formato Inglese invece rappresenta i decimali con il pumto e le migliaia con la virgola. Poiché trovo molto più comodo il formato inglese anche per il fatto che con esso possiamo digitare tutto sul tastierino. Per modificare la formattazione possiamo utilizzare due modalità:

 

Questa:

js = new JSpinner();
js.setModel(new SpinnerNumberModel(inc,0.0d,360.0d,0.1d));               
JSpinner.NumberEditor ne = (JSpinner.NumberEditor) js.getEditor();
ne.getFormat().setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.ENGLISH));          

 

O questa:

Locale.setDefault(Locale.Category.FORMAT, Locale.ENGLISH);        

 

La prima coinvolge solo lo spinner la seconda è generale. La seconda è decisamente più pratica e simtetica La prima bisogna scriverla per ogni spider che si ha.