2014-05-19 19 views
8

Jest to najmniejszy możliwy do uruchomienia SSCCE, z mojego projektu, który mógłbym wprowadzić, aby Ci pokazać.Oddzielny wątek logiki od wątku wysyłania zdarzeń

  • Czytałem, że wywołanie gra logiczna z wątku Event Dispacth jest złą praktyką, w jaki sposób można je rozdzielić, bo jak widać update() i repaint() związane są w pętli i jak mogę w łatwy sposób oddzielić kod, mam kłopoty z tym, próbując dowiedzieć się, jak to zrobić.

  • mam napisali podobne pytanie w sprawie i dostałem odpowiedź, że mówi do korzystania z Swing Timer, ale mam ogromne zadanie, aby i jak czytam Swing timer nie jest idealnym rozwiązaniem dla tych scenario.This jest pytanie :

główna klasa

import javax.swing.JFrame; 
    import javax.swing.SwingUtilities; 
    import javax.swing.UIManager; 

    public class Main { 

     private static final Main mainFrame = new Main(); 
     private final JFrame frame; 

     private Main() { 
     frame = new JFrame(); 
     frame.setUndecorated(true); 
     frame.add(new MyPanel()); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
     } 

     public static Main getMainFrameInstance() { 
     return mainFrame; 
     } 


     public static void main(String[] args) { 

     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
      Main.getMainFrameInstance(); 
      } 
     }); 
     } 

    } 

