Swing Ausführung einer SwingWorker Klasse stoppen

ralfb1105

Bekanntes Mitglied
Hallo,

für ein DB Test Programm möchte ich bestimmte Test Sequenzen in einer Klasse starten die während der Ausführung Ausgaben in einem JTextArea ausgibt. Um Das GUI nicht zu blockieren habe ich hier schon gelernt das ich die SwingWorker Klasse benutzen sollte, welche eine Nebenläufigkeit implementiert. Bevor ich diese Klasse mit den Tests nun starte "ziehe" ich einen Timer auf der die Test Laufzeit herunterzählt und die aktuell noch verbleibende Zeit anzeigt. Letzeres funkttioniert nun auch nach guter Hilfe von Euch hier im Forum 🙂

Ich habe mir nun gedacht, das ich innerhalb der Klasse in dem ich den Timer runterzähle und ausgebe die neue DbTest Klasse aufrufe, und nach Beendigung des Timer diese auch wieder stoppe. Hier sind wir nun bei meinem Problem 🙁 Ich kann den Timer und die DBTest Klasse starten, beide geben Ihre Ausgaben aus, aber nach Beendigung des Timer kann ich die DbTest Klasse nicht stoppen - NullPointerException 🙁

Hier nun der Code den ich verwendet habe:
1. Klasse die den Timer enthält und auch die DbTest Klasse (ProcessWorkerDbTest) startet

Java:
class ProcessWorkerCounter extends SwingWorker<Void, String>
    {
        private JLabel jLCounter;
        private long seconds;
        Timer timer = null;
        ProcessWorkerDbTest pt = null;
       
        public ProcessWorkerCounter(JLabel counter, long seconds)
        {
            this.jLCounter = counter;
            this.seconds = seconds;
        }


        @Override
        protected Void doInBackground() throws Exception
        {
            //hier läuft alles in einem eigenen Thread (nebenläufig) ab. Es ist also egal wie lange die Abarbeitung hier dauert.
           
                timer = new Timer(1000, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                            seconds--;
                            long hh = seconds / 3600;
                            long mm = (seconds % 3600) / 60;
                            long ss = seconds - (hh * 3600) - (mm * 60);
                            DecimalFormat format = new DecimalFormat("00");
                            publish(format.format(hh) + ":" + format.format(mm) + ":" + format.format(ss));
                            if (seconds == 0) {
                                timer.stop();
                                publish("Test finished!");
                                pt.cancel(true);
                        }
                       
                    }
                });
                timer.start();
                clearOutputArea();
                ProcessWorkerDbTest pt = new ProcessWorkerDbTest(jTAOutput);
                pt.execute();
            return null;
        }
       
        @Override
        protected void process(List<String> chunks)
        {
            //hier läuft alles auf dem EDT (Event Dispatch Thread). Darum können (und sollten) wir hier die GUI Komponenten manipulieren.
            for(int i = 0; i < chunks.size(); i++)
            {
                jLCounter.setText(chunks.get(i));
                //jTAOutput.append(System.getProperty("line.separator"));
            }
        }
    }
2. Die Klasse die den DbTest simuliert - noch kein echter Code 😵

Java:
class ProcessWorkerDbTest extends SwingWorker<Void, String>
    {
        private JTextArea jTAOutput;
       
        public ProcessWorkerDbTest(JTextArea textArea)
        {
            this.jTAOutput = textArea;
        }


        @Override
        protected Void doInBackground() throws Exception
        {
            //hier läuft alles in einem eigenen Thread (nebenläufig) ab. Es ist also egal wie lange die Abarbeitung hier dauert.
            while (!isCancelled()) {
                for (int i=1000; i>=0; i--) {
                    publish("DB Test Run: " + i);
                    TimeUnit.SECONDS.sleep(1);
                }
            }
            return null;
        }
       
        @Override
        protected void process(List<String> chunks)
        {
            //hier läuft alles auf dem EDT (Event Dispatch Thread). Darum können (und sollten) wir hier die GUI Komponenten manipulieren.
            for(int i = 0; i < chunks.size(); i++)
            {
                jTAOutput.append(chunks.get(i));
                jTAOutput.append(System.getProperty("line.separator"));
            }
        }
    }

Der Start überfolgt einen Button:

