2014-05-19 7 views
8

Dies ist die kleinste lauffähige SSCCE, von meinem Projekt, die ich implementieren könnte, um Ihnen zu zeigen.Separate Logik Thread von Event Dispatch Thread

  • Ich habe gelesen, dass das Spiel Logik aus dem Ereignis Dispacth Thema Aufruf ist eine schlechte Praxis, wie kann ich sie trennen, weil, wie Sie update() und repaint() sehen können, sind in Schleife im Zusammenhang und Wie kann ich Code auf eine schöne Art und Weise trennen? Ich bekomme damit Probleme und versuche herauszufinden, wie es geht.

  • Ich habe eine ähnliche Frage in Bezug auf gebucht und ich bekam eine Antwort, die eine Swing Timer zu verwenden, sagt, aber ich habe große Aufgabe zu machen und als i Swing timer lesen für diese scenario.This nicht ideal ist, ist die Frage :

Hauptklasse

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 Klasse

 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

Was meinen Sie mit "EDT"? – Illidanek

+3

@Illidanek Event Dispatch Thread. – OiRc

+1

Scheint so, als ob du in einer ereignisgesteuerten Umgebung (die Swing ist) versuchen, eine traditionell ausgelastete Spielschleife zu machen; das ist keine gute Idee. Ziehen Sie in Betracht, diese Schleife zu entfernen und stattdessen einen Swing-Timer zu verwenden. Oder benutze Swing nicht, sondern verwende eine Window + Canvas + BufferStrategy, um nicht mit einem EDT zu kollidieren. – Gimby

Antwort

3

Dies ist, wie es aussehen kann. Sie müssen den folgenden Code irgendwo in EDT oder durch Swing Timer aufrufen. Ich gehe hier davon aus, dass Ihre "große" Aufgabe ein Textfeld aktualisieren muss, aber es kann auch jede andere UI-Steuerung sein. All das, nur um eine Idee zu demonstrieren. Behandeln Sie es nicht als getesteten Code.

//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 aus AbstractTaskRunner, abgeleitet, die wie folgt aussieht:

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); 

} 

} 

Callback-Klasse:

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

GUIUpdater Klasse:

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

Ich werde deine Arbeit wirklich zu schätzen wissen, aber ich muss verstehen, ob es eine gute Modellierung meiner Frage ist. – OiRc

+1

Sicher, du wirst Zeit brauchen, um es zu verdauen und noch mehr Zeit zum Testen, denn wie gesagt, es ist eher ein Muster als ein getesteter Code, den du einfach kopieren/einfügen, kompilieren und ausführen kannst. –

+1

nach 1 Tag Debugging habe ich geschafft, alles funktioniert, habe ich viele Änderungen vorgenommen, vor allem auf den logischen Thread, wie ich sagte, ich wollte es nicht innerhalb von EDT ** 'und der Rückruf natürlich starten innen "**. Also habe ich ihn außerhalb des EDT angerufen und mit dem Kommentar, den du oben gepostet hast, nicht einverstanden: "starte eine neue Bedrohung (z. B. von EDT oder durch einen normalen Timer)" @Oleg Gryb. – OiRc