PDA

View Full Version : [JAVA] Creazione tavolozza colore RGB


Cory
26-06-2009, 10:25
Sto implementando un programma che mi consenta di visualizzare su un pannello il colore che selezioni giocando sui parametri RGB, ognuno dei quali è controllato da una JSlider. Cliccando su "Reset" si ritorna alla situazione iniziale.
Tuttavia non capisco perchè muovendo la prima slider mi diventa tutto nero e cliccando su Reset le slider tornano a posto, il colore no...PS: devo ancora lavorare sul Rosso e sul Blu.

package esercitazione4;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.border.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Esercitazione extends JFrame{

public static void main(String [] args){

JFrame x=new JFrame("Colori");
x.setSize(400, 300);
x.setResizable(true);
x.setContentPane(new Dialog());
x.setDefaultCloseOperation(EXIT_ON_CLOSE);
x.setVisible(true);
}
}

public class Dialog extends JPanel {

JPanel pane;
JSlider green;
JSlider red;
JSlider blue;
JButton reset;
int verde=0;
int rosso=0;
int blu=0;
Color colore=new Color(verde,rosso,blu); //dichiaro un nuovo colore, con variabili RGB inizializzate a 0
static final int MAX=250;
static final int MIN=0;
static final int INIT=0;

public Dialog(){

this.setLayout(new GridBagLayout());
GridBagConstraints c=new GridBagConstraints();

green=new JSlider(MIN,MAX,INIT);
green.addChangeListener(new Verde());
green.setName("G");
green.setMajorTickSpacing(100);
green.setMinorTickSpacing(50);
green.setPaintTicks(true);
green.setPaintLabels(true);
green.setBorder(BorderFactory.createLineBorder(Color.BLACK));
c.fill=GridBagConstraints.HORIZONTAL;
c.ipady=30;
c.gridx=0;
c.gridy=0;
add(green,c);

red=new JSlider(MIN,MAX,INIT);
c.fill=GridBagConstraints.HORIZONTAL;
c.gridx=0;
c.gridy=1;
add(red,c);

blue=new JSlider(MIN,MAX,INIT);
c.fill=GridBagConstraints.HORIZONTAL;
c.gridx=0;
c.gridy=2;
add(blue,c);

pane=new JPanel();
pane.setBackground(Color.WHITE);
c.fill=GridBagConstraints.BOTH;
c.gridx=1;
c.gridy=0;
c.ipadx=150;
c.gridheight=3;
add(pane,c);

reset=new JButton("RESET");
reset.addActionListener(new Reset());
c.fill=GridBagConstraints.NONE;
c.gridx=0;
c.gridy=3;
c.gridwidth=1;
c.gridwidth=1;
c.insets.top=5;
c.anchor=GridBagConstraints.CENTER;
add(reset,c);
}

class Verde implements ChangeListener{

public void stateChanged(ChangeEvent e) {
JSlider source=(JSlider)e.getSource();
if(!source.getValueIsAdjusting()){
if(colore.getGreen()<255){verde++;}
pane.setBackground(colore);

}
}
}

class Reset implements ActionListener{

public void actionPerformed(ActionEvent e) {
green.setValue(INIT);
verde=0;
pane.setBackground(colore);

}
}

}

banryu79
26-06-2009, 11:14
Tuttavia non capisco perchè muovendo la prima slider mi diventa tutto nero...

Al movimento della slider scatta l'evento ChangeEvent che intercetti nel lister: lì fai un setBackground() passando 'colore' come parametro ma non lo modifichi, perciò rimane uguale a come viene inizializzato, ovvero con tutti i componenti RGB a zero, il che equivale al colore nero.

Il problema è dato dal fatto che tu incrementi un int

class Verde implements ChangeListener{

public void stateChanged(ChangeEvent e) {
JSlider source=(JSlider)e.getSource();
if(!source.getValueIsAdjusting()){
if(colore.getGreen()<255){verde++;}
pane.setBackground(colore);

}
}
}

ma poi non lo passi al Color che passi al metodo setBackground e ti aspetti che il tuo Color venga modificato: non funziona così, perchè verde, di tipo int, è un tipo primitivo, non una reference...


...e cliccando su Reset le slider tornano a posto, il colore no...

Come sopra, modifichi verde, ma verde è solo un int, il Color non cambia.

Cory
26-06-2009, 11:23
facendo verde++; non vado a modificare il valore che verde ha alla riga 16, e di conseguenza il valore che assume il colore? :confused:

banryu79
26-06-2009, 11:26
Inoltre non credo i concetti con cui gestire l'evento ChangeEvent dentro al listener siano corretti per ottenere l'effetto che desideri...

Secondo me devi dare un'occhiata a della documentazione su come usare JSlider.
La versione lunga la trovi sul sito della Sun; una prima versione più breve e abbordabile la trovi sul tutorial di 50 paginette del buon PGI. andare a vanti a caso ti fa solo perdere del tempo che invece potresti usare per leggereti quel breve ma efficace tutorial e risparmiarti tempo e frustrazione futuri ;)

Esempio diretto, leggendo il tutorial di PGI (estratto):

