Avatar billede ellebaek Nybegynder
28. april 2003 - 20:35 Der er 26 kommentarer og
1 løsning

ProgressMonitor

Jeg er igang med at lave et script der kan kryptere/dekryptere med AES kryptering. Dette virker også glimrende. Men når jeg skal koble dette sammen med en GUI vil jeg gerne have en progressmonitor der kan fortælle brugeren hvordan det står til med processsen.

Jeg har testet AES delen, og her er der ingen problemer med de værdier jeg benytter til GUIen.

Jeg har så i GUI'en defineret en ProgressMonitor som jeg vil benytte. Denne benytter en timerListener der kaldes hvert sekund og opdatere monitoren. Men monitoren vises aldrig. Jeg har så testet dette script og skriver ud hver gang Listeneren skal kaldes, men den kaldes først efter krypteringen er færdig.

Jeg er rimelig på herrens mark med dette så jeg håber på hjælp!

//Delen der kalder encrypt. og derved også progressmonitoren
timer = new Timer(ONE_SECOND, new TimerListener());
            aes = new Stream_AES(fileIn,fileOut,keyField.getText(),(new Integer(keyBitSize)).intValue());
            progressMonitor = new ProgressMonitor(design.this, "Encrypting...","", 0, aes.getLength());
            progressMonitor.setProgress(0);
            progressMonitor.setMillisToPopup(ONE_SECOND/2);
           
            String fileOut = outFile.getText();
            timer = new Timer(ONE_SECOND, new TimerListener());
            Stream_AES aes = new Stream_AES(fileIn,fileOut,keyField.getText(),(new Integer(keyBitSize)).intValue());
            progressMonitor = new ProgressMonitor(design.this, "Encrypting...","", 0, aes.getLength());
            progressMonitor.setProgress(0);
            progressMonitor.setMillisToPopup(ONE_SECOND/2);
           
                  t = System.currentTimeMillis();
            System.out.println(aes.getLength());
            if (typOfAction.equals("Encrypt")) {
            encrypt.setEnabled(false);
            timer.start();
            aes.encrypt();
            //t = System.currentTimeMillis() - t;
            //encrypt.setEnabled(true);
            }
            else {
            decrypt.setEnabled(false);
            aes.decrypt();
            timer.start();
            //t = System.currentTimeMillis() - t;
            //decrypt.setEnabled(true);
            }

