Swing i kolorowanie JPanel w wątku

0

Witam.
Zanim przejdę do kłopotów, chciałbym krótko scharakteryzować zadanie, które wykonuję. Napisałem program używając Appletu, który tworzył pewną strukturę przedstawioną poniżej:

Pierwszy ekran to ekran startowy. Na środku okna widoczne jest niebieskie koło. Styka się ono z czterema innymi kołami w kolorze czerwonym.
Zasada działania programu jest następująca:

  1. Na starcie tworzone są dwie ArrayListy z obiektami Point, które przechowują współrzędne x i y punktu.
  2. Jedna ArrayLista przechowuje pokolorowane punkty, a druga punkty do pokolorowania.
  3. Po dodaniu do pierwszej ArrayListy punktu niebieskiego (jako pokolorowanego), następuje dodanie kolejnych punktów do pokolorowania do drugiej ArrayListy (tych w kolorze czerwonym).
  4. Następuje uruchomienie wątku.
  5. W wątku losowany jest jeden element z listy elementów do pokolorowania i jest on kolorowany na zielono i dodawany do pierwszej ArrayListy elementów pokolorowanych, a także jest usuwany z listy elementów do pokolorowania.
  6. Następnie podobnie jak w przypadku punktu startowego wokół tego nowego pokolorowanego punktu tworzone są koła w kolorze czerwonym i dodawane do listy elementów do pokolorowania. Oczywiście jeśli nie ma ich na żadnej liście.
  7. Wątek wykonywany jest do momentu zapełnienia ekranu.
    user image

Tu widoczny efekt pokolorowania kilkunastu punktów:
user image

A teraz problem.
Po napisaniu Appletu chciałem przenieść całą logikę programu do Swinga. No i tu nie potrafię sobie poradzić z rysowaniem. Oto, co mam do tej pory. Wątek aktualnie nie posiada, żadnych opóźnień w rysowaniu i warunków, które były np. w Applecie, ale to wynika z faktu, że nie szło w ogóle rysowanie:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JPanel;

public class EdenPanel extends JPanel implements Runnable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -1418394043622693890L;
	int width;
	int height;
	int size;
	Color c;
	Thread th;

	Point startPoint;
	Point top;
	Point right;
	Point bottom;
	Point left;
	Point newPoint;

	public Point getStartPoint() {
		return startPoint;
	}

	public void setStartPoint(Point startPoint) {
		this.startPoint = startPoint;
	}

	public Point getTop() {
		return top;
	}

	public void setTop(Point top) {
		this.top = top;
	}

	public Point getRight() {
		return right;
	}

	public void setRight(Point right) {
		this.right = right;
	}

	public Point getBottom() {
		return bottom;
	}

	public void setBottom(Point bottom) {
		this.bottom = bottom;
	}

	public Point getLeft() {
		return left;
	}

	public void setLeft(Point left) {
		this.left = left;
	}

	public Point getNewPoint() {
		return newPoint;
	}

	public void setNewPoint(Point newPoint) {
		this.newPoint = newPoint;
	}

	public ArrayList<Point> emptyPoints = new ArrayList<Point>();
	public ArrayList<Point> coloredPoints = new ArrayList<Point>();

	public ArrayList<Point> getEmptyPoints() {
		return emptyPoints;
	}

	public void setEmptyPoints(ArrayList<Point> emptyPoints) {
		this.emptyPoints = emptyPoints;
	}

	public ArrayList<Point> getColoredPoints() {
		return coloredPoints;
	}

	public void setColoredPoints(ArrayList<Point> coloredPoints) {
		this.coloredPoints = coloredPoints;
	}

	public EdenPanel(int sizeX, int sizeY) {
		this.width = sizeX;
		this.height = sizeY;

		c = Color.BLUE;
		setBackground(Color.BLACK);
		setPreferredSize(new Dimension(width * 3 / 4, height));
	}

	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2 = (Graphics2D) g;
		c = Color.BLUE;
		g2.setColor(c);
		if (getRight() != null) {
			g2.fill(new Ellipse2D.Float.Float(startPoint.x, startPoint.y, size, size));
		}
		c = new Color(155, 38, 38);
		g2.setColor(c);
		if (getRight() != null) {
			g2.fill(new Ellipse2D.Float.Float(getRight().x, getRight().y, size, size));
		}
		if (getBottom() != null) {
			g2.fill(new Ellipse2D.Float.Float(getBottom().x, getBottom().y, size, size));
		}
		if (getLeft() != null) {
			g2.fill(new Ellipse2D.Float.Float(getLeft().x, getLeft().y, size, size));
		}
		if (getTop() != null) {
			g2.fill(new Ellipse2D.Float.Float(getTop().x, getTop().y, size, size));
		}
		c = new Color(74, 208, 17);
		g2.setColor(c);
		if (getNewPoint() != null) {
			g2.fill(new Ellipse2D.Float.Float(getNewPoint().x, getNewPoint().y, size, size));
		}
	}

	public void update(Graphics g) {
		paint(g);
	}

	public void paintFirstCell(int size) {
		this.size = size;
		startPoint = createStartPoint(width * 3 / 4, height);
		left = createLeftPoint(startPoint);
		right = createRightPoint(startPoint);
		top = createTopPoint(startPoint);
		bottom = createBottomPoint(startPoint);
		revalidate();
		repaint();

	}

	public Point createStartPoint(int windowSizeX, int windowSizeY) {
		startPoint = new Point();
		startPoint.x = windowSizeX / 2;
		startPoint.y = windowSizeY / 2;
		setStartPoint(startPoint);

		coloredPoints.add(startPoint);
		setColoredPoints(coloredPoints);

		return startPoint;
	}

	private Point createLeftPoint(Point p) {
		left = new Point();
		left.x = p.x - size;
		left.y = p.y;

		if (!emptyPoints.contains(left) && !coloredPoints.contains(left) && left.x > size) {
			emptyPoints.add(left);
			setLeft(left);
			return left;
		} else {
			return null;
		}
	}

	private Point createRightPoint(Point p) {
		right = new Point();
		right.x = p.x + size;
		right.y = p.y;

		if (!emptyPoints.contains(right) && !coloredPoints.contains(right) && right.x < width - size) {
			emptyPoints.add(right);
			setRight(right);
			return right;
		} else {
			return null;
		}
	}

	private Point createTopPoint(Point p) {
		top = new Point();
		top.x = p.x;
		top.y = p.y + size;

		if (!emptyPoints.contains(top) && !coloredPoints.contains(top) && top.y < height - size) {
			emptyPoints.add(top);
			setTop(top);
			return top;
		} else {
			return null;
		}
	}

	private Point createBottomPoint(Point p) {
		bottom = new Point();
		bottom.x = p.x;
		bottom.y = p.y + this.size;

		if (!emptyPoints.contains(bottom) && !coloredPoints.contains(bottom) && bottom.y > this.size) {
			emptyPoints.add(bottom);
			setBottom(bottom);
			return bottom;
		} else {
			return null;
		}
	}

	@Override
	public void run() {
		while (true) {
			createNewPoint(getStartPoint());
			left = createLeftPoint(getNewPoint());
			right = createRightPoint(getNewPoint());
			top = createTopPoint(getNewPoint());
			bottom = createBottomPoint(getNewPoint());
		}
	}

	private void createNewPoint(Point p) {
		// TODO Auto-generated method stub
		Random r = new Random();
		int index = r.nextInt(getEmptyPoints().size());
		setNewPoint(getEmptyPoints().get(index));
		getColoredPoints().add(getNewPoint());
		setColoredPoints(coloredPoints);
	}

	public void stopPainting() {
		//th.interrupt();
	}
}
0

Klasa, w której uruchamiam:

public class MainClass {
	private static final int WIDTH = 800;
	private static final int HEIGHT = 600;

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				createAndShowGUI();
			}
		});
	}

	private static void createAndShowGUI() {
		System.out.println("Created GUI on EDT? " + SwingUtilities.isEventDispatchThread());
		JFrame f = new JFrame("Eden Growth Model");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setLayout(new BorderLayout());
		f.setResizable(false);
		f.setPreferredSize(new Dimension(WIDTH, HEIGHT));

		EdenPanel edenPanel = new EdenPanel(WIDTH, HEIGHT);
		ControlPanel controlPanel = new ControlPanel(WIDTH, HEIGHT, edenPanel);

		f.add(edenPanel);
		f.add(controlPanel, BorderLayout.EAST);
		f.pack();
		f.setLocationRelativeTo(null);
		f.setVisible(true);
	}
}

ControlPanel:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;

public class ControlPanel extends JPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = -6969280129122570471L;
	int width;
	int height;
	EdenPanel edenPanel;

	public ControlPanel(int sizeX, int sizeY, EdenPanel ep) {
		this.width = sizeX;
		this.height = sizeY;
		this.edenPanel = ep;

		setPreferredSize(new Dimension(width / 4, height));
		setBorder(BorderFactory.createLineBorder(Color.black));

		JLabel cellSizeLabel = new JLabel("Set size of single cell:");
		cellSizeLabel.setPreferredSize(new Dimension(width / 4 - 15, 20));

		JLabel cellsNumberLabel = new JLabel("Set number of cells:");
		cellsNumberLabel.setPreferredSize(new Dimension(width / 4 - 15, 20));

		JLabel growthSpeedLabel = new JLabel("Set the speed of growth");
		growthSpeedLabel.setPreferredSize(new Dimension(width / 4 - 15, 20));

		SpinnerModel cellSizeModel = new SpinnerNumberModel(5, 1, 20, 1);
		final JSpinner cellSizeSpinner = new JSpinner(cellSizeModel);
		cellSizeSpinner.setPreferredSize(new Dimension(width / 4 - 15, 20));

		int cellSize = (int) cellSizeSpinner.getValue();
		int maxCells = (int) ((width * height) / (Math.PI * cellSize / 2));
		SpinnerModel cellsNumberModel = new SpinnerNumberModel(maxCells, 1, maxCells, 1);
		final JSpinner cellsNumberSpinner = new JSpinner(cellsNumberModel);
		cellsNumberSpinner.setPreferredSize(new Dimension(width / 4 - 15, 20));

		final JSlider speedSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, 1);
		speedSlider.setPreferredSize(new Dimension(width / 4 - 15, 20));

		final JButton clearButton = new JButton("Clear");
		clearButton.setName("clear");
		clearButton.setPreferredSize(new Dimension(width / 4 - 15, 30));
		clearButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JButton but = new JButton("Buttonik");
				edenPanel.add(but);
				edenPanel.validate();
				edenPanel.repaint();
			}
		});

		JButton startButton = new JButton("Start");
		startButton.setName("start");
		startButton.setPreferredSize(new Dimension(width / 4 - 15, 30));
		startButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JButton b = (JButton) e.getSource();
				
				if(b.getText().equals("Start")) {
					b.setText("Stop");
					cellSizeSpinner.setEnabled(false);
					cellsNumberSpinner.setEnabled(false);
					speedSlider.setEnabled(false);
					clearButton.setEnabled(false);
					int size = (int) cellSizeSpinner.getValue();
					edenPanel.paintFirstCell(size);					
				} else {
					b.setText("Start");
					cellSizeSpinner.setEnabled(true);
					cellsNumberSpinner.setEnabled(true);
					speedSlider.setEnabled(true);
					clearButton.setEnabled(true);
					edenPanel.stopPainting();
				}
			}
		});

		add(cellSizeLabel);
		add(cellSizeSpinner);
		add(Box.createHorizontalStrut(50));
		add(new JSeparator(SwingConstants.HORIZONTAL));
		add(Box.createHorizontalStrut(50));
		add(cellsNumberLabel);
		add(cellsNumberSpinner);
		add(Box.createHorizontalStrut(50));
		add(new JSeparator(SwingConstants.HORIZONTAL));
		add(Box.createHorizontalStrut(50));
		add(growthSpeedLabel);
		add(speedSlider);
		add(Box.createHorizontalStrut(50));
		add(new JSeparator(SwingConstants.HORIZONTAL));
		add(Box.createHorizontalStrut(50));
		add(startButton);
		add(Box.createHorizontalStrut(50));
		add(new JSeparator(SwingConstants.HORIZONTAL));
		add(Box.createHorizontalStrut(50));
		add(clearButton);
	}
}

Point:

public class Point {
	int x;
	int y;

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1