PDA

View Full Version : [JAVA NETBEANS] Riempire dinamicamente Jtable


alfo1
26-04-2011, 22:48
Salve ragazzi avrei un problema con il riempimento dinamico di una Jtable.. Qualcuno mi da un aiuto per riempire una Jtable con per esempio nella prima colonna i nomi dei file presi in una determinata cartella? Grazie mille

PGI-Bis
27-04-2011, 12:49
Il modo più comprensibile per manipolare una JTable è probabilmente quello di passare per i "micrometodi" del suo modello, supponendo che sia un DefaultTableModel (il modello standard).

JTable table = new JTable(0, 0);//tabella vuota
DefaultTableModel model = (DefaultTableModel) table.getModel();

Aggiungo una colonna:

model.addColumn("Nome del file");

Adesso la tabella ha una colonna e zero righe.

Per aggiungere una riga in fondo alla tabella posso dire:

model.setRowCount(model.getRowCount() + 1);

Per impostare il valore dell'ultima riga posso dire:

model.setValueAt("valore", model.getRowCount() - 1, 0);

cioè valore, indice di riga, indice di colonna.

Ne consegue che, data una cartella, volendo mostrare i nomi dei file in una tabella potrei dire:

package test;

import java.io.File;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class Main implements Runnable {

public static void main(String[] args) throws IOException {
java.awt.EventQueue.invokeLater(new Main());
}

public void run() {
File folder = new File(System.getProperty("user.home"));
File[] files = folder.listFiles();

JTable table = new JTable(0, 0);//tabella "vuota"
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.addColumn("Nome del File");

for (int i = 0; i < files.length; i++) {
File file = files[i];
model.setRowCount(model.getRowCount() + 1);
model.setValueAt(file.getName(), model.getRowCount() - 1, 0);
}

JScrollPane tableScroller = new JScrollPane(table);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(tableScroller);
frame.pack();
frame.setVisible(true);
}

}

Non è il modo più efficiente di farlo perchè esistono metodi che permettono di riempire la tabella in un colpo solo anzichè avere N invocazioni di metodo ma è sempre meglio essere certi prima di essere rapidi.

alfo1
27-04-2011, 20:11
Il problema e' il fatto di lavorare con netbeans e cosi la tabella non viene aggiornata.. Come risolvo?

PGI-Bis
27-04-2011, 20:45
L'editor visuale dichiara la tabella come campo di istanza. Se non l'hai rinominata sarà qualcosa tipo "jTable1". Dopo l'initComponents, invocato nel costruttore, con quel "jTable1" puoi fare quello che preferisci, incluso lavorare col modello come indicato. Ad esempio puoi dire:

costruttore() {
initComponents();
DefaultTableModel model = new DefaultTableModel(0, 0);
jTable1.setModel(model);
model.addColumn("pippo");
//eccetera

alfo1
27-04-2011, 21:08
Con l ultimo suggerimento ha funzionato :) Grazie mille.. Ora provero' a riempire le altre colonne ma sono gia che avro' bisogno di aiuto e quindi ti richiedero' le cose :)

alfo1
28-04-2011, 13:00
Sulla gestione di un Jtree sai dirmi qualcosa?

PGI-Bis
28-04-2011, 14:37
Be', non mi sembra il luogo per una dissertazione di carattere generale :D. Hai un'esigenza specifica al riguardo?

alfo1
28-04-2011, 20:16
Avere la gerarchia delle cartelle del file system nell albero :)

