PDA

View Full Version : [JAVA] Problema confronto tra due date scritte in JComboBox


franksisca
02-04-2012, 15:48
allora, ho questa situazione, mi trovo a dover compilare 6 JComboBox che costituiscono due date. il problema è che la seconda data non può mai essere inferiore alla prima.

per il momento ho scritto questo codice:
/**
*
* @param giorno1 giorno della prima data
* @param mese1 mese della prima data
* @param anno1 anno della prima data
* @param giorno2 giorno della seconda data
* @param mese2 mese della seconda data
* @param anno2 anno della seconda data
* @return il metodo ritorna true se la prima data è antecedente alla
* seconda, false altrimenti
*/
private boolean compare2Dates(String giorno1, String mese1, String anno1, String giorno2, String mese2, String anno2) {
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.set(Integer.parseInt(anno1), Integer.parseInt(mese1), Integer.parseInt(giorno1));
c2.set(Integer.parseInt(anno2), Integer.parseInt(mese2), Integer.parseInt(giorno2));
if (c1.before(c2)) {
return true;//prima data minore della seconda
} else {
return false;//seconda data maggiore o uguale della prima
}
}

/**
*
* da inserire nei changeItemState dei vari comboBox
*/
private void verificaData() {
String giorno1 = (String) this.giorniInizio.getSelectedItem();
String mese1 = (String) this.meseInizio.getSelectedItem();
String anno1 = (String) this.annoInizio.getSelectedItem();
String giorno2 = (String) this.giorniScadenza.getSelectedItem();
String mese2 = (String) this.mesiScadenza.getSelectedItem();
String anno2 = (String) this.annoScadenza.getSelectedItem();
if (!(compare2Dates(giorno1, convertiMese(mese1), anno1, giorno2, convertiMese(mese2), anno2))) {
this.giorniScadenza.setSelectedItem(this.giorniInizio.getSelectedItem());
this.mesiScadenza.setSelectedItem(this.meseInizio.getSelectedItem());
this.annoScadenza.setSelectedItem(this.annoInizio.getSelectedItem());
}
}

/**
*
* @param mese Converte in numero in formato stringa un mese ricevuto in
* formato stringa
* @return Ritorna la stringa "1" se il parametro è Gennaio
*/
private String convertiMese(String mese) {
if (mese.equalsIgnoreCase("Gennaio")) {
return "1";
}
if (mese.equalsIgnoreCase("febbraio")) {
return "2";
}

if (mese.equalsIgnoreCase("marzo")) {
return "3";
}

if (mese.equalsIgnoreCase("aprile")) {
return "4";
}

if (mese.equalsIgnoreCase("maggio")) {
return "5";
}

if (mese.equalsIgnoreCase("giugno")) {
return "6";
}

if (mese.equalsIgnoreCase("luglio")) {
return "7";
}

if (mese.equalsIgnoreCase("agosto")) {
return "8";
}

if (mese.equalsIgnoreCase("settembre")) {
return "9";
}

if (mese.equalsIgnoreCase("ottobre")) {
return "10";
}

if (mese.equalsIgnoreCase("novembre")) {
return "11";
}

if (mese.equalsIgnoreCase("dicembre")) {
return "12";
}
return "-1";
}

Poi per ogni changeItemState io richiamo il metodo verificaData(), ma dopo un paio di richiami mi và in java.lang.StackOverflowError.

Cosa potrebbe essere secondo la vostra esperienza? Io penso che ci sia un sovraccarico di richieste e quindi una carenza di risorse...avete metodi alternativi per fare quello che serve a me? Considerate che la struttura delle date non può modificarsi più di tanto....volevo provare ad usare JCalendar ma non credo che implementi in automatico una gestione delle date che possa soddisfare le mie richeste

banryu79
02-04-2012, 17:47
Ciao franksisca, tre cose: primo puoi "snellire" e rifattorizzare un po' il codice per rendere il tutto più leggibile, ad esempio in questo modo (ma ovviamente va a gusti personali):

