繁体   English   中英

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

[英]Updating java GUI as internal state of model changes

我在模拟模型的内部状态更改时更新gui时遇到问题。 类模拟器运行一定数量的步骤。 每一步,计算机的内部状态都会改变。 然后,Gui收到通知,应重新绘制其计算机图形表示形式,包括当前状态的文本。 不幸的是,对于下面详述的类,gui仅在模拟的最后一步运行后才更新更改。 我正在使用观察者(计算机)和可观察(GUICanvas)模式。 我做错了什么,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();
              }
    }
}
}

您可能会花费很长的运行时间来占用事件分发线程或EDT,这会消耗大量在事件线程上运行的代码:

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

尝试使用SwingWorker或其他后台线程来解决此问题。

除非您在tick()simulate()中某个未显示的地方有一个Thread.sleep()否则该模拟应该几乎立即运行。 然后,所有对repaint()的调用将合并为一个单独的repaint。

编辑:

这是一个简单的示例,其中在观察它们的GUI中显示了对main()线程上Observable的偶发更新:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM