Lange Ladezeit bei JFrame

  • Themenstarter Themenstarter Sebastian G
  • Beginndatum Beginndatum
S

Sebastian G

Hallo,

zuerst eine kurze Übersicht über mein Programm:

Ich habe das Ising-Model (2D) mit Hilfe einer Monte Carlo Simulation (Metropolis Alogrithmus) simuliert. Vereinfacht gesagt, es befinden sich Teilchen auf einem Gitter, die zwei unterschiedliche Zustände annehmen können. Die Änderung des Zustands jedes einzelnen Teilchens wird nach einer gewissen Regel (Metropolis) berechnet.

Nun möchte ich die Teilchen auf dem Gitter graphisch darstellen. Jedes Teilchen soll als Rechteck der Grösse 1X1 Pixel und mit einer entsprechenden Farbe, die den Zustand repräsentiert auf einem Gitter ausgegeben werden.

Zur Ausgabe verwende ich ein JPanel mit einem GridLayout, welches genausoviele Felder hat wie es Teilchen gibt. Nun werde Teilchen in das JPanel hizugefügt.

Zur Steuerung gibt es noch 2 JButton (Start, Pause) und ein JLabel sowie ein JTextField, welche in einem zweiten JPanel liegen.

Nun füge ich diese beiden JPanel einem JFrame (mit BorderLayout) hinzu.


Nun zum Problem:


Nachdem ich das Programm starte wird der JFrame und die beiden JPanels (meist) sofort angezeigt. Allerdings muss ich (abhängig von der Grösse des Gitter) relativ lange (bei einem 200X200 Gitter einige Minuten) warten bis die JButton, das JTextField und das X des JFrames anklickbar sind.

Nach dieser Wartezeit (ich kann nun die Simulation über einen Button starten) treten keine Probleme mehr auf.

Code:
public class Start {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		Model model = new Model (200,200,0);
		
		model.initialzeParticles();
		
		model.createView();
		
		model.simulate();
	}

}

Code:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;



public class Model {
	
	public static double BOLTZMANN_CONST = 1.3806504 * Math.pow(10, -23);

	private Particle[][] particleDoubleArray;
	
	private double temperature;
	private boolean flag;
	
	private JTextField temperatureTextField;
	private JLabel temperatureLabel;
	private JButton startButton;
	private JButton pauseButton;
	private JPanel simulationPanel;
	private JPanel controlPanel;
	private JFrame frame;
	
	/*
	 * constructor
	 */
	public Model (int numberOfRows, int numberOfCollumns, double temperature) {
		this.particleDoubleArray = new Particle[numberOfRows][numberOfCollumns];
		this.temperature = temperature;
		this.flag = false;
	}
	
	/*
	 * getter for temperature
	 */
	public double getTemperature() {
		return this.temperature;
	}
	
	/*
	 * setter for temperature
	 */
	public void setTemperature(double temperature) {
		this.temperature = temperature;
	}
	
	/*
	 * setter for flag
	 */
	public void setFlag(boolean flag) {
		this.flag = flag;
	}
	
	/*
	 * getter for Particle
	 */
	public Particle getParticle(int row, int column) {
		return this.particleDoubleArray[row][column];
	}
	
	/*
	 * getter for number of rows
	 */
	public int getNumberOfRows() {
		return this.particleDoubleArray.length;
	}
	
	/*
	 * getter for number of columns
	 */
	public int getNumberOfColumns() {
		return this.particleDoubleArray[0].length;
	}
	
	/*
	 * initialize Particle array
	 */
	public void initialzeParticles() {
		
		for (short index1 = 0; index1 < this.particleDoubleArray.length; index1++) {
			for (short index2 = 0; index2 < this.particleDoubleArray[0].length; index2++) {
				byte spin;
				double random = Math.random();
				if (random < 0.5) {
					spin = -1;
				}
				else {
					spin = 1;
				}
				this.particleDoubleArray[index1][index2] = new Particle(index1, index2, spin, this);
			}
		}
	}
	
	/*
	 * update each Particle in the Particle array
	 */
	private void updateParticles() {
			for (short index1 = 0; index1 < this.particleDoubleArray.length; index1++) {
				for (short index2 = 0; index2 < this.particleDoubleArray[0].length; index2++) {
					this.particleDoubleArray[index1][index2].update();
				}
			}
	}
	
	/*
	 * simulate
	 */
	public void simulate() {
		while (true) {
			if (flag) {
				try {
					this.setTemperature(Double.parseDouble(temperatureTextField.getText()));
				}
				catch (Exception e) {
					
				}
				this.updateParticles();
				this.frame.repaint();
				try {
					Thread.sleep(100);
				}
				catch (Exception e) {
				
				}
			}
		}
	}
	
	
	/*
	 * create View
	 */
	public void createView() {
		
		this.simulationPanel = new JPanel();
		this.simulationPanel.setLayout(new GridLayout(this.getNumberOfRows(), this.getNumberOfColumns()));
		this.simulationPanel.setSize(this.getNumberOfRows() * 2, this.getNumberOfColumns() * 2);
		for (short index1 = 0; index1 < this.getNumberOfRows(); index1++) {
			for (short index2 = 0; index2 < this.getNumberOfColumns(); index2++) {
				this.simulationPanel.add(new ParticleWithView(this.getParticle(index1, index2)));
			}
		}
		
		this.startButton = new JButton("Start");
		this.startButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				
				flag = true;
				
			}
			
		});
		
		this.pauseButton = new JButton("Pause");
		this.pauseButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				
				flag = false;
				
				startButton.setText("Continue");
				
			}
			
		});
		
		this.temperatureLabel = new JLabel("Temperature in Kelvin");
		
		this.temperatureTextField = new JTextField(this.temperature + "", 3);
		this.temperatureTextField.setHorizontalAlignment(JTextField.RIGHT);

	
		this.controlPanel = new JPanel();
		this.controlPanel.add(this.startButton);
		this.controlPanel.add(this.pauseButton);
		this.controlPanel.add(this.temperatureTextField);
		this.controlPanel.add(this.temperatureLabel);
		
		this.frame = new JFrame("Ising - Monte Carlo Simulation (Metropolis)");
		this.frame.setLayout(new BorderLayout());
		this.frame.setSize(610, 750);
		this.frame.add(this.controlPanel, BorderLayout.SOUTH);
		this.frame.add(this.simulationPanel, BorderLayout.CENTER);
		this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.frame.setResizable(false);
		this.frame.setVisible(true);
		
	}
		
	
}

Code:
public class Particle {
	
	private final double constant = -Model.BOLTZMANN_CONST;
	
	private Model model;
	
	private short x;
	private short y;
	private short spin;
	
	/*
	 * constructor
	 */
	public Particle(short x, short y, byte spin, Model model) {
		this.x = x;
		this.y = y;
		this.spin = spin;
		this.model = model;
	}
	
	/*
	 * getter for x
	 */
	public short getX() {
		return this.x;
	}
	
	/*
	 * getter for y
	 */
	public short getY() {
		return this.y;
	}
	
	/*
	 * getter for spin
	 */
	public short getSpin() {
		return this.spin;
	}
	
	/*
	 * update all properties of the Particle
	 */
	public void update() {
		
		this.updateSpin();
	}
	
	/*
	 * update spin according to "Computational physics" p. 174 
	 */
	private void updateSpin() {
		
		byte tmpSpin;
		
		if (this.spin == -1) {
			tmpSpin = 1;
		}
		else {
			tmpSpin = -1;
		}
		
		
		
		//for the 4 next neighbors
		double sumOfNeighborEnergies = 0;
		for (short direction = 0; direction < 4; direction++) {
			sumOfNeighborEnergies = sumOfNeighborEnergies + this.getNextNeighbor(direction).getSpin();
		}
		
		double energyChange = constant * tmpSpin * sumOfNeighborEnergies;
		
		if (energyChange <= 0) {
			this.spin = tmpSpin;
		}
		else {
			if (Math.random() < Math.exp(-energyChange/(Model.BOLTZMANN_CONST * model.getTemperature()))) {
				this.spin = tmpSpin;
			}
		}
	}
	
	/*
	 * get the next neighbor of this particle in a given direction;
	 * uses periodic boundaries;
	 * directions:
	 * 0: x+1
	 * 1: x-1
	 * 2: y+1
	 * 3: y-1
	 */
	private Particle getNextNeighbor(short direction) {
		
		switch (direction) {
		
		case 0: if (this.getX() == model.getNumberOfRows() - 1) {
					return model.getParticle(0, this.getY());
				}
				return (model.getParticle(this.getX() + 1, this.getY()));
				
		case 1: if (this.getX() == 0) {
					return model.getParticle(model.getNumberOfRows() - 1, this.getY());
				}
				return (model.getParticle(this.getX() - 1, this.getY()));
				
		case 2: if (this.getY() == model.getNumberOfRows() - 1) {
					return model.getParticle(this.getX(), 0);
				}
				return (model.getParticle(this.getX(), this.getY() + 1));
			
		case 3: if (this.getY() == 0) {
					return model.getParticle(this.getX(), model.getNumberOfColumns() - 1);
				}
				return (model.getParticle(this.getX(), this.getY() - 1));
		
		default: return null;
				
		}
		
	}
	

}

Code:
import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JPanel;


public class ParticleWithView extends JPanel {
	
	private Particle particle;
	
	/*
	 * constructor
	 */
	public ParticleWithView (Particle particle) {
		this.particle = particle;
	}
	
	/*
	 * (non-Javadoc)
	 * @see javax.swing.JComponent#paint(java.awt.Graphics)
	 */
	public void paint(Graphics g) {
		
		if (particle.getSpin() == 1) {
			g.setColor(Color.RED);
		}
		else {
			g.setColor(Color.YELLOW);
		}
		g.fillRect(0,0,1, 1);
	}
	
}


Ich weiss einfach nicht wo die lange Ladezeit herkommt. Ich wäre sehr dankbar für eure Ratschläge.

Vielen Dank im Voraus.

Sebastian
 
Du rufst ja in deiner main schon simulate auf. Das läuft in einer Endlosschleife im Hauptthread. Dadurch kann der Frame nicht mehr laden.
 
Ich habe daraufhin die Zeile

Code:
model.simulate();

auskommentiert. Allerdings hat sich an der Ladezeit nichts geändert.


Wo würde man die model.simulate() sinnvoll aufrufen? Im ActionListener des StartButtons?
 
Zurück