Grazie per l'interessamento. Premetto che la gestione delle immagini è particolare, è stata implementata da altre persone che hanno fatto la parte iniziale dell'applicazione (è un progetto d'esame all'uni).
Le immagini vengono caricate tramite la seguente classe:
codice:
package control;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.util.TreeMap;
import javax.imageio.ImageIO;
/**
*
* @author Alessandro
*
* Classe di FONDAMENTALE importanza per le PRESTAZIONI dell'applicazione. Premesso che:
* - l'applicazione è composta da IMMAGINI, di due tipi
* • A) relative alla grafica ovvero all'interfaccia del programma (icone, pulsanti, sfondi di Panel, ecc.)
* • B) contenenti informazioni e dunque prelevate dal DB (locandine degli spettacoli, loghi dei cinema, foto dei cinema)
* - il tipo A è preponderante rispetto al tipo B, ed inoltre non è il risultato di una query pertanto il suo utilizzo è CERTO e dunque PREVEDIBILE
* - ogni componente che utilizza il tipo A prelevava le immagini (nella versione precedente di questa applicazione) attraverso la libreria ImageIO
* ovvero LEGGENDO DA FILE OGNI volta che il componente veniva istanziato
* - poteva capitare benissimo (vedi schermata PIFOrario) che 50 istanze dello stesso componente (ad esempio il pulsante per il GIORNO) ogni volta
* che venivano istanziate (50 istanze) leggessero da file, dallo STESSO file!!! (50 letture dallo stesso file)
* - la lettura da FILE è lenta, anche più di un accesso al DB
* - l'applicazione risultava molto lenta nel passaggio da una schermata all'altra e nell'interazione con l'utente
*
* L'idea che mi è venuta e la conseguente sua realizzazione sono descritte dai seguenti punti:
* • le immagini utilizzate sono TANTE (attualmente 207 ma potrebbero raggiungere anche 400) e PICCOLE (mediamente 20-30 KB)
* • perchè non caricarle tutte in RAM all'avvio (30KB x 400 = 12 MB) e renderle disponibili, invece di leggerle da file ogni volta?
* • per far ciò è necessaria una classe (QUESTA) avente unica istanza che alloca tutto in RAM la prima volta e poi, su richiesta, fornisce l'imma-
* gine desiderata
* • la struttura dati più consona al nostro caso è una TreeMap <chiave, valore> in cui
* - <chiave> = stringa contenente il percorso RELATIVO dell'immagine (ES.: "/presentation/icone/pulsante_avanti.png"), questo per evitarMI di es-
* sere costretto ad andare a modificare tutte le classi dove si usava il percorso relativo per individuare l'immagine
* - <valore> = l'immagine desiderata
* • tale struttura dati sfrutta gli algoritmi sugli alberi binari di ricerca (BST) per restituire un elemento con getElemento(chiave x) in tempo
* O(logn) dove n è la dimensione dell'input (nel nostro caso n = 400 => t = log400 = circa 9-10 colpi di clock!!!!)
* • si tratta semplicemente di leggere da file tutte le immagini UNA SOLA VOLTA (avvio del programma). Quali immagini? TUTTE quelle contentute nel-
* la cartella /presentation/icone (farò un ciclo per questo)
* • dal momento che le classi che costruiscono la grafica sono quelle contenute in presentation.componenti è bastato andare in ciascuna di esse e
* sostituire la lettura da file mediante ImageIO.read(path_relativo) con la chiamata CImmagini.istanza().getImage(path_relativo)
*
* NOTA : le prestazioni sono migliorate del 70-80 % (ho eseguito il test con lo strumento "Profile" di Netbeans)
* NOTA2: "Sì, ma io che cacchio devo fare?" potreste chiedervi a questo punto.
* - beh le classi che costruiscono la grafica sono già pronte,quindi dovete solo utilizzarle (ES.: new backgroundedButton("/presentation/icone/pul-
* sante_avanti.png")
* - se avete la necessità in qualunque momento ed in qualunque classe di ottenere un'immagine di tipo A (ovvero quelle in /presentation/icone) NON
* utilizzate ImageIO.read(path_relativo) ma utilizzate CImmagini.istanza().getImage(path_relativo)
* - se avete la necessità di ottenere un'immagine di tipo B (ovvero quelle del DB) ovviamente potete usare ImageIO
*/
public class CImmagini
{
private static CImmagini unicaIstanza = null;
private TreeMap<String,Image> icone;
public CImmagini()
{
//istanzio icone
this.icone = new TreeMap<String,Image>();
//prelevo la lista (stringhe) dei files presenti nella cartella presentation/icone
File f = new File(this.getClass().getResource("/presentation/icone").toString().substring(6));
String[] arrayNomiFiles = f.list();
//inserisco tutte le icone attraverso un ciclo "intelligente" che sfrutta la conoscenza dei files presenti in presentation/icone
for(int i=0; i<arrayNomiFiles.length; i++)
{
try {this.icone.put("/presentation/icone/"+arrayNomiFiles[i], ImageIO.read(getClass().getResource("/presentation/icone/"+arrayNomiFiles[i])));}
catch (IOException ex) {System.out.print("ERRORE di lettura dell'icona\n");}
}
}
Quindi, per esempio, se mi serve un bottone con un'immagine di background, all'interno delle mie classi chiamo costruttori di questo tipo:
codice:
icon = new backgroundedButton("/presentation/icone/r_icona.png");
In cui la classe backgroundedButton è così definita:
codice:
package presentation.componenti;
import ...[..]
public class backgroundedButton extends javax.swing.JButton
{
private Image img;
private Image img_PRESSED;
private Image img_FOCUSED;
private Image img_FLASH;
private String localURL;
public backgroundedButton(String localURL)
{
this.localURL = localURL;
//recupero le 3 immagini (abilitato, cliccato e focalizzato) dall'URL relativo passato
this.img = CImmagini.istanza().getImage(localURL);
this.img_PRESSED = CImmagini.istanza().getImage(localURL.substring(0, localURL.length()-4)+"_PRESSED.png");
this.img_FOCUSED = CImmagini.istanza().getImage(localURL.substring(0, localURL.length()-4)+"_FOCUSED.png");
this.img_FLASH = null; //by Anthony
//elimino il contenuto grafico ed il contorno di default del pulsante
this.setContentAreaFilled(false);
this.setFocusPainted(false);
//imposto l'immagine di base
this.setIcon(new javax.swing.ImageIcon(img));
//imposto l'immagine visualizzata quando il mouse clicca sul pulsante
this.setPressedIcon(new javax.swing.ImageIcon(img_PRESSED));
//imposto l'immagine visualizzata quando il mouse passa sopra il pulsante o quando esso è selezionato
this.setRolloverEnabled(true);
this.setRolloverIcon(new javax.swing.ImageIcon(img_FOCUSED));
this.setSelectedIcon(new javax.swing.ImageIcon(img_FOCUSED));
//imposto il puntatore del mouse appropriato per gli oggetti attivi su cui cliccare
this.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
}
public void changeImage(String localURL)
{
//imposto gli attributi attuali
this.localURL = localURL;
//leggo l'immagine
this.img = CImmagini.istanza().getImage(localURL);
this.img_PRESSED = CImmagini.istanza().getImage(localURL.substring(0, localURL.length()-4)+"_PRESSED.png");
this.img_FOCUSED = CImmagini.istanza().getImage(localURL.substring(0, localURL.length()-4)+"_FOCUSED.png");
this.img_FLASH = null;
//elimino il contenuto grafico ed il contorno di default del pulsante
this.setContentAreaFilled(false);
this.setFocusPainted(false);
//imposto l'immagine di base
this.setIcon(new javax.swing.ImageIcon(img));
//imposto l'immagine visualizzata quando il mouse clicca sul pulsante
this.setPressedIcon(new javax.swing.ImageIcon(img_PRESSED));
//imposto l'immagine visualizzata quando il mouse passa sopra il pulsante o quando esso è selezionato
this.setRolloverEnabled(true);
this.setRolloverIcon(new javax.swing.ImageIcon(img_FOCUSED));
this.setSelectedIcon(new javax.swing.ImageIcon(img_FOCUSED));
//imposto il puntatore del mouse appropriato per gli oggetti attivi su cui cliccare
this.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
}
/* il metodo "setBounds" si occupa di posizionare e dimensionare un elemento grafico. Noi creiamo
* qui una versione "facilitata" di questo metodo che dimensiona AUTOMATICAMENTE il pulsante se-
* condo le dimensioni dell'immagine, pertanto in ingresso riceve solo due coordinate */
public void setBounds(int x, int y)
{
super.setBounds(x,y,img.getWidth(this),img.getHeight(this));
}
//metodi aggiunti da Anthony
public void takeFlashIcon() {img_FLASH = CImmagini.istanza().getImage(localURL.substring(0, localURL.length()-4)+"_FLASH.png");}
public void setFlashIcon() {this.setIcon(new javax.swing.ImageIcon(img_FLASH));}
public void setDefaultIcon() {this.setIcon(new javax.swing.ImageIcon(img));}
.....
}
Spero davvero tu mi possa aiutare, anche perchè non mi spiego come abbiano fatto i miei colleghi prima a creare l'eseguibile relativo alla loro parte, visto che questo metodo di caricamento l'hanno usato anche loro.
Grazie ancora.