syntaxhighlighter.googlecode.com

niedziela, 2 lutego 2014

Swing - obsługa długo trwających akcji

Problem dotyczy obsługi akcji w Swingu, w których występuje długie przetwarzanie danych. Pojawia się problem blokady wątku Swinga - kontrolki Swinga w tym czasie "nie żyją".

Oto rozwiązanie problemu, przy pomocy klasy SwingWorker, dostępnej w Java SE (od wersji 6).
Idea jest następująca:
  1. Tworzymy obiekt SwingWorker
  2. nadpisujemy metodę doInBackground() - tu umieszczamy logikę, która może trwać dowolnie długo
  3. nadpisujemy metodę done() - tu dajemy kod modyfikujący kontrolki Swinga
  4. Całość uruchamimay przez metodę execute()


package pl.prv.wojsal.action;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;

import org.apache.log4j.Logger;

import pl.prv.wojsal.utils.UtCzas;
import pl.prv.wojsal.utils.UtLog;

/**
 * <pre>
 * <ul>
 * <li>Projekt: wsSwing
 * <li>Klasa:
 * <li>Opis: Obsluga akcji o dlugim czasie przetwarzania
 * <li>Utworzono: 02-02-2014, 14:24:12
 * <li>author: (c) Wojciech Salata
 * </ul>
 * </pre>
 */

public class ObslugaDlugiejAkcji {

    private static Logger    log    = Logger.getLogger(ObslugaDlugiejAkcji.class.getName());

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        UtLog.initLog4jForTests();
        ObslugaDlugiejAkcji m = new ObslugaDlugiejAkcji();
        m.run();
    }

    private JFrame    fr;

    /**
     *
     */
    private void run() {
        JPanel panel = new JPanel();
        final JLabel lb1 = new JLabel("Label chowany/pokazywany przez Bt1");
        panel.add(lb1);
        final JLabel lb2 = new JLabel("Label chowany/pokazywany przez Bt2");
        panel.add(lb2);

        JButton bt1 = new JButton("Button 1 (dluga akcja)");
        bt1.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                log.debug("Obsluga akcji bt1 - start");

                final ObslugaDlugiejAkcji oa1 = new ObslugaDlugiejAkcji();
                oa1.run();
                // UtCzas.sleep("To jest zle - to musi byc w doInBackground()");
                log.debug("Po oa1.run()");
                SwingWorker<Object, Object> sw = new SwingWorker<Object, Object>() {

                    @Override
                    protected Object doInBackground() throws Exception {
                        UtCzas.sleep("Czekamy na koniec akcji bt1");
                        log.debug("Koniec dlugiego przetwarzania bt1");
                        return null;
                    }

                    @Override
                    protected void done() {
                        boolean visible = lb1.isVisible();
                        lb1.setVisible(!visible);
                        oa1.dispose();
                        log.debug("Usuniete oa1");
                    }
                };
                sw.execute();

                log.debug("Obsluga akcji bt1 - koniec");
            }
        });
        panel.add(bt1);
        JButton bt2 = new JButton("Button 2");
        bt2.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                log.debug("Obsluga akcji bt2 - start");
                boolean visible = lb2.isVisible();
                lb2.setVisible(!visible);
                log.debug("Obsluga akcji bt2 - koniec");
            }
        });
        panel.add(bt2);
        this.fr = new JFrame();
        fr.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        fr.getContentPane().add(panel);
        fr.setSize(300, 200);
        fr.setVisible(true);
    }

    /**
     *
     */
    protected void dispose() {
        this.fr.dispose();
    }


}