MyPanel Klasa

 import java.awt.Dimension; 
     import java.awt.Graphics; 
     import java.awt.Graphics2D; 
     import java.awt.RenderingHints; 
     import java.awt.image.BufferedImage; 

     import javax.swing.JPanel; 

     public class MyPanel extends JPanel implements Runnable,KeyListener,MouseListeners { 

      private static final long serialVersionUID = 1L; 

      // thread and loop 
      private Thread thread; 
      private boolean running; 
      private int FPS = 60; 
      private long targetTime = 1000/FPS; 
      private long start; 
      private long elapsed; 
      private long wait; 

      // image 
      public BufferedImage image; 
      // foo 
      private Foo foo; 

      private Render render = Render.getRenderManagerInstance(); 

      public MyPanel() { 
      setPreferredSize(new Dimension(700, 700)); 
      setFocusable(true); 
      requestFocus(); 
      } 

      public void addNotify() { 
      super.addNotify(); 
      if (thread == null) { 
        addKeyListeners(this); 
        addMouseListener(this); 
       thread = new Thread(this); 
       thread.start(); 
      } 
      } 


      private void initGraphic() { 
      image = new BufferedImage(700, 700, BufferedImage.TYPE_INT_RGB); 
      foo = new Foo(); 
      running = true; 

      } 

      public void run() { 
      initGraphic(); 

      // loop 
      while (running) { 
       start = System.nanoTime(); 
       foo.update(); 
       repaint(); 
       elapsed = System.nanoTime() - start; 
       wait = (targetTime - elapsed/1000000) - 8; 
       if (wait <= 0) 
       wait = 6; 

       try { 
       Thread.sleep(wait); 
       } catch (Exception e) { 
       e.printStackTrace(); 
       } 

      } 
      } 

      public void paintComponent(Graphics graphics) { 
     super.paintComponent(graphics); 
     graphics = image.getGraphics(); 
     ((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     ((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 
     render.setRenderState((Graphics2D) graphics); 
     graphic.drawImage(image, 0, 0, this); 
    // clear graphics resources after use them 
    graphic2D.dispose(); 

     } 
     public void keyPressed(KeyEvent keyEvent) { 
        //code not considerable 
      } 

      public void keyReleased(KeyEvent keyEvent) { 
         //code not considerable 

      } 

      public void mousePressed(MouseEvent mouseEvent) { 
         //code not considerable 

      } 

      public void mouseReleased(MouseEvent mouseEvent) { 
         //code not considerable 
      } 

    } 
+0

Co masz na myśli przez "EDT"? – Illidanek

+3

@Illidanek Event Dispatch Thread. – OiRc

+1

Wygląda na to, że próbujesz zrobić tradycyjną zapętloną pętlę gier w środowisku sterowanym zdarzeniami (którym jest Swing); to nie jest dobry pomysł. Rozważ usunięcie tej pętli i zamiast tego użyj Swing Timer. Lub nie używaj Swing, ale raczej użyj strategii Window + Canvas + BufferStrategy, aby nie zderzyć się z EDT. – Gimby

Odpowiedz

3

To jak może wyglądać. Musisz zadzwonić pod następujący kod gdzieś w EDT lub przez Swing Timer. Zakładam, że twoje "ogromne" zadanie będzie musiało zaktualizować pole tekstowe, ale może to być również dowolna inna kontrola interfejsu użytkownika. Wszystko po to, żeby zademonstrować pomysł. Nie traktuj tego jako sprawdzonego kodu.

//javax.swing.JTextField jfield; The field that needs to be updated. Take it from your Panel 
String text = ""; // just a place holder 
Object params [] = new Object []{jfield, text}; 
HugeTaskRunner ht = new HugeTaskRunner(params, new CallBack()); 

HugeTaskRunner pochodzi od AbstractTaskRunner, która wygląda następująco:

public abstract class AbstractTaskRunner extends Thread { 


CallBack callBack = null; 
Object [] params = new Object[0]; 

public AbstractTaskRunner (Object [] params, CallBack callBack) { 
    this.params = params; 
    this.callBack = callBack; 

} 
public abstract void doTask(); 
@Override 
public void run() { 
    doTask(); 
    if (callBack != null) { 
     callBack.doCall(new Object[]{"DONE"}); 
    } 
} 

} 

HugeTaskRunner:

public class HugeTaskRunner extends AbstractTaskRunner { 

public HugeTaskRunner(Object[] params, CallBack callBack) { 
    super(params, callBack); 
    // TODO Auto-generated constructor stub 
} 

@Override 
public void doTask() { 
    // HERE YOU'LL HAVE TO DO SOME HUGE TASK ACTIONS 
    // THEN YOU'LL NEED TO CALL callBack.doCall(params) to update GUI 
    String newText = "Image #1 has been loaded"; 
    params[params.length -1] = newText; // assuming that the last param is for updated text 
    callBack.doCall(params); 

} 

} 

klasa callback:

public class CallBack { 
public void doCall (Object [] params) { 
    javax.swing.SwingUtilities.invokeLater(new GUIUpdater(params, null)); 
} 
} 

klasa GUIUpdater:

public class GUIUpdater extends AbstractTaskRunner { 

public GUIUpdater(Object[] params, CallBack callBack) { 
    super(params, callBack); 
} 

@Override 
public void doTask() { 
    // UPDATE YOUR GUI HERE TAKING Swing UI objects from params, e.g. 
    if (params.length == 1 && params[0].equals("DONE")) { 
     // HUGE TASK IS COMPLETED, DO SOMETHING IF YOU NEED TO 
    } 
    else if (params.length == 2) { // It's a request to update GUI 
     javax.swing.JTextField txt = (javax.swing.JTextField) this.params[0]; 
     txt.setText((String)this.params[1]); 
    } 
    else { 
     // UNKNOWN REQUEST 
    } 

} 

} 
+1

Doceniam twoją pracę, naprawdę, ale muszę zrozumieć, czy to dobre modelowanie mojego pytania. – OiRc

+1

Oczywiście, będziesz potrzebował czasu, aby go przetrawić, a jeszcze więcej czasu na sprawdzenie, ponieważ, jak już wspomniałem, jest to raczej wzór niż testowany kod, który można po prostu skopiować/wkleić, skompilować i uruchomić. –

+1

po 1 dniu debugowania udało mi się sprawić, że wszystko działało, wprowadziłem wiele zmian, szczególnie w tym, jak uruchomić wątek logiczny, ponieważ, jak powiedziałem, nie chciałem go uruchamiać wewnątrz EDT **, a wywołanie w naturalny sposób wewnątrz "**. dlatego nazwałem go poza EDT i nie zgadzałem się z komentarzem zamieszczonym powyżej: "uruchom nowe zagrożenie (np. z EDT lub przez zwykły zegar)" @Oleg Gryb. – OiRc

Powiązane problemy