Java:
private void jBStartCounterActionPerformed(ActionEvent evt) {
        long hours = Long.parseLong(jTFHour.getText());
        long minutes = Long.parseLong(jTFMinute.getText());
        long seconds = Long.parseLong(jTFSecond.getText());
        seconds = (hours * 3600) + (minutes * 60) + seconds;
        ProcessWorkerCounter pc = new ProcessWorkerCounter(jLCounter, seconds);
        pc.execute();
    }

Problem: Nach Ablauf des Timer, also beim Aufruf von
Java:
pt.cancel(true);
bekomme ich eine NullPointerException:
Code:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at oracle.OraAccess$ProcessWorkerCounter$1.actionPerformed(OraAccess.java:258)
    at javax.swing.Timer.fireActionPerformed(Unknown Source)
    at javax.swing.Timer$DoPostEvent.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

Über eine Idee was ich hier falsch mache wäre ich sehr dankbar. Danke Euch schon mal.

Gruß

Ralf
 
Hallo Robat,

Danke für Deine schnelle Antwort. Da ich blutiger Java Anfänger bin muss ich gestehen das ich nicht weiß wo ich Deine Antwort im Code "einsortieren" soll ... ??

Ich muss doch ein neues Objekt der Klasse "ProcessWorkerDbTest" erstellen um dann die Ausführung mittels Objekt.execute() zu starten .. oder bin ich jetzt komplett falsch unterwegs ??

Es wäre toll wenn Du mir an Hand meines Codes schreiben lönntest wo ich Deiner Meinung nach den Fehler habe. Danke schon mal für Deine Hilfe!

Gruß
Ralf
 
Vielleicht hier mal zum Verständnis dein Code ein wenig gekürzt und mit Kommentaren.
Java:
    private ProcessWorkerDbTest pt = null;  // (1)
   
    @Override
        protected Void doInBackground() throws Exception
        {
                timer = new Timer(1000, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                            ..
                           if (seconds == 0) {
                                ...
                                pt.cancel(true);   // dieses pt bezieht sich auf das mit (1) markierte Objekt .. welches noch NULL ist .. daher auch die NullPointerException
                        }
                      
                    }
                });
                ...
                ProcessWorkerDbTest pt = new ProcessWorkerDbTest(jTAOutput); (2)
                 // hier erstellst du ein neues Objekt was du auch pt nennst. Dieses hat aber nichts mit dem
                 // mit (1) markierten Objekt zu tun. Dies bleibt immer NULL
                 // anstatt ein zweites Objekt zu erstellen was auch pt heißt, solltet du das eigentliche Objekt initialisieren.
                pt.execute();
            return null;
        }
 
Hallo Robat,

ja so ist das mit den Anfängern 🙄
DANKE für Deine Erklärungen .. jetzt ist es auch mir klar 😉 habe die Klasse jetzt folgendermassen geändert:
Java:
class ProcessWorkerCounter extends SwingWorker<Void, String>
    {
        private JLabel jLCounter;
        private long seconds;
        Timer timer = null;
        ProcessWorkerDbTest pt = new ProcessWorkerDbTest(jTAOutput);
        //ProcessWorkerDbTest pt = null;
       
        public ProcessWorkerCounter(JLabel counter, long seconds)
        {
            this.jLCounter = counter;
            this.seconds = seconds;
        }


        @Override
        protected Void doInBackground() throws Exception
        {
            //hier läuft alles in einem eigenen Thread (nebenläufig) ab. Es ist also egal wie lange die Abarbeitung hier dauert.
           
                timer = new Timer(1000, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                            seconds--;
                            long hh = seconds / 3600;
                            long mm = (seconds % 3600) / 60;
                            long ss = seconds - (hh * 3600) - (mm * 60);
                            DecimalFormat format = new DecimalFormat("00");
                            publish(format.format(hh) + ":" + format.format(mm) + ":" + format.format(ss));
                            if (seconds == 0) {
                                pt.cancel(true);
                                timer.stop();
                                publish("Test finished!");
                                pt.printFinishMessage("\nDB Test finishing ...\n");
                               
                        }
                       
                    }
                });
                timer.start();
                clearOutputArea();
                pt.execute();
               
            return null;
        }
Jetzt gibt es nur ein Objekt "pt" und dieses wird gestartet (pt.execute()) und auch wieder gestoppt über das "cancel" flag der SwingWorker Klasse (pt.cancel(true)).

Vielen Dank noch einmal!!!

Gruß

Ralf
 

Zurück
Oben