PDA

View Full Version : [JAVA] Implementare Progress Bar


miao84
24-11-2009, 10:43
Dovrei implementare una progress bar, su una classe jFrame, che dovrebbe partire quando clicco su un bottone e terminare quando i metodi lanciati all'interno dell'evento del bottone sono finiti...solo che non c'ho mai capito molto sull'utilizzo di questa progress bar..chi sa aiutarmi?:mc:

Questo è più o meno quello che avevo in mente...

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//la progress bar si avvia
avvia();
info();
comprimi();
riempi();
//la progress bar arriva 100%
}

yorkeiser
24-11-2009, 16:52
Beh, ci sono vari modi (e molto più sofisticati, potresti usare un timer ad esempio), ma ad esempio puoi partire con una cosa semplice semplice come questa:


jpb = new JProgressBar(0, 100);
[...]

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//la progress bar si avvia
avvia();
jpb.setValue(25);
info();
jpb.setValue(50);
comprimi();
jpb.setValue(75);
riempi();
jpb.setValue(100);
//la progress bar arriva 100%
}

^TiGeRShArK^
24-11-2009, 21:14
http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html
Credo che sia la soluzione migliore se usi java 6...

miao84
25-11-2009, 14:21
@yorkeiser
con il tuo metodo non mi aggiorna la progress bar progressivamente ma solo alla fine del programma

yorkeiser
25-11-2009, 14:33
@yorkeiser
con il tuo metodo non mi aggiorna la progress bar progressivamente ma solo alla fine del programma

Suppongo si debba lanciare ogni volta un refresh sul pannello o sul singolo elemento grafico (ovvero la progress bar)
Prova a forzare il refresh dell'elemento con

jpb.repaint();

ogni volta che modifichi il valore.
O, in alternativa, attendi che passi qualcuno più esperto di me sulle GUI Java e su come funziona il refresh dell'interfaccia.

^TiGeRShArK^
25-11-2009, 15:06
non può funzionare perchè si deve lanciare in un altro thread altrimenti rimane bloccato l'EDT e di conseguenza anche il refresh dell'interfaccia grafica.
La soluzione standard è in questo caso quella che dicevo prima, lo SwingWorker che permette di gestire in maniera estremamente semplice il tutto senza stare ad impazzire con thread, sincronizzazioni e callback.
Nella pagina che ho linkato c'è un esempio completo di funzionamento di una Progress bar con lo Swing Worker.

yorkeiser
25-11-2009, 16:14
non può funzionare perchè si deve lanciare in un altro thread altrimenti rimane bloccato l'EDT e di conseguenza anche il refresh dell'interfaccia grafica.
La soluzione standard è in questo caso quella che dicevo prima, lo SwingWorker che permette di gestire in maniera estremamente semplice il tutto senza stare ad impazzire con thread, sincronizzazioni e callback.
Nella pagina che ho linkato c'è un esempio completo di funzionamento di una Progress bar con lo Swing Worker.

Mmmh, interessante.
E se io avessi lanciato quelle istruzioni nella run() di un thread creato ad hoc, piuttosto che lanciarle direttamente nell'ActionPerformed ? Ci sarebbe stato il refresh?

^TiGeRShArK^
25-11-2009, 16:24
Mmmh, interessante.
E se io avessi lanciato quelle istruzioni nella run() di un thread creato ad hoc, piuttosto che lanciarle direttamente nell'ActionPerformed ? Ci sarebbe stato il refresh?

ni, lanciando in un thread esterno quelle istruzioni avrebbe dato errore dato che avresti provato ad accedere al thread della GUI da un thread esterno...
Per fare le cose bene manualmente avresti dovuto usare SwingUtilities.InvokeLater()
cmq qui è spiegato abbastanza bene il tutto...
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html

miao84
25-11-2009, 21:24
Sono riuscito ad implementare SwingWorker abbastanza bene nel mio codice...solo che rimane il problema di "refresh" della progress bar. Ho cambiato la variabile "int progress" in globale e nelle varie parti dei miei metodi la incremento...solo che la progress bar si aggiorna solamente a fine programma o in alternativa se blocco momentaneamente il programma (per esempio aprendo una finestra di dialogo). Da quanto ho capito nel momento che avvio il task questo rimane in esecuzione mentre il resto del programma va avanti. Momentaneamente non ho il codice sotto,domani lo posto.

P.S:GRAZIE MILLE PER L'AIUTO DATO FINORA!!!:)