...cut...
JSlider
I costruttori di JSlider permettono di creare un selettore verticale o orizzontale (parametro
orientation) e di stabilire il valore minimo ed il valore massimo mostrati nella barra e selezionabili
dall'utente. Quando l'utente interagisce con il selettore spostando il nodo di selezione lo slider
produce degli eventi ChangeEvent quindi per catturare l'interazione utente occorre usare un
javax.swing.event.ChangeListener. Supponedo che slider sia una variabile di tipo JSlider vale il
seguente esempio:
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
int value = source.getValue();
System.out.println(value); //stampa il valore sulla console
}
});
Attraverso lo slider (metodo getValueIsAdjusting) è possibile sapere se un evento ChangeEvent si è
verificato ma l'utente non ha ancora terminato di far scorrere lo slider. Il valore restituito da
getValueIsAdjusting può quindi essere usato per eseguire un certo compito solo quando l'utente ha
effettivamente stabilito un nuovo valore per lo slider e non durante l'interazione.
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
if(!source.getValueIsAdjusting()) {
int value = source.getValue();
JOptionPane.showMessageDialog(source, "Valore: " + value);
}
}
});
...continue...


Io cambierei il tuo listener così:

class Verde implements ChangeListener{

public void stateChanged(ChangeEvent e) {
JSlider source=(JSlider)e.getSource();
verde = source.getValue();
pane.setBackground(new Color(rosso,verde,blu));
}
}


Provalo ;)

banryu79
26-06-2009, 11:31
facendo verde++; non vado a modificare il valore che verde ha alla riga 16, e di conseguenza il valore che assume il colore? :confused:
No, perchè vede è di tipo int, non è una reference, cioè non è un oggetto.

Dovresti leggerti qualcosa sul sitema dei tipi in Java e sul passaggio dei parametri ai metodi.

In Java il passaggio dei parametri ai metodi è sempre per copia del valore del parametro.
Nel caso di passaggio di un tipo primitivo, viene copiato il valore della primitiva; nel tuo caso viene copiato il valore di verde (che vale zero) quando invochi la prima volta il costruttore di Color.
Poi tu continui a modificare la variabile 'verde', ma Color internamente ha la sua copia, che non viene modificata.
Ed ecco spiegato perchè il Color resta nero.

Cory
26-06-2009, 11:32
Sì, in effetti devo ancora leggere il tutorial che mi hai consigliato :stordita: ho l'esame venerdì e non so se riesco a farcela :mc:

comunque mi sa che il grosso problema era che non avevo capito bene come funzionano i metodi dell'interfaccia :help: :doh:

Cory
26-06-2009, 11:34
No, perchè vede è di tipo int, non è una reference, cioè non è un oggetto.

Dovresti leggerti qualcosa sul sitema dei tipi in Java e sul passaggio dei parametri ai metodi.

In Java il passaggio dei parametri ai metodi è sempre per copia del valore del parametro.
Nel caso di passaggio di un tipo primitivo, viene copiato il valore della primitiva; nel tuo caso viene copiato il valore di verde (che vale zero) quando invochi la prima volta il costruttore di Color.
Poi tu continui a modificare la variabile 'verde', ma Color internamente ha la sua copia, che non viene modificata.
Ed ecco spiegato perchè il Color resta nero.

grazie della spiegazione, adesso penso di aver capito :) vedo di ripassare l'argomento! ma se quindi invece di int l'avessi dichiarato come Integer, avrebbe invece funzionato?

banryu79
26-06-2009, 11:38
Sì, in effetti devo ancora leggere il tutorial che mi hai consigliato :stordita: ho l'esame venerdì e non so se riesco a farcela :mc:

Sinceramente, 50 pagine, scritte in maniera chiara, con la capacità di esporre i concetti in maniera cristallina come solo una persona che ha completamente padroneggiato i concetti di cui parla e ha una visione di insieme delle cose molto profonda, quale PGI è in ambito Java, ti assicuro che si fa leggere quasi come un buon romanzo (sempre se la programmazione e il linguaggio Java ti appassionano).

Diciamo che ritagliandoti 2-3 orette riusciresti a leggerlo tutto capendolo.
Io questo, a maggior ragione in vista di un esame, lo vedo come un investimento (specie se dovrai ancora avere a che fare con Java in futuro).


comunque mi sa che il grosso problema era che non avevo capito bene come funzionano i metodi dell'interfaccia :help: :doh:

Il grosso del problema io lo vedo altrove; come per esempio non avere chiara la differenza tra un tipo primitivo e un tipo reference: queste sono le basi del linguaggio, e sono assolutamente prioritarie rispetto la conoscenza delle librerie.

banryu79
26-06-2009, 11:46
grazie della spiegazione, adesso penso di aver capito :) vedo di ripassare l'argomento! ma se quindi invece di int l'avessi dichiarato come Integer, avrebbe invece funzionato?
Sarebbe dipeso dal rispetto delle seguenti condizioni:
1) che la classe Color avesse un costruttore (o esponesse altri metodi per specificare le componenti di colore RGB) che prende in ingresso tipi Integer;
2) che la classe Color rispetto al punto 1) prendesse gli Integer per memorizzarli internamente così come sono (come reference, quindi una modifica esterna alla classe agli Integer si rifletterebbe anche internamente, le reference alla fine sono puntatori) e non per estrarne il valore di tipo int e memorizzare quello (come copia di un int esterno che, anche se poi viene successivamente modificato, non si riflette internamente alla classe).

In pratica se vai a vedere i javadoc della classe Color potrai notare dalla mancanza di metodi 'set' per le singole componenti di colore che la classe non è pensata per essere modficabile nel modo in cui vorresti tu.

banryu79
26-06-2009, 11:51
Ah, due dettagli rispetto al sorgente postato al tuo primo post:
- non occorre che chiami setResizable(true) sul JFrame: un JFrame di default è ridimensionabile.
- class Esercitazione e class Dialog sono entrambe dichiarate come public, e questo è un errore: in uno stesso file .java puoi avere solo una classe 'public'.