public class CompareDateFields {

enum Mese {
GEN("gennaio"), FEB("febbraio"), MAR("marzo"), APR("aprile"),
MAG("maggio"), GIU("giugno"), LUG("luglio"), AGO("agosto"),
SET("settembre"), OTT("ottobre"), NOV("novembre"), DIC("dicembre");

final String name;

Mese(String n) {
name = n;
}
}

static class SimilData implements Comparable<SimilData> {
final int day;
final int mounth;
final int year;

SimilData(String giorno, String mese, String anno) {
this.day = Integer.parseInt(giorno);
this.mounth = asInteger(mese);
this.year = Integer.parseInt(anno);
}

private int asInteger(String mese) {
for (Mese m : Mese.values())
if (mese.equalsIgnoreCase(m.name))
return m.ordinal() + 1;
throw new IllegalArgumentException(mese + " is not a valid mounth name.");
}

@Override public int compareTo(SimilData other) {
int diff = year - other.year;
if (diff != 0) return diff;
diff = mounth - other.mounth;
if (diff != 0) return diff;
return day - other.day;
}

boolean before(SimilData other) {
return this.compareTo(other) < 0;
}
}

//
// Example:
//

public static void main(String[] args) {
verificaData("15", "gennaio", "2014", "16", "gennaio", "2001");
verificaData("15", "gennaio", "2014", "15", "gennaio", "2014");
verificaData("15", "gennaio", "2014", "16", "gennaio", "2014");
verificaData("15", "gennaio", "2014", "16", "aprile", "2014");
verificaData("31", "dicembre", "2013", "15", "gennaio", "2014");
}

static void verificaData(String giorno1, String mese1, String anno1,
String giorno2, String mese2, String anno2) {
SimilData d1 = new SimilData(giorno1, mese1, anno1);
SimilData d2 = new SimilData(giorno2, mese2, anno2);
if (d1.before(d2)) System.out.println("d1 is before d2");
else System.out.println("d1 is same day of or after d2");
}
}



Secondo, se avrai a che fare pesantemente con le date anche in futuro, puoi semplificarti di molto la vita usando questa libreria: http://joda-time.sourceforge.net/ che è molto comoda e ben pensata, secondo me.

Terzo: lo StackOverflowError viene lanciato dalla jvm quando appunto lo spazio sullo stack termina a causa di una chiamata ricorsiva troppo profonda nella applicazione. Sarò distratto ma nel tuo codice non ne vedo (di esplicite chiamate ricorsive) però vedo una cosa che mi puzza:

/**
*
* da inserire nei changeItemState dei vari comboBox
*/
private void verificaData() {
String giorno1 = (String) this.giorniInizio.getSelectedItem();
String mese1 = (String) this.meseInizio.getSelectedItem();
String anno1 = (String) this.annoInizio.getSelectedItem();
String giorno2 = (String) this.giorniScadenza.getSelectedItem();
String mese2 = (String) this.mesiScadenza.getSelectedItem();
String anno2 = (String) this.annoScadenza.getSelectedItem();
if (!(compare2Dates(giorno1, convertiMese(mese1), anno1, giorno2, convertiMese(mese2), anno2))) {
this.giorniScadenza.setSelectedItem(this.giorniInizio.getSelectedItem());
this.mesiScadenza.setSelectedItem(this.meseInizio.getSelectedItem());
this.annoScadenza.setSelectedItem(this.annoInizio.getSelectedItem());
}
}

In questo metodo, se non sbaglio, ogni volta che chiami un setSelectedItem (e che la condizione testata in compare2Dates è vera) si scatena l'evento changedItemState del combo box corrispondente (viene pubblicato l'evento nella event queue che verrà processato appena possibile dall'edt) che a sua volta causa una nuova chiamata (futura) al metodo stesso.
Non ci metterei la mano sul fuoco, ma questa potrebbe essere la causa dell'esaurimento dello stack.
Nel caso lo fosse, dovresti, verificata la condizione e prima di chiamare i setSelectedItem, "staccare" e mettere da parte tutti i listener dell'evento change item state dei combo box, chiamare i setSelectedItem, e infine ripristinare i listener staccati.

PGI-Bis
02-04-2012, 17:48
Ti va in loop da qualche parte. Probabilmente nel changelistener fai qualcosa che comporta il rilascio di un ulteriore ChangeEvent. Nel codice del ChangeListener prima di fare qualsiasi altra cosa verifica che il valore attuale della casella combinata sia effettivamente cambiato (puoi ad esempio conservare l'indice dell'ultimo elemento selezionato e compararlo con quello dell'elemento attualmente selezionato per verificare se sia cambiato qualcosa oppure sia un "misfire").

franksisca
03-04-2012, 09:04
grazie ad entrambi:

@banryu79
il refactoring da te consigliato mi piace molto, sinceramente nella prima bozza di codice butto tutto lì e poi refattorizzo dopo, a "programma completo" (lo sò che è bruttina come cosa, oltre che dispendiosa, ma quando non ho il tempo di pianificare la programmazione non riesco a fare di meglio)

Per l'utilizzo di librerie....purtroppo mi trovo costretto da direttive superiori (ovviamente non competenti nel campo) ad utilizzare le combobox in questo modo, che io odio. in passato ho usato JCalendar e mi sono trovato verametne molto bene...ma ripeto che non dipende da me

probabilmente il problema dello stack è proprio lì, devo rivedere quella parte di codice come da te consigliato.

@pgi-bis
probabilmente và in loop nella parte di codice selezionata da banryu79, ovvero si richiamano in cascata i "cambiamenti delle combobox". ora inserisco un check come da te suggerito sul precedente indice selezionato e dovrei risolvere.