0

シミュレーションモデルの変更の内部状態としてguiを更新する際に問題があります。クラスシミュレータは、特定のステップ数だけ実行されます。毎回、コンピュータの内部状態が変化します。 Guiは通知を受け、現在の状態のテキストを含むコンピュータのグラフィック表示を再描画する必要があります。残念ながら、GUIの下で詳述されているクラスでは、シミュレーションの最後のステップが実行された後の変更のみが更新されます。私はオブザーバー(コンピューター)と観測可能な(GUICanvas)パターンを使用しています。シミュレーションの中間ステップでGUIが再描画されないのは間違っていますか?モデル変更の内部状態としてのJava GUIの更新

public class NwSim { 


    public NwSim() { 
    } 

    public static void main(String[] args) { 
     JFrame frame; 
     Simulator simulator = new Simulator();  
     canvas = new GUICanvas();   //create gui canvas, which paints guy computers 
     canvas.setBackground(Color.white); 
     contentPane.add(canvas, BorderLayout.CENTER); 
     frame.pack(); 
     frame.setVisible(true); 
    simulator.simulate(); 
    } 
} 

//represents the controller in the simulation 
public class Simulator { 
List<Computer> computers; 
private int simulationSteps; 

public Simulator() 
    simulationSteps = 200; 
       computers = new ArrayList<Computer>(); 


    public void simulate() { 
     for(int step = 0; step < simulationSteps; step++) { 
     for(Computer computer : computers) { 
     computer.tick() 
    } 
    } 
    } 

    public Computer createComputer() { 
    Computer computer = new Computer(); 
    computers.add(computer) 
    } 
} 



public class Computer extends Observable { 

    public void tick { 
    ….. // update field state of the computer 
     if (state.stateChanged()) { 
      setChanged(); 
      notifyObservers(); //notify observer- gui canvas that the state of computer has changed and it is time to repaint guiComputers 

     } 
} 

public string getState() { 
return state; 
} 
} 

public class GUIComputer { 

private static final long serialVersionUID = 1L; 
private int width; 
private int height; 
private Image image; 
private Computer computer; 


public GUIComputer(int x, int y, Computer computer component, Image image) { 
    this.computer = computer; 
    setX(x); 
    setY(y); 
    this.image = image; 
    width = image.getWidth(null); 
    height = image.getHeight(null); 
} 


@Override 
public void drawGuiComputer(Graphics g){ 
     g.drawImage(image, getX(), getY(), null); 
     Graphics2D g2 = (Graphics2D)g; 
     g2.drawString(computer.getState().toString(), getX() + 20, getY() // repaint the state for each guiComputer taken from Computer 
       + height + 10); 
} 
} 

public class GUICanvas extends JPanel implements Observer { 

// 
private List<GUIComputer> guiComputers; 

public GUICanvas(Simulator simulator) { 
    this.guiComputers = new ArrayList<GUIComputer>(); 
    // create guy computers using method createGuiComputer below , code omitted 
} 

public createGuiComputer(Transferable transferable, Point dropPoint, Computer computer) { 
Image image = Toolkit.getDefaultToolkit().getImage("images/" + imageName); 
     Computer computer = simulator.createComputer(); 
         GUIComputer guiComputer = new GUIComputer(dropPoint.x, dropPoint.y, computer, image); 
         guiComputers.add(guiComputer); 
         guiComputer.addObserver(this); 

} 

    @Override 
    public void paintComponent(Graphics g) { 

     super.paintComponent(g); 
     Graphics2D g2 = (Graphics2D)g;  
      if (!GuiComputers.isEmpty()) { 
        for(GUIComputer guiComputer : guiComputers) { 
       // redraw guiComputer 
          guiComputer.drawGuiComputer(g); 
         } 
      } 
} 

    @Override 
    public void update(Observable o, Object o1) { 
    for(final GUIComputer guiComputer : guiComputers) { 
       if(guiComputer.getComputer().equals(o)) { 
        //if update requested by Computer object then update gui, redrawing all guiComputers 
        revalidate(); 
        repaint(); 
       } 
    } 
} 
} 
+2

