PDA

View Full Version : [JAVA] Problemi con JPanel


Mesh89
12-10-2008, 16:51
Ecco il codice. Il problema è che, nel metodo initClientePanel, quando cerco di fare add, mi lancia un NullPointerException. Investigando, ho scoperto che clientePanel, al momento della add, è a null.

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;


public class NewGUI extends JFrame {
private static NewGUI inst;
private Core coreProgramma = new Core();

private JPanel clientiPanel;
private JPanel progettiPanel;
private JPanel preventiviPanel;
private JPanel fatturePanel;

private DefaultTableModel clientiListData;
private JTable clientiList;

private JButton apriAggiungiClienteFrameButton;


private NewGUI(int width, int height) {
setTitle("Gestione fatture");
setSize(new Dimension(width, height));
setLocation(100,100);
this.setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

setVisible(true);
}

private static void createAndShowGUI() {
inst = new NewGUI(1024,768);
inst.initMainPanels();

inst.pack();
inst.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}

private void initMainPanels() {
initMainPanel(clientiPanel);
initClientiPanel();

initMainPanel(progettiPanel);
initMainPanel(preventiviPanel);
initMainPanel(fatturePanel);
}
private void initMainPanel(JPanel panel) {
panel = new JPanel(new GridBagLayout());

panel.setPreferredSize(new Dimension(this.getWidth()/4, this.getHeight()));
panel.setBorder(new LineBorder(Color.GRAY));

this.add(panel);
panel.setVisible(true);
}

private void initClientiPanel() {
GridBagConstraints c = new GridBagConstraints();

clientiListData = new DefaultTableModel(0,1);
clientiList = new JTable(clientiListData);

/*clientiList.setBorder(new LineBorder(Color.GRAY));
clientiList.setPreferredSize(new Dimension(clientiPanel.getWidth(), (int)((3.0/4.0)*clientiPanel.getHeight())));
clientiList.getColumnModel().getColumn(0).setCellRenderer(MyCellRenderer.MY_RENDERER);
clientiList.setVisible(true);*/

//clientiPanel.add(clientiList, c);

apriAggiungiClienteFrameButton = new JButton("Aggiungi cliente");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 0;

if (clientiPanel == null) System.out.println("Errore");
clientiPanel.add(apriAggiungiClienteFrameButton);
}
private void fillClientiListData()
{
for (int i = clientiListData.getRowCount()-1; i >= 0; i--)
clientiListData.removeRow(i);

for (Cliente c : coreProgramma.getClientiList())
clientiListData.addRow(new Object[] {
"<HTML>"+c.getSocieta()+"<br>"+
c.getAnagrafica().getNome()+" "+c.getAnagrafica().getCognome()+"<br>"+
"</HTML>"
});
}

static class MultilineCellRenderer extends DefaultTableCellRenderer {
public static final MultilineCellRenderer MY_RENDERER = new MultilineCellRenderer();

public Component getTableCellRendererComponent (JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
Component c = super.getTableCellRendererComponent (table, value,
isSelected, hasFocus, row, column);
int height = c.getPreferredSize ().height;
if (height > table.getRowHeight (row)) {
table.setRowHeight (row, height);
}
return c;
}
}
}


Eppure nel metodo initMainPanel(clientePanel) avrebbe dovuto inizializzarla, no?
Purtroppo in Java sono abbastanza niubbo, è praticamente la prima volta che ci lavoro, per cui probabilmente è una cavolata o una sfumatura del linguaggio che non conosco, e che qualcuno più esperto di me troverà sicuramente

Mixmar
12-10-2008, 18:25
L'errore è sul passaggio di parametri, che in Java avviene sempre per valore. Quando tu chiami il metodo che inizializza clientiPanel, initMainPanel, gli passi clientiPanel, che in quel momento vale null, crei un nuovo oggetto JPanel e lo inizializzi: ma questo oggetto non "torna indietro" alla chiusura del metodo come ti aspetteresti, e quindi la clientPanel che hai passato è ancora null come prima dell'esecuzione di initMainPanel.

Per spiegare meglio: la variabile panel di tipo JPanel nel metodo initMainClient viene inizializzata dentro il metodo stesso, quando chiami la new; da quel momento in poi, qualsiasi azione tu faccia va ad influire sulla nuova istanza di JPanel, non su quella vecchia che tu hai passato. Solo che la nuova istanza è referenziata da una sola variabile, quella panel di cui abbiamo appena parlato: siccome è locale al metodo (in quanto parametro di ingresso), appena finito viene "buttata via", e l'oggetto viene dereferenziato (in realtà no, per via di quella "this.add", ma questo è un effetto collaterale).

In questi casi le soluzioni sono (almeno?) due: o fai sì che il metodo initMainClient ritorni un riferimento al JPanel creato, così:


private void initMainPanels() {
clientiPanel = initMainPanel();
initClientiPanel();

initMainPanel(progettiPanel);
initMainPanel(preventiviPanel);
initMainPanel(fatturePanel);
}
private JPanel initMainPanel() {
panel = new JPanel(new GridBagLayout());

panel.setPreferredSize(new Dimension(this.getWidth()/4, this.getHeight()));
panel.setBorder(new LineBorder(Color.GRAY));

this.add(panel);
panel.setVisible(true);

return panel;
}


Oppure sfrutti il fatto che clientiPanel ha visibilità a livello di classe, e semplicemente operi su quello anzichè sulla variabile locale panel nel metodo initMainPanel (come peraltro fai già sotto):


private void initMainPanels() {
initMainPanel();
initClientiPanel();

initMainPanel(progettiPanel);
initMainPanel(preventiviPanel);
initMainPanel(fatturePanel);
}
private void initMainPanel(JPanel panel) {
clientiPanel = new JPanel(new GridBagLayout());

clientiPanel.setPreferredSize(new Dimension(this.getWidth()/4, this.getHeight()));
clientiPanel.setBorder(new LineBorder(Color.GRAY));

this.add(clientiPanel);
clientiPanel.setVisible(true);
}

Mesh89
12-10-2008, 19:41
Caspita, ma sai che, non so perchè, ero convinto che avvenisse sempre per referenza? O.o

Ora tutto quadra, grazie mille, credo proprio che andrò per il primo metodo ;)