Avatar billede mtilsted Nybegynder
24. juli 2001 - 00:28 Der er 2 kommentarer og
1 løsning

Threads, swing

Jeg har noget jeg ikke forstaar ved swing. Her er et stykke code til at vise det.

---------- Code start ----------
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class Test
{
    public static void main(String args[])
    {

        MyFrame F=new MyFrame();
        F.setVisible(true);

        for(int i=0;i!=100000;i++)
        {
            System.out.println(i);
        }
    }
}

class MyFrame extends JFrame implements WindowListener
{
    MyFrame()
    {
        super(\"Hey\");
        addWindowListener(this);
    }

    public void windowActivated(WindowEvent e)
    {
        for(int i=0;i!=1000;i++)
            System.out.println(\"Window actine \" + i );
    }

    public void windowClosed(WindowEvent e){}
    public void windowClosing(WindowEvent e){}
    public void windowDeactivated(WindowEvent e){}
    public void windowDeiconified(WindowEvent e){}
    public void windowIconified(WindowEvent e){}
    public void windowOpened(WindowEvent e){}
}
------------------ Code slut ------------------
Her er saa spørgsmaalet. Naar min main funktion \"løber up\" og dermed stopper hvor kommer alle de events saa fra som mit program modtager?

Saa vidt jeg kan se bliver maa swing enter bruge en skjult tråd mere, eller ogsaa slutter traaden ikke selvom den naar slutningen af main funktionen. Men jeg kan ikke faa nogle af disse muligheder til at passe:

1: Hvis swing bruger en traad mere, maa der da opstaa enorme problemer da swing ikke er thread safe.

2: Hvis der bare en 1 traad der ikke slutter kan jeg ikke forstaa det output jeg faar naar jeg aktivere vinduet, i det det giver
Window actine 869
19090
Window actine 870
19091
Window actine 871
19092
Window actine 872
19093
Window actine 873

Altsaa output er blandet fra mit main loop, og fra windowActivated.

Martin Tilsted.


Avatar billede logical Nybegynder
24. juli 2001 - 08:37 #1
Swing er single-threaded i sin model, så thread-safe skal du selv kode.

Når din main er færdig, er der startet en anden tråd, og det er den der kører.

Første gang du gør brug af en GUI komponent, vil den uvægerligt begynde at sende et GUI event, gennem en EventKlasse, som ikke er startet. Events bliver postet via en static metode i en klasse, så første event sørger for opstarten af GUI event tråden, lidt ala:

void deliverEvent(long evt) {
  if (myThread != null) {
    myThread = new EventListenerThread();
    myThread.start();
  }

  addToEventQueue(evt); // for later retrieval by the thread.
}

Tråden er ikke en dæmon, så den lever videre selv om din main kører.

Swing kører (primært) i den ene tråd, men kan godt manipuleres fra andre, og det er her at !thread-safe er noget at tænke på.

Det er iøvrigt fra denne event dispatcher tråd, at alle call-back metoder bliver udført i, så som actionPerformed, windowActivated etc. Så sålænge du udfører din for sætning, kan der ikke ske andre gui-ting. Det kan du bevise ved at dække dit vindue lidt til med et andet, og frigive det. Så vil dit native windows-system sende en event til Swing, som placeres for enden af event køen. Event køen er Thread-safe.

Derfor burde du lave din optælling (eller anden længerevarende operation) i en separat tråd, ala:
public void windowActivated(WindowEvent e) {
  new Thread() {
    public void run() {
      for (.....)  ...;
    }
  }.start();
}

Hvis du så bruger en anden tråd, og skal have rettet en komponent, f.eks.

public void windowActivated(WindowEvent e) {
  new Thread() {
    public void run() {
      for (....) ....;
      label.setText(\"Fææærrdiiiggg!!!\");
    }
  }.start();
}

I dette tilfælde retter du labelens tekst fra en anden tråd, og ved derfor ikke om labelen er igang med at blive gentegnet. Det kan betyde flickering at gøre noget sådan, men det er vist også den største forbrydelse.

For at løse dette, kan du kan du smide et Runnable objekt i event køen, som bliver behandlet af gui tråden, når tid er. Dette sker ved hjælp af metoderne

SwingUtilities.invokeLater(Runnable r); // Invoke the run method, when appropriate
SwingUtilities.invokeAndWait(Runnable r); //block until r has been invoked.

Så kommer scenariet til at se sådan her ud:
public void windowActivated(WindowEvent e) {
  new Thread() {
    public void run() {
      for (....) ....;
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          label.setText(\"Fææærrdiiiggg!!!\");
        }
      });
    }
  }.start();
}


Altså:
Swing bruger sin egen tråd, og er ligeglade med dine.
Lange handlinger som resultat af events skal ske i en separat tråd
Al gui opdatering bør foregå i gui event tråden.

Hjalp det?
Avatar billede mtilsted Nybegynder
25. juli 2001 - 17:54 #2
Ja. Bare lige et nemt spørgsmaal mere :}

Er der 1 traad i alt, eller 1 traad for hver JFrame man bruger?
Avatar billede logical Nybegynder
25. juli 2001 - 20:08 #3
En Swing Event tråd.. Derfor er Swing single trådet.
Alle event bliver postet til en kø, som denne tråd læser fra sekventielt.
Uafhængig af hvor mange JFrames du har, så vil de alle sende events til den samme kø, som så bliver læst af guitråden, så al opdatering sker herfra (sekventielt).

Alle eventmetoder fra dine komponenter, som f.eks. windowClosing, actionPerformed etc er kaldt fra guitråden på baggrund af et event, som er læst op fra eventkøen.
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