あなたのコードのインデントが混乱ですが、あなたのコード例コンパイルされません。それが最初の問題です。 –

答えて

2

あなたはおそらくイベントスレッドで実行されているコードの実行時間の長い時間がかかるビットでイベントディスパッチスレッドまたはEDTを拘束している:

public void simulate() { 
    for(int step = 0; step < simulationSteps; step++) { 
     for(Computer computer : computers) { 
     computer.tick() 
     } 
    } 
} 

SwingWorkerまたは他のバックグラウンドを使用してみてくださいこれを解決するスレッド。

+0

これも私の最初の考えでしたが、 'simulate()'の呼び出しは 'main()'にあります。 –

+0

@RussellZahniser:はい、そうです。それは除外されているにもかかわらず、コードには多くのことがあるので、私はまだSwingの問題で並行性が疑わしいです。 –

1

Thread.sleep()のいずれかがtick()またはsimulate()で表示されていない限り、シミュレーションはほぼ即時に実行する必要があります。 repaint()へのすべての呼び出しは、1つの再描画に合体されます。

編集:

ここではそれらを観察main()スレッドでObservable sの散発的な更新はGUIに示されている簡単な例です:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Observable; 
import java.util.Observer; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class Animation extends JPanel implements Observer { 
    Simulation simulation; 

    Animation(Simulation simulation) { 
     this.simulation = simulation; 
     setPreferredSize(new Dimension(200, 200)); 

     for(Blob blob : simulation.blobs) { 
      blob.addObserver(this); 
     } 
    } 

    @Override 
    public void update(Observable o, Object arg) { 
     Blob blob = (Blob)o; 
     repaint(blob.x - 12, blob.y - 12, 24, 24); 
    } 

    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     for(Blob blob : simulation.blobs) { 
      g.setColor(blob.color); 
      g.fillOval(blob.x - 10, blob.y - 10, 20, 20); 
     } 
    } 

    public static void main(String[] args) { 
     Simulation simulation = new Simulation(); 

     JFrame frame = new JFrame(); 
     frame.getContentPane().add(new Animation(simulation)); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setVisible(true); 

     simulation.simulate(); 
    } 
} 

class Simulation { 
    List<Blob> blobs = new ArrayList(); 

    Simulation() { 
     for(int i = 0; i < 20; ++i) { 
      blobs.add(new Blob()); 
     } 
    } 

    void simulate() { 
     while(true) { 
      try { 
       Thread.sleep(50); 
      } catch(InterruptedException e) { 
       return; 
      } 
      for(Blob blob : blobs) { 
       blob.tick(); 
      } 
     } 
    } 
} 

class Blob extends Observable { 
    int x = (int)(Math.random() * 180 + 10); 
    int y = (int)(Math.random() * 180 + 10); 
    float hue = (float)Math.random(); 
    Color color = Color.getHSBColor(hue, 1, 1); 

    void tick() { 
     if(Math.random() < 0.05) { 
      x += 4 * Math.random() - 2 + .5; 
      y += 4 * Math.random() - 2 + .5; 
      hue += Math.random() * .1 - .05; 
      hue -= Math.floor(hue); 

      color = Color.getHSBColor(hue, 1, 1); 
      setChanged(); 
      notifyObservers(); 
     } 
    } 
} 
+0

ラッセルとホバークラフト満員のEelsさんありがとうございます。確かに問題はスレッドによって引き起こされました – Sharissa

+0

私は実際に私のコードでThread.sleepを持っていましたが...私のシミュレートメソッドはボタンのアクションイベントの内側にあったので... simulate()はメインスレッドではなくEDT内で実行していました。なぜGUIがリフレッシュされていないのかを説明しています.... 1つの余分なスレッドを追加してsimulate()を実行すると、問題は解決しました。ありがとうございます。 – Sharissa

関連する問題