PGI-Bis
28-04-2011, 21:14
Anche lì puoi sfruttare il fatto che un jtree predefinito usa come modello un DefaultTreeModel (se butti l'occhio alla doc vedrai che ha un tot di metodi utili) e lavora su nodi di tipo DefaultMutableTreeNode.

Nota che quello che è mostrato in un JTree predefinito è l'invocazione del metodo toString sullo userObject di ciascun DefaultMutableTreeNode, quindi se usi un file come userObject dei tuoi nodi vedrai il percorso completo del file, se usi solo il nome vedi solo il nome. Di norma conviene usare un wrapper per lo user object, tipo:

public class FileWrapper {
public final File file;
public FileWrapper(File file) { this.file = file; }
public String toString() { return file.getName(); }
}

Perchè ti permette di associare ai nodi, oltre al valore vero e prorpio, altri dati, magari per il rendering.

Qui trovi degli esempio d'uso di JTree

http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-JTree.html
http://www.java2s.com/Code/Java/Swing-JFC/SwingJTreeexample.htm
http://java.sun.com/docs/books/tutorial/uiswing/components/tree.html

alfo1
29-04-2011, 09:40
Ho guardato i tuoi link e sono utili solo che ho problemi nell'implementazione in netbeans

PGI-Bis
29-04-2011, 13:05
Con netbeans crei l'albero e lo piazzi nella gui. Dopodichè lo maneggi come fai con la tabella, solo che per l'albero usi DefaultTreeModel. Netbeans ti crea il campo - in ipotesi - jTree1. Nell'initComponents lo inizializza e lo inserisce nella gui dove gli hai detto di metterlo. Subito dopo l'initComponents puoi fargli di tutto e di più. Ad esempio, dovendo caricare le cartelle che stanno in un certo file puoi dire:

...costruttore() {
initComponents();
File rootFile = qualche cartella
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(rootFile);
for(File f : rootFile.listFiles()) {
if(f.isDirectory()) rootNode.add(new DefaultMutableTreeNode(f)));
}
DefaultTreeModel model = new DefaultTreeModel(root);
jTree1.setModel(model);

Puoi farlo nel costruttore ma puoi anche farlo in un metodo che invochi quando è premuto un pulsante: il campo è sempre quello, l'inizializzazione la fa il codice creato da netbeans, tu devi solo "manipolarlo".

alfo1
29-04-2011, 13:54
il problema e' che in netbeans l albero vuole un paramentro in ingresso come root all'inizio quando viene inizializzato; ed e' li lo scoglio che non riesco a superare

PGI-Bis
29-04-2011, 14:24
Il tuo netbeans è diverso dal mio :D.

Apri la finestra in modalità "design", trascini un "Tree" dalla finestra "Palette" sezione SwingControls nel contenitore dove vuoi metterlo. Appare un albero con un po' di voci (JTree, colors, sports, food). Vai in source, costruttore, dopo l'init components puoi mettere quello che preferisci.

alfo1
29-04-2011, 16:45
:i infatti ora funziona :rolleyes: Ho un ultima domanda, ma per richiamare la visualizzazione delle e file nell'albero ricorsivamente come posso fare?

PGI-Bis
29-04-2011, 17:31
La questione è un po' lunga da spiegare ma alla fine basterebbe un metodo ricorsivo che attraversi le cartelle (File) e richieda in più un DefaultMutableTreeNode come argomento.

Il fatto è che non è buona idea perchè un filesystem può richiedere diverso tempo (secondi o minuti) per poter essere attraversato completamente, il che ammazzerebbe i tempi di risposta della tua gui.

Se è necessario che il tuo programma abbia a disposizione l'albero completo del filesystem allora devi separare la scansione dalla pubblicazione dei nodi nell'albero: la prima la fai con un pool di thread in background, la seconda con l'edt (il thread che maneggia le gui awt/swing).

Se, come è più probabile, non ti interessa l'albero completo ma solo la parte attualmente visibile all'utente allora carichi solo le radici e quando l'utente espande una cartella, carichi i file/cartelle che quella contiene.

Per intercettare l'espansione del nodo puoi usare il metodo addTreeExpansionListener o il metodo addTreeWillExpandListener: a te interessa più il secondo perchè devi creare i nodi prima che la cartella sia "aperta".

L'ascoltatore di eventi che registri col metodo predetto avrà nel suo metodo di gestione un procedimento così composto (ad esempio):

1. prendi il file del nodo-cartella
2. carica la lista L di file contenuti in quella cartella (file.listFiles())
3. prendi tutti i figli N del nodo-cartella
4. per ogni nodo di N che non ha una controparte in L (file spostato o rimosso o rinominato) -> elimina il nodo dal nodo-cartella
5. per ogni file di L che non ha una controparte in N (nuovo file o primo caricamento) -> aggiungi un nuovo nodo al nodo-cartella

Inserimenti e rimozioni si fanno passando per il modello dell'albero, nel presupposto che sia un DefaultTreeModel:

DefaultTreeModel model = (DefaultTreeModel) jTree1.getModel();

4. rimozione

model.removeNodeFromParent(il nodo da rimuovere)

5. inserimento

DefaultMutableTreeNode nuovo = new DefaultMutableTreeNode(il file);
model.insertNodeInto(nuovo, il nodo della cartella)

E' necessario passare per il modello (tree.getModel()) altrimenti la vista (il JTree) non riflette le mutazioni che potresti applicare direttamente ai nodi (puoi aggiungere o rimuovere nodi passando direttamente per DefaultMutableTreeNode ma se non avverti il modello il JTree resterà tale e quale).

alfo1
29-04-2011, 17:42
mmm... Non sembra difficile da implementare... Devo provare e sperare di riuscire senza fare casini.. No esistono tutorial o spezzoni di codice?

PGI-Bis
29-04-2011, 18:04
C'è un esempio completo che centra in pieno il bersaglio:

http://www.java2s.com/Code/Java/Swing-JFC/DisplayafilesysteminaJTreeview.htm

alfo1
29-04-2011, 18:29
Ma scrivendo il codice l'albero resta con i nomi di default

PGI-Bis
30-04-2011, 09:36
So che non si risponde ad una domanda con un'altra domanda, quindi ne faccio due: cosa intendi per nomi di default e di codice parliamo?

alfo1
30-04-2011, 11:00
allora se in designe faccio click di dx sull labero e vado in customize code nell'inizializzazione dell albero devo mettere quale sara' il root giusto? Quindi lo devo dichiare prima dell'init non dopo

/* Ho risolto il problema qui sopra.. l''atro probelam resta il fatto di navigare nel Jtree, ho problemi a richiamarlo ricorsivamente */