PDA

View Full Version : [java] relazionare Package


mirkus90
02-04-2011, 12:29
ciao raga vi posto la domanda che mi ha fatto un mio amico:
"Sto creando un progetto con la GUI, che deve essere strutturato così:
prima schermata con il login. Dopo essersi loggato, deve scomparire questa schermata e comparire la scheramata principale del progetto.
Il problema sorge qui. Come ca**o faccio.... Ora non ricordo bene come avevo fatto, perchè ci sono riuscito, ma non sono molto convito che vada bene. Praticamente ho aggiunto il frame nel package della prima schermata.... Non so se sta bene. Io vorrei fare che ogni schermata deve avere il suo package. Come ca**o di faaaaaaaa. HELPPPPPPPP "
Penso che si sia capito che il problema è come relazionare due o più Package in uno stesso progetto

PGI-Bis
02-04-2011, 13:38
In java i package non sono relazionabili - in effetti sono entità puramente nominali e del tutto autonome.

Ciò premesso, il problema dev'esere da un'altra parte perchè se il tuo amico vuole creare un package per ogni schermata la soluzione è... creare un package per ogni schermata: da questo punto di vista manca proprio il problema.

Forse non trova il pulsante nell'ide per introdurre un package nel suo progetto oppure riesce a creare tutti i package che vuole ma non riesce a collegare le istanze dichiarate in classi appartenenti ad un package ad istanze di classi dichiarate in altri package.

Bisogna indagare.

flex990
02-04-2011, 20:21
Salve,
Allora in allegato trovate il progetto in discussione.
Praticamente se vedete dentro il source c'è il package ergon e i jframe gui.java e prince.java.
Io vorrei tramite la pressione di un tasto in gui.java che comparisse prince.java.
Come fare?

Qui il progetto:
http://www.megaupload.com/?d=0DUEU7T9

PGI-Bis
02-04-2011, 21:52
Seleziona la classe GUI.java
Si apre il form editor, seleziona il pulsante "ok", a destra premi il pulsante "Events", scorri in basso fino ad arrivare al mouse listener e rimuovilo (basta cancellare il nome).

Poi fai doppio click sul pulsante "ok". L'ide genera un metodo:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}

Al posto del TODO metti:

Prince prince = new Prince();
prince.setVisible(true);

Cioè il metodo diventa:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Prince prince = new Prince();
prince.setVisible(true);
}

Se devi fare delle verifiche prima di aprire la finestra prince, li fai prima del setVisible.

Questo apre la finestra. Più che una soluzione è una pezza perchè poi incontrerai altri problemi relativi alla comunicazione tra oggetti. Ma è un altro paio di maniche.

flex990
05-04-2011, 00:09
E come consiglieresti di fare?
Cioè come dovrei fare per creare un programma con diversi form correlati tra loro e connessi al db?

PGI-Bis
05-04-2011, 12:04
La scelta dipende da una divinazione: come si evolverà il programma. Dal punto di vista pratico la soluzione più rapida da scrivere ed usare è probabilmente l'uso di singleton.

Crei una classe e la doti di un campo statico per ogni "modulo" del tuo programma:

package ergon;

public class ApplicationElements {

public static final GUI gui = new GUI();
public static final Database database = new Database();
public static final Prince prince = new Prince();
}

Poi crei un punto d'entrata unico del programma, una classe con un main che esegue la prima operazione dell'applicazione, ad esempio aprire la finestra "gui" sullo schermo:

package ergon;

import java.awt.EventQueue;

public class Application implements Runnable {

public void run() {
ApplicationElements.gui.setVisible(true);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Application());
}
}

Per via di ApplicationElements (ovvero della condivisione di uno stesso ambito di esecuzione da parte degli elementi del tuo programma) In GUI il metodo jButton1ActionPerformed che richiede un Prince diventa:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
ApplicationElements.prince.setVisible(true);
}

Allo stesso modo, quando avrai bisogno di un metodo del database, in una qualsiasi parte del codice, dirai:

ApplicationElements.database.connetti("pippo", "superpippo", "ultrapippo");

Se vuoi introdurre un altro form, lo definisci nella sua classe come per GUI o Prince, lo "pubblichi" in ApplicationElements e lo usi passando per ApplicationElements.


Esistono poi approcci un po' più evoluti. Puoi ad esempio stabilire che ogni elemento del tuo programma sia un "modulo" ed ogni modulo possa accedere agli altri attraverso la condivisione di un canale di comunicazione. Un modulo è un elemento con un ciclo vitale, di solito tripartito o quadripartito:

package ergon;

public interface Module {

void init(Module channel);

void start(Module channel);

void stop(Module channel);

void destroy(Module channel);

<T extends Module> T find(Class<T> module);
}