banryu79
25-11-2009, 23:55
I Java Tutorial sono tuoi amici :)
-> How to Use Progress Bars (http://java.sun.com/docs/books/tutorial/uiswing/components/progress.html)

miao84
07-12-2009, 15:00
I Java Tutorial sono tuoi amici :)
-> How to Use Progress Bars (http://java.sun.com/docs/books/tutorial/uiswing/components/progress.html)

bella risposta :rolleyes: Provo a spiegarmi meglio....la progress bar l'ho implementata e ora quando pigio il bottone parte un thread che ho realizzato (funziona nello stesso modo di SwingWorker solo che è più pulito secondo me) che finchè progress (variabile globale che viene incrementata dentro i metodi avvia() ecc.) non arriva a 100 rimane in esecuzione...se lancio solo il thread nel momento in cui clicco il bottone (commento quindi avvia() e gli altri metodi) e incremento progress dentro il thread stesso, la barra aumenta in tempo reale, mentre se lascio anche gli altri metodi all'interno dell'action performed del bottone non aumenta in tempo reale ma setta i vari progress in pochi millisecondi alla fine dell'esecuzione dell'action performed del bottone...spero di essere stato chiaro cmq...


public int progress=0;

......

public Client() {
initComponents();
progressBar.setMinimum(0);
progressBar.setMaximum(100);
progressBar.setValue(0);
progressBar.setStringPainted(true);
jButton1.addActionListener(new jButton1action());
}

.......

//CLICCO SUL BOTTONE PER FAR PARTIRE L'ESECUZIONE DEI METODI
public class jButton1action implements ActionListener{
public void actionPerformed (ActionEvent e){
new Thread(new thread1()).start(); //parte il thread che dovrebbe incrementare
avvia();
infodb();
comprimi();
jTextArea1.append("Fine Trasferimento!\n");
progressBar.setValue(100);
progressBar.repaint();
}
}

.......

public class thread1 implements Runnable{
public void run(){
while (progress<100){
progressBar.setValue(progress);
progressBar.repaint();
System.out.println(progressBar.getValue());//STAMPA IL VALORE DELLA PROGRESS BAR AGGIORNATO E LO STAMPA IN TEMPO REALE A DIFFERENZA DELLA PROGRESS BAR VISUALIZZATA
try{Thread.sleep(400);} //Sleep
catch (InterruptedException err){}
}
}
}

naturalmente progress come detto sopra lo incremento nei metodi...sono diversi giorni che provo e riprovo, ho visto i tutorial ma probabilmente faccio un errore di fondo io...:mc: :mc:

EDIT: come la progress bar non mi aggiorna in tempo reale nemmeno la jTextArea. L'unica "gabola" che ho trovato per far scorrere entrambi in tempo reale, come già detto è avviare un Message dialog dopo ogni incremento, ma non posso certo lasciare che per ogni aggiornamento della barra compaia una finestra...

PGI-Bis
07-12-2009, 15:52
Quel thread non va bene. Ti faccio un esempio con swing worker, ritagliato sullo schema del tuo codice:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class Main {

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new Main().createAndShowUI();
}
});
}

private void createAndShowUI() {
final int AVVIA = 0;
final int INFO = 1;
final int COMPRIMI = 2;
final int RIEMPI = 3;
final int FINE = 4;

final JFrame window = new JFrame("Test");
final JProgressBar bar = new JProgressBar(0, 100);
final JDialog progressDialog = new JDialog(window, true);

progressDialog.add(bar);
bar.setStringPainted(true);

final JButton button = new JButton(new AbstractAction("Avvia") {

public void actionPerformed(ActionEvent e) {

new SwingWorker<Void, Integer>() {

public Void doInBackground() {
publish(AVVIA);
avvia();
publish(INFO);
info();
publish(COMPRIMI);
comprimi();
publish(RIEMPI);
riempi();
publish(FINE);
fine();
return null;
}

public void process(java.util.List<Integer> steps) {
for(final Integer step : steps) {
switch(step) {
case AVVIA:
bar.setValue(0);
bar.setString("Avvio");
progressDialog.pack();
progressDialog.setLocationRelativeTo(null);
progressDialog.setVisible(true);
break;
case INFO:
bar.setValue(25);
bar.setString("Info");
break;
case COMPRIMI:
bar.setValue(50);
bar.setString("Comprimi");
break;
case RIEMPI:
bar.setValue(75);
bar.setString("Riempi");
break;
case FINE:
bar.setValue(100);
bar.setString("Fine");
break;
}
}
}
}.execute();
}
});

window.add(button);
window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
window.setLocationRelativeTo(null);
window.pack();
window.setVisible(true);
}

public void avvia() {
pausa(1000);
}

public void info() {
pausa(1000);
}

public void comprimi() {
pausa(1000);
}

public void riempi() {
pausa(1000);
}

public void fine() {

}

private void pausa(long time) {
try {
Thread.sleep(time);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}

La questione è relativamente semplice, si tratta solo di intervallare le invocazioni in background con gli aggiornamento dell'EDT.

miao84
09-12-2009, 09:09
grazie per la risposta, comunque ho trovato una soluzione più breve ed efficiente facendo partire un'altro thread con all'interno i metodi. Quindi due thread in parellelo fanno si che la progress bar si muova in tempo reale:sofico: :sofico: :sofico: . ciao e grazie a tutti per il supporto!!!

PGI-Bis
09-12-2009, 09:37
se uno dei due thread non è l'edt la soluzione non è più efficiente, è sbagliata.