Обновление java GUI как внутреннее состояние изменений модели - PullRequest
0 голосов
/ 24 февраля 2012

У меня проблема с обновлением графического интерфейса при изменении внутреннего состояния имитационной модели. Класс симулятора работает за определенное количество шагов. Каждый шаг внутреннее состояние компьютера меняется. Затем Gui получает уведомление и должен перерисовать свое графическое представление компьютера, включая текст для текущего состояния. К сожалению, с классами, описанными ниже, графический интерфейс обновляет изменения только после последнего шага симуляции. Я использую наблюдатель (компьютер) и наблюдаемый (GUICanvas) шаблон. Что я делаю не так, что графический интерфейс не перерисовывается на промежуточных этапах симуляции?

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 голосов
/ 25 февраля 2012

Скорее всего, вы связываете поток диспетчеризации событий или EDT с большим количеством кода, который выполняется в потоке событий:

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

Попробуйте использовать SwingWorker или другой фоновый поток для решения этой проблемы.

1 голос
/ 25 февраля 2012

Если у вас нет Thread.sleep() где-то в tick() или simulate(), который вы не показывали, симуляция должна выполняться почти мгновенно.Все вызовы repaint () затем будут объединены в один repaint.

Редактировать:

Вот простой пример, когда отдельные обновления Observable s наmain() поток отображается в графическом интерфейсе, наблюдая за ними:

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