0

我在更新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

你的代碼縮進是一個爛攤子,你的代碼示例不編譯。這是第一個問題。 – 2012-02-24 20:06:46

回答

2

你很可能會佔用事件調度線程或EDT與消費是在事件線程上運行的代碼位長的運行時間:

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

嘗試使用SwingWorker或其他背景線程來解決這個問題。

+0

這也是我的第一個想法,但對'simulate()'的調用在'main()'中。 – 2012-02-25 03:39:11

+0

@RussellZahniser:是的,你說得對。雖然這個代碼被遺漏了,但代碼還是很多的,所以我仍然懷疑Swing問題的併發性。 – 2012-02-25 03:47:42

1

除非您有Thread.sleep()的某個地方在tick()simulate()中沒有顯示,否則仿真應該幾乎立即運行。所有的repaint()調用都將被合併爲一個重繪對象。

編輯:

這裏有一個簡單的例子,其中零星更新Observable S於該main()線程一個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

謝謝羅素和氣墊船全是鰻魚。事實上,這個問題是由線程引起的 – Sharissa 2012-02-25 15:36:00

+0

我之前在代碼中實際上有Thread.sleep,但是我的模擬方法在按鈕的動作事件中......因此,模擬()在EDT內運行,而不是主線程,這解釋了爲什麼GUI沒有刷新....添加1個額外的線程來運行模擬()解決了問題,謝謝你們。 – Sharissa 2012-02-25 15:48:59