PDA

View Full Version : [JAVA] Problema con le finestre


Garet Jax
12-01-2011, 13:07
Ciao a tutti,

sto scrivendo una GUI per un progetto dell'università e mi sono imbattuto in questo problema che non riesco a risolvere.

In pratica ho due finestre che contengono una lista, in pratica la prima finestra (quella principale) visualizza l'elenco attuale, mentre la seconda serve per inserire nuovi elementi nella lista. Tutto procede bene fino a quando non passo daal finestra secondaria a quella pricipale: in pratica non riesco più a visualizzare la lista.

Le ho provate tutte con i metodi validate, revalidate, paint e repaint su form contenitori e ogni possibile componente ma nulla da fare.

Vi posto qui un esempio giocattolo per rendere l'idea cosa ho bisogno che faccia il programma.

La prima finestra ha un pulsante che apre l'altra; la seconda finestra ha due bottoni: il primo per aggiungere gli elementi in un vector tampone, il secondo per inserire il tutto nella lista e chiudere la finestra corrente.

Il motivo è che le modifihce non sono effettuate fino a quando l'utente non conferma col secondo pulsante.

La cosa SNERVANTE è che se riapro la finestra secondaria dalla principale DOPO le modifiche, i nuovi elementi sono presenti.

Se mi potete dare una mano, ve ne sarei grato.

//FINESTRA PRINCIPALE

package finestre;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Testform extends JFrame {
// elementi
private JList lista = null;
private JButton bottone = null;
private JScrollPane scroll = null;
private DefaultListModel modello = null;
private JPanel pannello = null;

// metodi
public Testform() {
super("Test");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// creo oggetti della finestra
bottone = new JButton("Apri");
modello = new DefaultListModel();
lista = new JList(modello);
scroll = new JScrollPane(lista);

//eventi
ApriAction azione = new ApriAction();
bottone.addActionListener(azione);

// layout e contenitori
pannello = new JPanel();
pannello.add(bottone);

// posizionamento oggetti nella finestra
this.add(scroll, BorderLayout.CENTER);
this.add(pannello, BorderLayout.EAST);
}// end costruttore

private class ApriAction implements ActionListener {

@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
TestForm2 t2 = new TestForm2(lista, Testform.this);
t2.pack();
t2.setVisible(true);
Testform.this.setVisible(false);

}// enn actionPerformed

}// end inner class
}// end finestra di test

//FINESTRA SECONDARIA
package finestre;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class TestForm2 extends JFrame {
// oggetti
private JList lista = null;
private JScrollPane scroll = null;
private JButton aggiungi = null;
private JButton ok = null;
private Testform finestra = null;
private Vector<String> elementi = null;

// contenitori
private JPanel pannelloEst = null;
private JPanel pannelloSud = null;

public TestForm2(JList elenco, Testform win) {
super("Test 2");
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
lista = elenco;
finestra = win;

// disegno la form

// oggetti
elementi = new Vector<String>();
scroll = new JScrollPane(lista);
aggiungi = new JButton("Aggiungi");
ok = new JButton("Ok");

// eventi
AggiungiAction aggAz = new AggiungiAction();
OkAction okaz = new OkAction();
aggiungi.addActionListener(aggAz);
ok.addActionListener(okaz);

// layout e contenitori
pannelloEst = new JPanel();
pannelloSud = new JPanel();

// aggiunta oggetti
pannelloEst.add(aggiungi);
pannelloSud.add(ok);
this.add(scroll, BorderLayout.CENTER);
this.add(pannelloEst, BorderLayout.EAST);
this.add(pannelloSud, BorderLayout.SOUTH);
}// end costruttore

private class AggiungiAction implements ActionListener {

@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
elementi.add("Nuovo Elemento");
JOptionPane.showMessageDialog(TestForm2.this,
"Aggiunto nuovo elemento", "Attenzione",
JOptionPane.INFORMATION_MESSAGE);
}// end actionPerformed
}// end inner class AggiungiAction

private class OkAction implements ActionListener {

@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
DefaultListModel modello = (DefaultListModel) lista.getModel();
for (int i = 0; i < elementi.size(); i++) {
modello.addElement(elementi.get(i));
}// end for
finestra.validate();
finestra.setVisible(true);
TestForm2.this.dispose();
}// actionPerformed
}// end OkAction
}// end TestForm2

banryu79
12-01-2011, 15:29
Passa alla seconda finestra il modello (DefaultListModel) invece della JList.
Nel costruttore della seconda finestra costuirai un'altra JList con il model passato.
Nella action della seconda finestra esegui gli inserimenti direttamente sul model passato.

Grosso modo, ApriAction diventa:

private class ApriAction implements ActionListener {

@Override
public void actionPerformed(ActionEvent arg0) {
TestForm2 t2 = new TestForm2(modello, TestForm.this);
t2.pack();
t2.setVisible(true);
TestForm.this.setVisible(false);

}// enn actionPerformed

}// end inner class


E in TestForm2, elimini il membro JList e aggiungi un membro DefaultListModel:

class TestForm2 extends JFrame {
// oggetti
private DefaultListModel modello = null;
private JScrollPane scroll = null;
private JButton aggiungi = null;
private JButton ok = null;
private TestForm finestra = null;
...

Di conseguenza cambia il costruttore:

public TestForm2(DefaultListModel mod, TestForm win) {
super("Test 2");
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
modello = mod;
JList lista = new JList(modello);
finestra = win;
...

e OkAction:

private class OkAction implements ActionListener {

@Override
public void actionPerformed(ActionEvent arg0) {
// riga eliminata
for (int i = 0; i < elementi.size(); i++) {
modello.addElement(elementi.get(i));
}// end for
finestra.setVisible(true);
TestForm2.this.dispose();
}// actionPerformed
}// end OkAction


Qui trovi un tutorial ufficiale su JList:
http://download.oracle.com/javase/tutorial/uiswing/components/list.html#mutable

E se bazzichi da poco nelle Swing e vuoi una guida base, guarda il link che ho in firma.

Garet Jax
12-01-2011, 19:47
:doh: :doh: :doh: :doh:

Quanto tempo ci ho perso?!?! 3 giorni?!

Effettivamente se volevo modificare la serie di elementi, avrei dovuto lavorare sul modello e non sulla lista :muro:

Comunque, ti ringrazio per i link, avevo già scoperto "googlando" la guida sul GridBagLayout di PGI-Bis e avere quella sullo Swing non guasta.

Ho, però, un altro un altro effetto simpatico su cui i mitici (o meglio inutili) metodi validate e compagnia bella non funzionano.

In questo caso ho bisogno di creare dei pulsati a comando nella parte centrale di una finestra e in posizioni ben precise. Per fare questo uso un GridBagLayout in cui inserisco dei pannello vuoti (verdi) per avere una specie di inizializzazione. Poi quando premo un bottone viene inserito un nuovo pulsante nella posizione voluta.

Ora, la prima versione del codice prevedeva di inserire i bottoni direttamente; l'effetto era che NON venivano disegnati fino a quando non ci passavo sopra col cursore del mouse.

Nella seconda versione, quella che ti posto, ho aggiunto l'uso del metodo remove del pannello scoperto spulciando la documentazione. Il motivo per cui il primo pannello è arancione è che avevo bisogno di verificare che remove andasse a prendere il pannello verde corretto.

Comunque, in questo caso il risultato è ancora più stupefacente: alcuni bottoni me li disegna, altri no... :boh:

Al momento mi tengo i bottoni fantasma che appaiono al passare del puntatore, non è proprio bellissimo ma almeno i bottoni ci sono :)

Grazie per l'aiuto (e la comprensione)


package finestre;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Testform extends JFrame {

// elementi
private int contatore = 0;
private JButton bottone = null;
private JPanel panneloEst = null;
private JPanel pannelloCent = null;
private GridBagConstraints vincoli = null;
private GridBagLayout layout = null;

// metodi
public Testform() {
super("Test");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// oggetti
bottone = new JButton("inserisci");
vincoli = new GridBagConstraints();

// eventi
Azione a = new Azione();
bottone.addActionListener(a);

// layout e contenitore est
panneloEst = new JPanel();

// layout e pannello centrali
layout = new GridBagLayout();
pannelloCent = new JPanel(layout);

// aggiunta oggetti pannello est
panneloEst.add(bottone);

// aggiunta oggetti pannello cent
inizializzaCentro(9);

pannelloCent.getComponent(contatore).setBackground(Color.ORANGE);

// aggiunta oggetti alla form
this.add(panneloEst, BorderLayout.EAST);
this.add(pannelloCent, BorderLayout.CENTER);
}// end costruttore

private void inizializzaCentro(int max) {
for (int i = 0; i < max; i++) {
vincoli.gridx = i % 3;
vincoli.gridy = i / 3;
vincoli.weightx = 1;
vincoli.weighty = 1;
vincoli.anchor = GridBagConstraints.CENTER;
vincoli.fill = GridBagConstraints.BOTH;
vincoli.insets = new Insets(10, 10, 10, 10);
JPanel pan = new JPanel();
pan.setBackground(Color.GREEN);
layout.setConstraints(pan, vincoli);
pannelloCent.add(pan);
}// end for
}// end inizializzaCentro

private class Azione implements ActionListener {

@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
JButton nuovoBottone = new JButton("Bottone" + (contatore + 1));
vincoli.gridx = contatore % 3;
vincoli.gridy = contatore / 3;
vincoli.fill = GridBagConstraints.BOTH;
vincoli.anchor = GridBagConstraints.CENTER;
vincoli.insets = new Insets(10, 10, 10, 10);
layout.setConstraints(nuovoBottone, vincoli);
pannelloCent.remove(contatore);
pannelloCent.add(nuovoBottone);
pannelloCent.validate();
pannelloCent.revalidate();
pannelloCent.repaint();
Testform.this.repaint();
contatore++;
}// end actionPerformed

}// end inner class Azione

}// end finestra di test

banryu79
13-01-2011, 09:31
Quando rimuovi/aggiungi un component da/a un container il cui stato è displayable devi chiamare validate.
L'errore sta nel fatto che per sostituire il componente ad un certo indice nel codice postato rimuovi il vecchio componente che si trova a quell'indice e poi aggiungi quello nuovo (il bottone) senza specificare l'indice.

Modifica Action così:

private class Azione implements ActionListener {

@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
JButton nuovoBottone = new JButton("Bottone" + (contatore + 1));
vincoli.gridx = contatore % 3;
vincoli.gridy = contatore / 3;
vincoli.fill = GridBagConstraints.BOTH;
vincoli.anchor = GridBagConstraints.CENTER;
vincoli.insets = new Insets(10, 10, 10, 10);
layout.setConstraints(nuovoBottone, vincoli);
pannelloCent.remove(contatore);
pannelloCent.add(nuovoBottone, contatore);
pannelloCent.validate();
contatore++;
}// end actionPerformed

}// end inner class Azione

Garet Jax
13-01-2011, 12:47
Capisco. In sostanza non erano i metodi validate che non andavano, ma semplicemente andava in confusione perché non gli indicavo quale componente sostituire.

Grazie mille, mi hai aiutato tantissimo.