2010-08-12 11 views
6

Questo è per gli esperti di swing là fuori. Ho dedicato molto tempo a questo problema, quindi mi porterò qualche riga per spiegare il problema.Barra di avanzamento swing Java dal problema EDT

Ho un'applicazione standalone java swing (java 6). Nella mia applicazione, ho una cornice con un gruppo di pulsanti di opzione. Ho una singola azione collegata a tutti i pulsanti del gruppo. L'azione controlla per vedere quale pulsante di opzione è selezionato ed esegue un po 'di lavoro. Il "lavoro" comporta alcuni calcoli in background e alcuni dipinti in altri due frame nella mia applicazione. Il calcolo dello sfondo è multi-thread.

Vorrei visualizzare una barra di avanzamento quando l'utente seleziona uno dei pulsanti di opzione. Tuttavia, quando viene selezionato un pulsante di opzione, mentre l'azione sul pulsante di opzione è in corso, la barra di avanzamento non viene mai visualizzata. Ho provato barre di avanzamento di tipo jdialog, pannelli di vetro, ecc. Nessuno di essi appare fino a quando il "lavoro" è tutto completato. Questo sembra essere dovuto al fatto che Swing non finisce di dipingere il pulsante radio finché non viene completato il "lavoro" nell'azione corrispondente. E poiché l'EDT esegue solo una cosa alla volta, la finestra di dialogo della barra di avanzamento (o riquadro di vetro) non viene mai visualizzata.

Ho quindi provato a utilizzare uno SwingWorker per fare tutto questo "lavoro". Avviare la barra di avanzamento (o attivare un riquadro di vetro), avviare SwingWorker e chiudere la barra di avanzamento (o disattivare il pannello di vetro) nel metodo done() per SwingWorker. Questo sembra far apparire bene la barra di progresso, ma il dipinto che fa parte del "lavoro" a volte non è completato, lasciandomi con alcuni artefatti di pittura (il metodo paintComponent è piuttosto complicato, quindi non voglio riprodurlo qui). Gli artefatti scompaiono se ridimensiono la finestra. In effetti, questo succede se uso una classe che estende Thread al posto di SwingWorker. Questo perché Swing non è protetto da thread e sto provando a fare il lavoro con la GUI da un thread diverso da EDT. Capisco quella parte.

Cosa devo fare? "lavoro" dura circa 30 secondi e sembra troppo lungo per andare senza mostrare all'utente una sorta di indicazione che il programma sta funzionando. Ho anche provato a cambiare il cursore in un cursore di attesa e ho incontrato gli stessi problemi di cui sopra. L'unica cosa che posso fare è disabilitare il frame e impostare il titolo del frame su un testo come "working ..."

Qualcuno ha già visto questo problema?

risposta

4

Penso che tu abbia ragione nel fare il lavoro nel thread di SwingWorker, ma non dovresti provare a fare la tua pittura lì.

sarei propenso a:

  • Avere lo spettacolo ActionListener() la barra di avanzamento, partì lo SwingWorker quindi uscire

  • Avere il thread di lavoro fare il lavoro, e periodicamente chiamare repaint() sul componente della barra di avanzamento (questo è garantito per essere thread-safe)

  • La barra di avanzamento ha il proprio paintComponent (che verrà chiamato automaticamente sull'EDT). Se necessario, è possibile leggere alcune variabili aggiornate dal thread di lavoro per misurare i progressi

  • Al termine del thread di lavoro, chiamare invokeLater() per eseguire una funzione di chiusura finale sull'EDT, che nasconderà il barra di avanzamento e fare qualsiasi altra pulizia GUI correlati/mostrano un messaggio di completamento per l'utente, ecc

+0

Come faccio a garantire che l'EDT non esegua nessun altro disegno fino a quando il lavoro sul thread SwingWorker non è completato? Il lavoro che può essere svolto in background deve essere completato prima che i miei fotogrammi vengano nuovamente dipinti. – Anu

+0

Grazie! L'ho fatto funzionare. – Anu

4

Quando hai spostato il lavoro dall'EDT al lavoratore dell'oscillazione (che era la cosa giusta da fare), sembra che sia il lavoro sia il dipinto siano stati trasferiti allo swing worker. Il dipinto dovrebbe ancora accadere sull'EDT. È possibile ottenere ciò utilizzando SwingUtilities.invokeLater per richiamare un repaint dal thread in background o utilizzando lo SwingWorker.publish(V...), che prenderà le notifiche dal thread di lavoro e renderle disponibili sull'EDT tramite il metodo di modello SwingWorker.process(V...) (che si sovrascrive). L'override process può gestire le notifiche intermedie ridipingendo una parte dello schermo, aggiornando i progressi o prendendo altre azioni appropriate come desiderato. Qualsiasi modifica dell'interfaccia utente eseguita qui sarà visibile senza attendere il completamento del resto del lavoro.

+0

Grazie, ho ottenuto la soluzione di Mikera a lavorare, ma i suoi commenti su aver spostato il dipinto al EDT pure stimolato la Ho cambiato le cose! – Anu

+0

Utilizzare SwingWorker.publish() sul thread di lavoro è la strada da percorrere, credo. – keuleJ

Problemi correlati