//Timerlisteneren
    class TimerListener implements ActionListener {
        public void actionPerformed(ActionEvent evt) {
        System.out.println("hej");
        progressMonitor.setNote("Completed" + aes.getCurrent() + " of " + aes.getLength());
        progressMonitor.setProgress(aes.getCurrent());
        String test = "";
            if (progressMonitor.isCanceled() || aes.done()) {
        progressMonitor.close();
            Toolkit.getDefaultToolkit().beep();
        if (aes.done())
            System.out.println("færdig");
                timer.stop();
        t = System.currentTimeMillis() - t;
        if (typOfAction.equals("Encryption"))
            encrypt.setEnabled(true);
        else
            decrypt.setEnabled(true);
        if (test.equals("canceled"))
            response = typOfAction + " canceled";
        else if (aes.done()) {
              response = typOfAction + " completed in " + t + " ms";
           
          }
Mvh. Jens Ellebæk
Avatar billede arne_v Ekspert
28. april 2003 - 21:05 #1
Hvor lang tid tager krypteringen ?
Avatar billede ellebaek Nybegynder
28. april 2003 - 21:06 #2
forskelligt....

Den jeg har testet på tager 8-10 sek...
Avatar billede arne_v Ekspert
28. april 2003 - 21:41 #3
Hm.

Jeg har lidt svært ved helt at gennemskue din kode.

Men jeg har lavet et lille eksempel med en DummyEncrypter som
ser ud til at virke fint:

package test;

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

public class ProgTest extends JFrame {
    private final static int N = 100;
    private ProgressMonitor progressMonitor;
    private Timer timer;
    private DummyEncrypter aes = new DummyEncrypter();
    public ProgTest() {
        super();
        progressMonitor =
            new ProgressMonitor(this, "Encryption", "Running", 0, N);
        progressMonitor.setProgress(0);
        timer = new Timer(1000, new TimerListener());
        timer.start();
        aes.encrypt();
    }
    class TimerListener implements ActionListener {
        public void actionPerformed(ActionEvent evt) {
            progressMonitor.setProgress(aes.getCurrent());
            if (aes.isDone()) {
                timer.stop();
            }
        }
    }
    public static void main(String[] args) throws Exception {
        ProgTest f = new ProgTest();
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.pack();
        f.setVisible(true);
    }
}

class DummyEncrypter {
    private final static int N = 100;
    private int n = 0;
    public int getCurrent() {
        if (n < N)
            n++;
        return n;
    }
    public boolean isDone() {
        return (n >= N);
    }
    public void encrypt() {
        while (!isDone()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
        }
    }
}
Avatar billede arne_v Ekspert
28. april 2003 - 21:42 #4
Prøv med den kode og din rigtige encrypter.

Hvis det virker, så bygger du videre på det.
Avatar billede ellebaek Nybegynder
28. april 2003 - 21:51 #5
den kommer frem med progressmonitoren nu, men den når at afslutte krypteringen inden den kommer frem. Det er som om krypteringen tager alle resourcer og derefter kan den starte monitoren.

Men så står den naturligvis bare på det sted hvor den er nået, i dette tilfælde 6 af 100...

Jeg forstår det ikke..
Avatar billede arne_v Ekspert
28. april 2003 - 21:56 #6
Har du mulighed for at putte nogle:

            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
            }

ind i din kryptering efter hver 1 MB eller 100 KB eller noget ?
Avatar billede arne_v Ekspert
28. april 2003 - 21:57 #7
Eller endnu bedre bare:

Thread.yield();
Avatar billede ellebaek Nybegynder
28. april 2003 - 21:59 #8
prøver lige...!

skal try skal være omkring alt det der sender videre til selve krypteringen ??
Avatar billede arne_v Ekspert
28. april 2003 - 22:02 #9
try catch skal kun lige omkring sleep.

Men brug yield i.s.f..
Avatar billede ellebaek Nybegynder
28. april 2003 - 22:11 #10
try {
                Thread.yield();
        }
        catch (InterruptedException e) {
            }

Satte dette ind, og har declareret exceptionen i klassen, men får følgende fejl..
Stream_AES.java:113: exception java.lang.InterruptedException is never thrown in body of corresponding try statement
        catch (InterruptedException e) {
            ^
Stream_AES.java:229: unreported exception java.lang.InterruptedException; must be caught or declared to be thrown
    stream1.encrypt();
Avatar billede arne_v Ekspert
28. april 2003 - 22:16 #11
Du skal ikke bruge try-catch with yield (det er kun ved sleep).
Avatar billede ellebaek Nybegynder
28. april 2003 - 22:54 #12
Jeg har sat den ind nu, hver gang jeg sender en mb videre til kryptering.

Men som før kommer monitoren ikke frem...(hvis slut er længden af processen)
Jeg har bedt den om at udskrive current, der er det tal der viser hvor langt den er nået, dette gør den også, men først når den er færdig med dette vises progressmonitoren.(hvis slut er 100)
Avatar billede arne_v Ekspert
29. april 2003 - 08:20 #13
Mystisk.
Avatar billede carstenknudsen Nybegynder
29. april 2003 - 09:46 #14
Prøv at lave en separat tråd der sørger for at opdatere din monitor.
Avatar billede arne_v Ekspert
29. april 2003 - 09:50 #15
Er Timer ikke en tråd ?
Avatar billede carstenknudsen Nybegynder
29. april 2003 - 10:04 #16
Nej, det er den faktisk ikke. Den nedarver direkte fra Object. Derfor er det ikke umiddelbart klart hvilken tråd den udføres i. Dokumentationen siger blot at den udføres i en baggrundstråd, men ikke hvilken. Den kunne derfor dele resourcer med andre processer der bruger al tiden. Når jeg bruge ProgressMonitor benytter jeg en eksplicit ny tråd til at tegne med.
Avatar billede carstenknudsen Nybegynder
29. april 2003 - 10:14 #17
Ved at læse videre ser man at der til hver Timer er en baggrundstråd.
Avatar billede arne_v Ekspert
29. april 2003 - 10:26 #18
Øh. Sådan læser jeg det ikke.

Although all Timers perform their waiting using a single, shared thread (created by the first Timer object that executes), the action event handlers for Timers execute on another thread -- the event-dispatching thread. This means that the action handlers for Timers can safely perform operations on Swing components. However, it also means that the handlers must execute quickly to keep the GUI responsive.

Men det sidste re måske en forklaring. Hvis den tunge krypterings
process udføres direkte i en event-handler ("start button"), så
er det nok det der er skyld i problemet.
Avatar billede arne_v Ekspert
29. april 2003 - 10:27 #19
Hvis den hypotese er korrekt, så skal krypteringen være en separat tråd.
Avatar billede carstenknudsen Nybegynder
29. april 2003 - 10:52 #20
Du har ret her, det er skrevet lidt mindre klart i javadoc'en, derfor den forkerte konklusion.
Avatar billede ellebaek Nybegynder
29. april 2003 - 17:37 #21
Jeg har min startknap, når der trykkes på den kaldes listener.
    private final class listener implements ActionListener {
    public void actionPerformed(ActionEvent e) { HandleChoice(e.getActionCommand()); }
    }

Listener kalder så videre til HandleChoice og her begynder jeg krypteringen og timeren på den måde jeg har beskrevet i mit spg.

Hvordan laver jeg det til en seperart tråd ??
Avatar billede arne_v Ekspert
29. april 2003 - 19:14 #22
public class X extends Thread {
  public X() {
  }
  public void run() {
      // do the stuff
  }
}

Så kan du lave:
  X x = new X();
  x.start();
og så kører det i en separat tråd.

Hvis der skal bruges nogle data kan de overføres i constructor.
Avatar billede ellebaek Nybegynder
29. april 2003 - 19:27 #23
ok...! Det vil jeg prøve, men tænkte på om det kan lade sig gøre at skrive til progressmonitoren eller kalde den fra aes-klassen. Altså så hver gang jeg sender en mb, videre til kryptering opdateres monitoren, og vil det i såfald være hensigtsmæssigt?
Avatar billede arne_v Ekspert
29. april 2003 - 22:07 #24
Nyt eksempel:

package test;

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

public class ProgTest extends JFrame {
    private ProgressMonitor progressMonitor;
    private Timer timer;
    private DummyEncrypter aes = new DummyEncrypter();
    public ProgTest() {
        super();
        progressMonitor =
            new ProgressMonitor(this, "Encryption", "Running", 0, aes.getLength());
        progressMonitor.setProgress(0);
        timer = new Timer(1000, new TimerListener());
        timer.start();
        (new EncrypterThread(aes)).start();
        aes.encrypt();
    }
    class TimerListener implements ActionListener {
        public void actionPerformed(ActionEvent evt) {
            progressMonitor.setProgress(aes.getCurrent());
            if (aes.isDone()) {
                timer.stop();
            }
        }
    }
    public static void main(String[] args) throws Exception {
        ProgTest f = new ProgTest();
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.pack();
        f.setVisible(true);
    }
}

class DummyEncrypter {
    private final static int N = 100;
    private int n = 0;
    public int getCurrent() {
        if (n < N)
            n++;
        return n;
    }
    public int getLength() {
        return N;
    }
    public boolean isDone() {
        return (n >= N);
    }
    public void encrypt() {
        while (!isDone()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
        }
    }
}

class EncrypterThread extends Thread {
    private DummyEncrypter aes;
    public EncrypterThread(DummyEncrypter aes) {
        this.aes = aes;
    }
    public void run() {
        aes.encrypt();
    }
}
Avatar billede ellebaek Nybegynder
29. april 2003 - 23:51 #25
Nu er vi meget tæt på...
Det virkede for krypteringen før, men da jeg så ville udbygge det, tilføjede denne klasse
class DecrypterThread extends Thread {
    private Stream_AES aes;
    public EncrypterThread(Stream_AES aes) throws IOException {
        this.aes = aes;
   
    }
    public void run() {
    try {
        aes.encrypt();
    }
    catch (IOException e) {}
    }
}

og testede med en if oppe i kaldet hvilken af de 2 der skulle kaldes fik jeg denne fejl, og jeg kan ikke se hvad det er jeg har gjort galt..
design.java:632: invalid method declaration; return type required
    public EncrypterThread(Stream_AES aes) throws IOException {
          ^
1 error
Avatar billede arne_v Ekspert
30. april 2003 - 07:15 #26
Du skal bare ændre:

class DecrypterThread extends Thread {
    public EncrypterThread(Stream_AES aes) throws IOException {

til:

class DecrypterThread extends Thread {
    public DecrypterThread(Stream_AES aes) throws IOException {

constructor skal naturligvis hedde det samme som klassen.
Avatar billede ellebaek Nybegynder
01. maj 2003 - 12:26 #27
Kanon...

Det virker. Mange tak for hjælpen. Afsatte lige lidt flere point, da du har brugt lang tid på dette...

Men tak for hjælpen.
/Jens
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester