0

시뮬레이션 모델 변경 내부 상태로 gui를 업데이트하는 데 문제가 있습니다. 클래스 시뮬레이터는 특정 단계 수만큼 실행됩니다. 모든 단계에서 컴퓨터의 내부 상태가 변경됩니다. 그런 다음 Gui는 알림을 받고 현재 상태의 텍스트를 포함한 컴퓨터의 그래픽 표현을 다시 그려야합니다. 불행히도 아래에 자세히 나와있는 클래스는 시뮬레이션 실행 마지막 단계 이후의 변경 사항 만 업데이트합니다. 나는 관찰자 (컴퓨터)와 관측 가능한 (GUICanvas) 패턴을 사용하고 있습니다. GUI의 중간 단계에서 다시 그리지 않는다. 당신은 아마 이벤트 스레드에서 실행되는 코드의 비트를 소모 긴 실행 시간 이벤트 디스패치 스레드 또는 EDT를 묶는하고모델 변경의 내부 상태로 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

:

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

SwingWorker 또는 다른 배경을 사용해보십시오 이 문제를 해결하기위한 스레드.

+0

그건 내 첫 번째 생각 이었지만'simulate()'에 대한 호출은'main()'에 있습니다. –

+0

@RussellZahniser : 네, 맞습니다. 코드에는 많은 것이 있지만 생략되어 있으므로 스윙 문제의 동시성이 의심됩니다. –

1

Thread.sleep() 어딘가에 tick() 또는 simulate()이 표시되지 않으면 시뮬레이션이 거의 즉시 실행되어야합니다. repaint()에 대한 모든 호출은 단일 페인트로 통합됩니다.

편집 :

여기를 관찰 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

러셀과 호버크라크 뱀장어를 보시고 고맙습니다. 실제로 문제는 스레드에 의해 발생했습니다 – Sharissa

+0

실제로 내 코드에 Thread.sleep이 있습니다 ...하지만 내 시뮬레이션 메서드는 단추에 대한 작업 이벤트 안에있었습니다 ... 따라서 simulate()는 EDT가 아닌 주 스레드 내에서 실행 중이며, 왜 GUI가 새로 고쳐지지 않았는지를 설명합니다 ... 시뮬레이트()를 실행하기 위해 1 개의 추가 스레드를 추가하면 문제가 해결되었습니다. – Sharissa