Il canale fa le stesse cose di ApplicationElements ma permette di gestire dinamicamente (cioè durante l'esecuzione del programma) chi esegua quali funzioni.

package ergon;

import java.util.LinkedHashMap;
import java.util.Map;

public class ModuleChannel implements Module {

private final Map<Class<?>, Module> modules = new LinkedHashMap<Class<?>, Module>();

public <T extends Module, K extends T> void register(Class<T> type, K module) {
modules.put(type, module);
}

public void init(Module channel) {
for (Module m : modules.values()) {
m.init(channel);
}
}

public void start(Module channel) {
for (Module module : modules.values()) {
module.start(channel);
}
}

public void stop(Module channel) {
for (Module module : modules.values()) {
module.stop(channel);
}
}

public void destroy(Module channel) {
for (Module module : modules.values()) {
module.destroy(channel);
}
}

public <T extends Module> T find(Class<T> moduleType) {
Module module = modules.get(moduleType);
return module != null ? moduleType.cast(module) : null;
}
}

E questa è la base. Dopodichè ogni elemento del tuo programma che denoti un gruppo di funzioni autonomo (sia esso un form piuttostoche un pannello in uno di quei form o un database o un servizio di rete eccetera) diventa un modulo. Per essere un modulo, il tipo di quell'elemento implementa Module e definisce i cinque metodi. Ad esempio, GUI dirà:

public class GUI extends javax.swing.JFrame implements Module {
private Module channel;

public void init(Module channel) {
this.channel = channel;
}

public void start(Module channel) {
setVisible(true);
}

public void stop(Module channel) {
}

public void destroy(Module channel) {
setVisible(false);
}

public <T extends Module> T find(Class<T> module) {
return channel.find(module);
}
//...eccetera

Prince dirà:

public class Prince extends javax.swing.JFrame implements Module {
private Module channel;

public void init(Module channel) {
this.channel = channel;
//altre operazioni di inizializzazione
}

public void start(Module channel) {
//operazioni di avvio
}

public void stop(Module channel) {
//operazione di interruzione
}

public void destroy(Module channel) {
//operazioni di rilascio
}

public <T extends Module> T find(Class<T> module) {
return channel.find(module);
}
//...eccetera

E database:

public class Database implements Module {
private Module channel;

public void init(Module channel) {
this.channel = channel;
}

public void start(Module channel) {
}

public void stop(Module channel) {
}

public void destroy(Module channel) {
}

public <T extends Module> T find(Class<T> module) {
return channel.find(module);
}
//...eccetera

Infine, il punto d'entrata del programma crea un canale, registra tutti i moduli e avvia il sistema:

package ergon;

import java.awt.EventQueue;

public class Main implements Runnable {

public void run() {
ModuleChannel ch = new ModuleChannel();
ch.register(Database.class, new Database());
ch.register(GUI.class, new GUI());
ch.register(Prince.class, new Prince());
ch.init(ch);
ch.start(ch);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Main());
}
}

Che ci mettiamo adesso dentro al jButton1ActionPerformed di GUI per aprire Prince? L'accesso tramite il canale:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
find(Prince.class).setVisible(true);
}

La seconda via è chiaramente più complicata ma offre maggiori opportunità nella gestione della struttura del programma perchè puoi "pubblicare" parti di classi in moduli diversi, rimpiazzare un modulo con un altro, gestire moduli che operano in thread diversi e via dicendo. Se il programma non è sufficientemente complesso, i singleton vanno benissimo.

ally
05-04-2011, 14:14
...è sempre consigliabile separare la logica dalla grafica...ne consegue che la gestione di elementi come db o simili non hanno nessuna relazione con l'interfaccia e i suoi possibili mille mila frame...la comunicazione tra questi la si fa con uno strato ad eventi...

flex990
05-04-2011, 22:14
@PGI-Bis:
Mammamia, complimenti per la ottima preparazione. Ora ho capito come devo fare... Sono indirizzato per i canali di comunicazione. Vorrei fare una cosa in grande, se mi riesce:D :D :D
Grazie 1000!!!

@ally:
Era l'idea con cui ero partito, ma non sapevo come fare...
Cosa intendi per strato ad eventi?

ally
06-04-2011, 09:14
@PGI-Bis:
Mammamia, complimenti per la ottima preparazione. Ora ho capito come devo fare... Sono indirizzato per i canali di comunicazione. Vorrei fare una cosa in grande, se mi riesce:D :D :D
Grazie 1000!!!

@ally:
Era l'idea con cui ero partito, ma non sapevo come fare...
Cosa intendi per strato ad eventi?

...intendo che la logica di funzionamento legata all'interfaccia grafica non è annegata su questa...la pressione di un tasto scatena un evento verso la classe main che sceglierà l'operazione da svolgere...


loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
login(...);
}
});


...diventerà nella classe dell'interfaccia :



...

loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
launchEvent("login");
}
});

...

private void launchEvent(String evento) {

GraphicEvent event = new GraphicEvent(this,evento);

this.listeners.performedEvent(event);

}
}


...e nella main class :


public void performedEvent(GraphicEvent e) {

if(e.getEvent().equals("login"))
{
login(...);
}
else if(e.getFire().equals("reset"))
{
...
}