|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: May 2005
Messaggi: 340
|
[Java] Thread
Ho un problema....
Quando creo una classe estesa da Thread ( una balla di caricamento ), non riesco a farla scorrere prima del termine dell'operazione. Ho provato a mettere l'operazione che faccio successivamente come un Thread ma nemmeno questo influsice, la barra appare ma come se fosse bloccata. Appena il progesso finisce, si sblocca e si muove. |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: May 2005
Messaggi: 340
|
Per essere piu preciso:
La classe per il caricamento : Codice:
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
/**
*
* @author c.bianchini
*/
public class Caricamento extends Thread {
private javax.swing.JLabel jLabel1;
private javax.swing.JProgressBar jProgressBar1;
private JFrame frame;
private Thread t;
private String testo,testo2;
/** Creates a new instance of Caricamento */
public Caricamento(int g,String testo,String testo2) {
this.testo = testo;
this.testo2 = testo2;
// t = new Thread(this);
}
public void SetTesto(String testo) {
jLabel1.setText(testo);
}
public void Invisibile() {
frame.setVisible(false);
}
public void Visibile() {
frame.setVisible(true);
}
public void run() {
System.out.println("aaaa");
jProgressBar1 = new javax.swing.JProgressBar();
jLabel1 = new javax.swing.JLabel();
frame = new JFrame(testo);
frame.setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
frame.setResizable(false);
jProgressBar1.setIndeterminate(true);
jLabel1.setText(testo2);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(frame.getContentPane());
frame.getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1)
.addContainerGap(356, Short.MAX_VALUE))
.addComponent(jProgressBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel1))
);
frame.pack();
frame.setVisible(true);
}
}
Codice:
Caricamento load2 = new Caricamento(100,"Sto applicando le ACL...",""); load2.start(); ACL a = new ACL(); |
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: May 2005
Messaggi: 340
|
up up up
|
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: May 2005
Messaggi: 340
|
up
|
|
|
|
|
|
#5 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
L'EDT è il Thread che Swing usa per disegnare i componenti e gestire gli eventi. Parte e lavora automaticamente.
Il sintomo che descrivi è quello di un sovraccarico di questo EDT. L'apertura di una finestra richiede che l'EDT esegua una successione di compiti. Se tra l'inizio e la fine di questa successione infilassimo la richiesta di esecuzione di un compito oneroso, allora potremmo vedere una finestra non pienamente funzionante. A prescindere da questo il codice che proponi nasconde una precondizione che contraddittoria. Vale a dire che pur essendo "Caricamento" un Thread, l'invocazione del suo metodo start() è sempre un errore logico. L'errore sta in ciò che i due enunciati contenuti nel metodo run() di Caricamento: frame.pack(); frame.setVisible(true); devono obbligatoriamente essere eseguite dall'EDT. L'invocazione di start() su un Caricamento ne causa invece sempre ed inevitabilmente l'esecuzione in un Thread diverso dall'EDT. Lo stesso vale per i metodi visible(), invisible() e setTesto(String) (il bon ton Javesco vuole che i metodi inizino sempre con una lettera minuscola). Una possibile soluzione "parallelamente corretta" del problema è facile ma articolata. Richiede la presenza di un Thread diverso dall'EDT che blocca il flusso di esecuzione quando incontri una richiesta "apri la finestra di caricamento" e rilasci tale blocco quando la finestra risulti pienamente visibile. Lo stesso dovranno fare i metodi visible() e invisible() mentre setTesto(String) può limitarsi ad affidare gli enunciati ora direttamenti all'esecuzione indiretta tramite EDT.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: May 2005
Messaggi: 340
|
Quote:
|
|
|
|
|
|
|
#7 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Vediamo prima una versione breve. Se il compito da eseguire è apprezzabilmente lungo ed è affidato ad un Thread diverso dall'EDT allora basta e avanza.
Creo prima un'interfaccia per rendere chiaro quale sia l'insieme di capacità di questa finestra di progresso, a prescindere da come siano portati avanti i lavori. Codice:
package workinprogress;
/** Questa è la dichiarazione di ciò che farà la finestra di dialogo con
la barra di avanzamento. */
public interface ProgressDialog {
/** Imposta il testo proiettato nella finestra. */
void setTesto(String testo);
/** Chiude la finestra di avanzamento. */
void invisible();
/** Apre la finestra di avanzamento. */
void visible();
}
Codice:
package workinprogress;
public class Main {
public static void main(String[] args) {
//questi enunciati sono eseguiti dal Thread "Main"
ProgressDialog dialog = new SwingProgressDialog();
try {
dialog.visible(); //apre la finestra
dialog.setTesto("Avvio..."); //primo messaggio
sleep(1000); //simula un passaggio del compito eseguito dal Thread diverso dall'EDT
dialog.setTesto("Proseguimento..."); //messaggio
sleep(1000); //passo simulato
dialog.setTesto("Fine..."); //messaggio
sleep(1000); //passo simulato
} finally {
dialog.invisible(); //chiude la finestra
}
}
private static void sleep(long ms) {
try {
Thread.sleep(ms);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
Per farlo esiste un meccanismo ad hoc. Prendi gli enunciati che interagiscono con un componente Swing proiettabile e li metti nel metodo run di un Runnable. Poi passi quel Runnable al metodo invokeLater di EventQueue. Cioè se vuoi invocare: frame.pack(); frame.setVisible(true); scrivi: Codice:
Runnable task = new Runnable() {
public void run() {
frame.pack();
frame.setVisible(true);
}
};
EventQueue.invokeLater(task);
Detto questo, la versione concreta di ProgressDialog è facilmente immaginabile. Codice:
package workinprogress;
import java.awt.*;
import javax.swing.*;
/** Questo è come lo fa. */
public class SwingProgressDialog implements ProgressDialog {
private JLabel textLabel = new JLabel();
private JFrame window = new JFrame("Work in progress.");
private JProgressBar progressBar = new JProgressBar();
public SwingProgressDialog() {
window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
textLabel.setPreferredSize(new Dimension(300, 150));
textLabel.setHorizontalAlignment(JLabel.CENTER);
progressBar.setIndeterminate(true);
JPanel container = new JPanel(new BorderLayout(8, 8));
container.add(textLabel, BorderLayout.CENTER);
container.add(progressBar, BorderLayout.SOUTH);
container.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
window.add(container);
}
public void visible() {
Runnable edtTask = new Runnable() {
public void run() {
window.pack();
window.setVisible(true);
}
};
EventQueue.invokeLater(edtTask);
}
public void invisible() {
Runnable edtTask = new Runnable() {
public void run() {
window.setVisible(false);
window.dispose();
}
};
EventQueue.invokeLater(edtTask);
}
public void setTesto(final String text) {
Runnable edtTask = new Runnable() {
public void run() {
textLabel.setText(text);
}
};
EventQueue.invokeLater(edtTask);
}
}
SwingProgressDialog x = new SwingProgressDialog(); puoi invocare i metodi visible, invisible e setTesto da un Thread diverso dell'AWT Event Dispatcher (sempre l'EDT, nome proprio) nel pieno rispetto di Swing e del risultato voluto. L'invocazione degli stessi metodi da parte dell'EDT può invece causare risultati inattesi. In particolare, può non apparire un bel niente, le cose possono non essere aggiornate come dovrebbero eccetera. Ciò capita se al normale compito di disegno affianchi procedimenti che siano onerosi in termini di tempo o di risorse di calcolo. E' una cosa che andrebbe comunque evitata per cui la più complessa "soluzione B" non dovrebbe essere necessaria.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#8 |
|
Senior Member
Iscritto dal: May 2005
Messaggi: 340
|
Codice:
Compiling 1 source file to C:\Documents and Settings\xxx\ACL\build\classes
C:\Documents and Settings\xxx\ACL\src\acl\Caricamento.java:66: cannot find symbol
symbol: class ProgressDialog
public class Caricamento implements ProgressDialog {
1 error
BUILD FAILED (total time: 0 seconds)
|
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
E' contenuta nei sorgenti che ho incollato (il primo, è un'interfaccia) ma l'ho messa solo per evidenziare il contratto. Tu puoi anche togliere quell' "implements ProgressDialog" e usare direttamente SwingProgressDialog.
Poi probabilmente userai delle classi tue, questo è solo un esempio del modo.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: May 2005
Messaggi: 340
|
Niente... funziona allo start del programma ma quando avvio la procedura di eseguire delle operazione è come prima:
Codice:
public class Caricamento {
private javax.swing.JLabel jLabel1;
private javax.swing.JProgressBar jProgressBar1;
private JFrame frame;
private String testo,testo2;
public Caricamento(String testo, String testo2) {
this.testo = testo;
this.testo2 = testo2;
jProgressBar1 = new javax.swing.JProgressBar();
jLabel1 = new javax.swing.JLabel();
frame = new JFrame(testo);
frame.setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
frame.setResizable(false);
jProgressBar1.setIndeterminate(true);
jLabel1.setText(testo2);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(frame.getContentPane());
frame.getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1)
.addContainerGap(356, Short.MAX_VALUE))
.addComponent(jProgressBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel1))
);
frame.pack();
frame.setVisible(true);
}
public void SetTesto(final String testo) {
Runnable edtTask = new Runnable() {
public void run() {
jLabel1.setText(testo);
}
};
EventQueue.invokeLater(edtTask);
}
public void Invisibile() {
Runnable edtTask = new Runnable() {
public void run() {
frame.setVisible(false);
frame.dispose();
}
};
EventQueue.invokeLater(edtTask);
}
public void Visibile() {
Runnable edtTask = new Runnable() {
public void run() {
frame.pack();
frame.setVisible(true);
}
};
EventQueue.invokeLater(edtTask);
}
}
|
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Prima di lanciare la "procedura" scrivi:
System.out.println(Thread.currentThread()); Verifica che il Thread che esegue la procedura non sia l'EDT. (AWT Event Dispatcher). Se sì, allora devi affidare l'esecuzione della procedura ad un Thread diverso.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#12 | |
|
Senior Member
Iscritto dal: May 2005
Messaggi: 340
|
Quote:
Scusa ma non sono molto afferato con sti Thread, mi dai una mano a "Se sì, allora devi affidare l'esecuzione della procedura ad un Thread diverso." Grazie |
|
|
|
|
|
|
#13 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Diciamo che ACL è un oggetto che possiede i metodi necessari all'esecuzione dell'operazione.
Ora hai una cosa di questo genere: Codice:
Caricamento car = new Caricamento();
ACL acl = new ACL();
try {
car.visible();
acl.computazioneUno();
car.setTesto("blabla");
acl.computazioneDue();
car.setTesto("blibli");
finally {
car.invisible();
}
Bene, la soluzione sta nell'affidare l'esecuzione delle computazioni ad un Thread ad hoc. Caricamento, per via di quella ridda di EventQueue.invokeLater, è perfettamente in grado di operare in un contesto concorrente (2 thread, l'EDT e il tuo). La stessa cosa di prima ora sarà: Codice:
new Thread() { public void run() {
Caricamento caricamento = new Caricamento();
ACL acl = new ACL();
try {
caricamento.visible();
acl.computazione();
caricamento.setText("blabla");
acl.computazione();
caricamento.setText("blibli");
acl.computazione();
} finally {
caricamento.invisible();
}
}}.start();
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#14 |
|
Senior Member
Iscritto dal: May 2005
Messaggi: 340
|
Ti posso baciare?
|
|
|
|
|
|
#15 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Calma e gesso.
A seconda del tipo di applicazione, potresti incontrare altri problemi nell'uso di quel componente Caricamento. In particolare, la finestra che si apre non è modale, quindi non impedisce all'utente di premere un'altra volta il pulsante nè rimane in primo piano rispetto al resto dell'applicazione. Insomma, non è ancora detto che quella sia anche la soluzione che ti serve. Devi vedere un po' il programma cosa richiede.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 14:30.



















