将java GUI更新为模型更改的内部状态

将java 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

你的代码缩进是一个烂摊子,你的代码示例不编译。这是第一个问题。 – 2012-02-24 20:06:46

你很可能会占用事件调度线程或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

除非您有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