Bonjour à tous,

Je fais appel à votre science pour m'aider à résoudre un petit problème concernant les JSpinner :

Je voudrais en effet créer un JSpinner qui permet de choisir une durée sous la forme "00:00".
J'aimerais que ce JSpinner ait un comportement similaire à celui d'un JSpinner de Date : lorsque le curseur est sur le nombre des heures, le clic sur les flèches du JSpinner aura un effet sur le nombre d'heures, idem pour les minutes.
De plus j'aimerais qu'il soit éditable avec une vérification de la saisie (un JFormattedTextField quoi) mais c'est une autre histoire.

Mais j'ai tout essayé, de l'AbstractSpinnerModel au SpinnerNumberModel, mais je n'arrive pas à faire en sorte d'adapter le JSpinner à ma classe représentant une durée que voici :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
public class Duration {
 
    /** Number of milliseconds in an hour */
    private static final long MILLISECONDS_IN_AN_HOUR = 1000 * 60 * 60;
 
    /** Number of milliseconds in a minute */
    private static final long MILLISECONDS_IN_A_MINUTE = 1000 * 60;
 
    /** Hours */
    private int hours;
 
    /** Minutes */
    private int minutes;
 
    /**
     * Constructor
     * Initializes the duration to 0 hours and 0 minutes
     */
    public Duration() {
	setMilliseconds(0);
    }
 
    /**
     * Constructor
     * @param duration the duration in milliseconds
     */
    public Duration(long duration) {
	setMilliseconds(duration);
    }
 
    /**
     * Constructor
     * @param hours the hours
     * @param minutes the minutes
     */
    public Duration(int hours, int minutes) {
	setHours(hours);
	setMinutes(minutes);
    }
 
    /**
     * Constructor
     * @param duration the duration from which the current duration is initialized
     */
    public Duration(Duration duration) {
	setMilliseconds(duration.getMilliseconds());
    }
 
    /**
     * Adds a duration to the current duration
     * @param duration the duration to add
     */
    public void add(Duration duration) {
	setMilliseconds(getMilliseconds() + duration.getMilliseconds());
    }
 
    /**
     * Substract a duration to the current duration
     * @param duration the duration to substract
     */
    public void substract(Duration duration) {
	if (getMilliseconds() <= duration.getMilliseconds()) {
	    setMilliseconds(0);
	} else {
	    setMilliseconds(getMilliseconds() - duration.getMilliseconds());
	}
    }
 
    /**
     * @return the duration in milliseconds
     */
    public long getMilliseconds() {
	return (this.hours * Duration.MILLISECONDS_IN_AN_HOUR + this.minutes
		* Duration.MILLISECONDS_IN_A_MINUTE);
    }
 
    /**
     * @param duration the duration to set in milliseconds
     * Duration can't be negative
     */
    public void setMilliseconds(long duration) {
	if (duration < 0) {
	    throw new IllegalArgumentException("Duration can't be negative");
	}
	this.hours = (int) (duration / Duration.MILLISECONDS_IN_AN_HOUR);
	this.minutes = (int) (duration % Duration.MILLISECONDS_IN_AN_HOUR
		/ Duration.MILLISECONDS_IN_A_MINUTE);
    }
 
    /**
     * @return the duration hours
     */
    public int getHours() {
	return this.hours;
    }
 
    /**
     * @param hours the number of hours to set
     * Number of hours can't be negative
     */
    public void setHours(int hours) {
	if (hours < 0) {
	    throw new IllegalArgumentException("Number of hours can't be negative");
	}
	this.hours = hours;
    }
 
    /**
     * @return the duration minutes
     */
    public int getMinutes() {
	return this.minutes;
    }
 
    /**
     * @param minutes the number of minutes to set
     * Number of minutes must be an integer between 0 and 59
     */
    public void setMinutes(int minutes) {
	if ((minutes < 0) || (minutes > 59)) {
	    throw new IllegalArgumentException(
		    "Number of minutes must be an integer between 0 and 59");
	}
	this.minutes = minutes;
    }
 
    @Override
    public String toString() {
	String hours = Integer.toString(this.hours);
	String minutes = Integer.toString(this.minutes);
 
	if (this.hours < 10) {
	    hours = "0" + this.hours;
	}
	if (this.minutes < 10) {
	    minutes = "0" + this.minutes;
	}
	return (hours + ":" + minutes);
    }
 
    /**
     * Converts a String into a Duration
     * @param durationString the duration string to convert into Duration
     */
    public static Duration valueOf(String durationString) {
	if (durationString.length() != 5 || durationString.charAt(2) != ':') {
	    throw new IllegalArgumentException("Duration string is not in the correct format");
	}
	Duration duration = new Duration();
	duration.setHours(Integer.valueOf(durationString.substring(0, 2)));
	duration.setMinutes(Integer.valueOf(durationString.substring(3, 5)));
 
	return duration;
    }
 
}
Voici le code du modèle de mon JSpinner :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class SpinnerDurationModel extends AbstractSpinnerModel {
 
    /** Duration */
    private Duration duration;
 
    /**
     * Constructor
     */
    public SpinnerDurationModel() {
	super();
	this.duration = new Duration();
    }
 
    @Override
    public Object getValue() {
	return this.duration;
    }
 
    @Override
    public void setValue(Object duration) {
	this.duration = (Duration)duration;
    }
 
    @Override
    public Object getNextValue() {
	Duration nextDuration = new Duration(this.duration);
	nextDuration.add(new Duration(0, 1));
	return nextDuration;
    }
 
    @Override
    public Object getPreviousValue() {
	Duration previousDuration = new Duration(this.duration);
	previousDuration.substract(new Duration(0, 1));
	return previousDuration;
    }
 
}
Visiblement, la méthode appelée lors du clic sur une flèche du JSpinner est setValue, et il semble qu'elle est appelée avec une String en paramètre. Pourtant mes méthodes getNext/PreviousValue ne retournent pas une String mais bien une durée.

D'où une exception : impossible de caster une String en Duration, ce qui est normal.

J'ai essayé quelques feintes mais ça me dérange de changer cette conception qui me semble correcte (ou alors je me trompe et j'attends vos corrections ).

Enfin bref, un peu d'aide de votre part serait la bienvenue !

Merci d'avance !