I'm trying to create a reset button for a grid of rectangles. When running it, you'll be able to click rectangles and turn them blue - the reset button is supposed to turn them all back to white. I'm stuck at what to put in the reset method in Lifeform. It currently does nothing. I appreciate any help!
Class Grid:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.Timer;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Grid extends JPanel{
private int a = 50;
private int b = 50;
private Lifeform[][] Life;
private Lifeform ife;
private boolean[][] life = new boolean[a][b];
private Timer t;
private JButton reset;
private JButton run;
private JPanel panel;
Grid(){
ife = new Lifeform();
run = new JButton("Run");
reset = new JButton("Reset");
reset.addActionListener(new ResetListener());
//creates grid of rectangles
Life = new Lifeform[a][b];
int ypos = 0;
for(int i = 0; i < Life.length; i++){
int xpos = 0;
for(int j = 0; j < Life[0].length; j++){
Rectangle r = new Lifeform();
r.setBounds(xpos, ypos, 50, 50);
Life[i][j] = (Lifeform) r;
xpos += 50;
}
ypos += 50;
}
t = new Timer(64, new Movement());
this.addMouseListener(new mouse());
}
public void paintComponent(Graphics g){
for(Lifeform[] n : Life){
for(Lifeform lf : n){
g.setColor(lf.getColor());
g.fillRect((int)lf.getX(), (int)lf.getY(), (int)lf.getWidth(), (int)lf.getHeight());
}
}
for (int i = 0; i <= 25; i++){
g.drawLine(0, 50*i, 1500, 50*i);
g.setColor(Color.black);
}
for (int i = 0; i <= 25; i++){
g.drawLine(50*i, 0, 50*i, 750);
g.setColor(Color.black);
}
}
private JFrame createGrid(){
JPanel panel = new JPanel();
JFrame frame = new JFrame("Alveolate");
frame.add(run, BorderLayout.NORTH);
frame.add(panel, BorderLayout.CENTER);
frame.add(reset, BorderLayout.SOUTH);
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,700);
frame.setVisible(true);
return frame;
}
public class mouse implements MouseListener{
//turns rectangles blue
public void mouseClicked(MouseEvent e) {
for(int i = 0; i < Life.length; i++){
for(int j = 0; j < Life[i].length; j++){
Lifeform spot = Life[i][j];
if (spot.contains(e.getPoint())) {
Color b = Color.blue;
if( spot.getColor().equals( Color.blue ) ) {
b = Color.white;
}
spot.setColor(b);
}
}
}
repaint();
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
public class Movement implements ActionListener{
public void actionPerformed ( ActionEvent e ){
}
updateUI();
}
repaint();
}
}
public void startTimer(){
t.start();
}
public void stopTimer(){
t.stop();
}
private class ResetListener implements ActionListener{
public void actionPerformed( ActionEvent e ) {
ife.reset();
updateUI();
}
}
public static void main(String[] args) {
Grid ABC = new Grid();
ABC.createGrid();
ABC.startTimer();
}
}
Class Lifeform:
import java.awt.Color;
import java.awt.Rectangle;
public class Lifeform extends Rectangle {
private Color c;
public Lifeform() {
c = Color.WHITE;
}
public Lifeform(int width){
reset();
}
public Color getColor() {
return c;
}
public boolean setColor( Color c ) {
boolean rtn = false;
if( c != null ) {
this.c = c;
rtn = true;
}
return rtn;
}
public void reset() {
}
}
It doesn't do anything when you hit the Reset button because reset (presumably the reset() method of Lifeform) is defined as doing nothing: there is no code in that method.
In the reset method of your Lifeform class, you code this:
public void reset() {
c = Color.WHITE;
}
In the actionPerformed method of your ResetListener class, you code this:
public void actionPerformed( ActionEvent e ) {
for(Lifeform[] n : Life) {
for(Lifeform lf : n) {
lf.reset();
}
}
updateUI();
}
And that's how you reset all of the Lifeform instances.
In your Grid class, you've coded:
private Lifeform[][] Life;
and
private boolean[][] life = new boolean[a][b];
Don't ever give two fields the same name like this. It's confusing to the reader of your code.
All field names in Java should start with a lowercase letter. This helps you see the difference between a class name Lifeform and a class instance lf.
In this case, the life boolean probably should be a field in the Lifeform class. A more descriptive name would be isLife.
Related
For this small program I am attempting to generate a list of squares to be drawn on a panel. Each thread will generate a list and then set the list in the GUI class. In the GUI class I have a swing timer which repaints the panel every 500 milliseconds. Whenever a thread completes their set of squares I want to display it in the GUI. I also want to be sure to overwrite the variable so that the squares from one set do not overlap with another. My program consists of a custom thread class, a main class, a GUI class, and a custom jpanel class. I understand that currently the threads are quite fast, but if they each took different amounts of time, I still am getting data race errors if 2 threads generate a solution at the same time. Is there some sort of waiting function that can occur where a thread will not be able to overwrite until another thread has finished?
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.CopyOnWriteArrayList;
class Custom extends Thread {
private CopyOnWriteArrayList<Point> squarelist = new CopyOnWriteArrayList<>();
private static volatile CopyOnWriteArrayList<CopyOnWriteArrayList<Point>> listoflists = new CopyOnWriteArrayList<>();
private GUI g;
Custom(GUI g) {
this.g = g;
}
private void generate() {
int x = (int) (Math.random() * (600 - 20 + 1) + 20);
int y = (int) (Math.random() * (600 - 20 + 1) + 50);
squarelist.add(new Point(x,y));
}
public void run() {
for (int i = 0; i < 5; i++) {
generate();
}
CopyOnWriteArrayList<Point> copy = new CopyOnWriteArrayList<>(squarelist);
System.out.println("SOLUTION = " + copy.toString());
listoflists.add(copy);
SwingUtilities.invokeLater(() -> {
g.setSquares(new CopyOnWriteArrayList<>(copy));
});
}
}
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
GUI g = new GUI();
g.setVisible(true);
Thread[] threads = new Thread[32];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Custom(g);
threads[i].start();
}
});
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.CopyOnWriteArrayList;
public class GUI extends JFrame implements ActionListener {
private MyPanel m;
GUI() {
initialize();
}
private void initialize() {
this.setLayout(new FlowLayout());
Timer timer = new Timer(500, e -> {
m.setPaint();
m.repaint();
});
int height = 600;
int width = 600;
m = new MyPanel(height, width);
this.setSize(1000,1000);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(m);
timer.start();
}
#Override
public void actionPerformed(ActionEvent e) {
}
void setSquares(CopyOnWriteArrayList<Point> squarelist) {
m.setSquares(squarelist);
}
}
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.CopyOnWriteArrayList;
public class MyPanel extends JPanel implements ActionListener {
private boolean paint;
private CopyOnWriteArrayList<Point> squarelist;
MyPanel(int h, int w) {
squarelist = new CopyOnWriteArrayList<>();
paint = false;
this.setPreferredSize(new Dimension(w,h));
this.setBackground(Color.pink);
Border blackline = BorderFactory.createLineBorder(Color.black);
this.setBorder(blackline);
}
#Override
public void actionPerformed (ActionEvent e) {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(paint) {
for(Point p : squarelist) {
g.setColor(Color.BLUE);
g.drawRect((int) p.getX(),(int) p.getY(),20,20);
g.fillRect((int) p.getX(),(int) p.getY(),20,20);
}
}
}
void setPaint() {
paint = true;
}
void setSquares(CopyOnWriteArrayList<Point> squarelist) {
this.squarelist = squarelist;
}
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
Im writing RiverRaidlike game, and i have a problem with restarting the game.
When Craft crashes i want to make it able to press space and restart the game.
Problem is that i have everything drawn on the JPanel.
My research:
When i try to pass a game object to the Panel class and dispose the last window there is a NullPointerException...
private void restart()
{
game.dispose();
new Game();
repaint();
}
I think it's a problem with calling constructors.. but im not sure...
When i try to reinitialize the JPanel it just repaints all but doesnt remove the old content
private void initBoard() {
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.PINK);
setLayout(new GridBagLayout());
craft = new Craft(ICRAFT_X, ICRAFT_Y);
setMinimumSize(new Dimension(WIDTH, HEIGHT));
initEnemiesAndAddThem();
czas = new Timer(delay, this);
czas.start();
}
private void initEnemiesAndAddThem() {
enemy = new EnemyJet(0, -600);
enemies.add(enemy);
fuel = new Fuel(0, 0);
fuels.add(fuel);
obstacle = new Obstacle(0, -600);
obst.add(obstacle);
}
private void restart()
{
initBoard();
}
Lastly, when i try to implement KeyListener to the JFrame it doesnt work at all... tried to print out a string when i press space, but nothing happens...
All i can do is to stop the Timer and start it again but it pausing the game but not restarting it.
Those are the JFrame class and JPanel class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package riverraid2;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
*
* #author Michał
*/
public class Game extends JFrame implements KeyListener {
private final static int WIDTH = 1024;
private final static int HEIGHT = 768;
Plansza panel;
Game() {
initGame();
}
private void initGame() {
Plansza panel = new Plansza();
setTitle("Reeevah Raaid");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(WIDTH, HEIGHT);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setMinimumSize(new Dimension(800, 600));
setMaximumSize(new Dimension(1680, 1050));
setLocationRelativeTo(null);
// panel.setState(new StartScreen(panel));
this.add(panel, BorderLayout.CENTER);
pack();
setVisible(true);
//setExtendedState(JFrame.MAXIMIZED_BOTH);
//setResizable(false);
}
public static void main(String[] args) {
new Game();
//ex.setVisible(true);
// ex.pack();
}
#Override
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
System.out.print("Spacja!");
}
}
#Override
public void keyReleased(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package riverraid2;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.util.ArrayList;
import javax.swing.Icon;
import javax.swing.JLabel;
/**
*
* #author Michał
*/
public class Plansza extends JPanel implements ActionListener {
private boolean paused = false;
private int ileWcisniec = 0;
private int slowDownSally = 0;
private int finalScore = 1;
private Game game;
private Timer czas;
private Thread thread;
private Craft craft;
private Fuel fuel;
private Obstacle obstacle;
private EnemyJet enemy;
private final int delay = 10;
private final int ICRAFT_X = 450;
private final int ICRAFT_Y = 600;
private final ArrayList<Fuel> fuels = new ArrayList<>();
private final ArrayList<EnemyJet> enemies = new ArrayList<>();
private final ArrayList<Obstacle> obst = new ArrayList<>();
boolean running = true;
long licznik = System.nanoTime();
public Plansza() {
// setBackground(Color.WHITE);
initBoard();
}
private void initBoard() {
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.PINK);
setLayout(new GridBagLayout());
craft = new Craft(ICRAFT_X, ICRAFT_Y);
setMinimumSize(new Dimension(WIDTH, HEIGHT));
initEnemiesAndAddThem();
czas = new Timer(delay, this);
czas.start();
}
private void initEnemiesAndAddThem() {
enemy = new EnemyJet(0, -600);
enemies.add(enemy);
fuel = new Fuel(0, 0);
fuels.add(fuel);
obstacle = new Obstacle(0, -600);
obst.add(obstacle);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
if (!running) {
drawGameOver(g, "");
g.drawString("Press SPACE to restart the game!", getWidth()/4, getHeight()/2);
}
Toolkit.getDefaultToolkit().sync();
}
private void doDrawing(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
drawStrings(g2);
ArrayList ms = craft.getMissiles();
for (Object m1 : ms) {
Missile m = (Missile) m1;
g2.drawImage(m.getImage(), m.getX(), m.getY(), this);
}
g2.drawImage(craft.getImage(), craft.getX(), craft.getY(), this);
for (EnemyJet enemy : enemies) {
g2.drawImage(enemy.getImage(), enemy.getX(), enemy.getY(), this);
}
for (Fuel fuel : fuels) {
g2.drawImage(fuel.getImage(), fuel.getX(), fuel.getY(), fuel.getHeight(), fuel.getHeight(), this);
}
for (Obstacle o : obst) {
g2.drawImage(o.getImage(), o.getX(), o.getY(), this);
}
drawStrings(g2);
}
private void drawGameOver(Graphics g, String msg) {
Font small = new Font("Helvetica", Font.BOLD, 36);
FontMetrics fm = getFontMetrics(small);
g.setColor(Color.white);
g.setFont(small);
g.drawString("GAME OVER", getWidth()/4, (getHeight()/2)-50);
g.drawString(msg, (1024 - fm.stringWidth(msg)) / 2,
800 / 2);
}
public void drawStrings(Graphics2D g) {
String score;
String fuelString;
score = "Score: " + finalScore;
g.setColor(Color.WHITE);
g.setFont(new Font("Consolas", Font.PLAIN, 48));
g.drawString(score, 150, 48);
fuelString = "Fuel: " + craft.getFuel();
g.drawString(fuelString, 650, 48);
}
public String gameOver() {
String msg = "";
if (craft.getFuel() <= 0) {
running = false;
msg = "Zabrakło ci paliwa!";
}
if (finalScore == 1000000) {
running = false;
msg = "Gra ukończona, jesteś mistrzem River Raid, oto Twój medal Mistrza River Raid";
}
return msg;
}
private void restart()
{
initBoard();
}
#Override
public void actionPerformed(ActionEvent e) {
removeAll();
gameRunning();
updateMissiles();
updateCraft();
updateEnemy();
updateFuel();
updateObstacles();
checkCollision();
gameOver();
if (slowDownSally % 100 == 0) {
updateArrays();
}
if (finalScore % 2000 == 0) {
levelUpJets();
}
repaint();
slowDownSally++;
}
public boolean gameState()
{
return running;
}
private void updateMissiles() {
ArrayList ms = craft.getMissiles();
for (int i = 0; i < ms.size(); i++) {
Missile m = (Missile) ms.get(i);
if (m.isVisible()) {
m.move();
} else {
ms.remove(i);
}
}
}
private void updateArrays() {
EnemyJet e = new EnemyJet(0, -600);
enemies.add(e);
Fuel f = new Fuel(0, -500);
fuels.add(f);
Obstacle o = new Obstacle(0, -600);
obst.add(o);
}
private void updateEnemy() {
for (int i = 0; i < enemies.size(); i++) {
EnemyJet e = enemies.get(i);
if (e.isVisible()) {
e.move();
} else {
enemies.remove(i);
}
}
}
private void updateFuel() {
for (int i = 0; i < fuels.size(); i++) {
Fuel e = fuels.get(i);
if (e.isVisible()) {
e.move();
} else {
fuels.remove(i);
}
}
}
private void updateObstacles() {
for (int i = 0; i < obst.size(); i++) {
Obstacle o = obst.get(i);
if (o.isVisible()) {
o.move();
} else {
obst.remove(i);
}
}
}
private void updateCraft() {
craft.move();
}
public void gameRunning() {
if (running == false) {
czas.stop();
}
}
void checkCollision() {
Rectangle r3 = craft.getBounds();
for (EnemyJet enemy : enemies) {
Rectangle r2 = enemy.getBounds();
if (r3.intersects(r2)) {
craft.setVisible(false);
enemy.setVisible(false);
running = false;
}
}
ArrayList<Missile> ms = craft.getMissiles();
for (Missile m : ms) {
Rectangle r1 = m.getBounds();
for (EnemyJet enemy : enemies) {
Rectangle r2 = enemy.getBounds();
if (r1.intersects(r2)) {
m.setVisible(false);
enemy.setVisible(false);
enemy.vis = false;
finalScore += 100;
}
}
}
for (Fuel fuel : fuels) {
Rectangle r4 = fuel.getBounds();
if (r3.intersects(r4)) {
craft.addFuel(50);
fuel.setVisible(false);
}
}
for (Obstacle o : obst) {
Rectangle r5 = o.getBounds();
for (Missile m : ms) {
Rectangle r1 = m.getBounds();
if (r1.intersects(r5)) {
m.setVisible(false);
}
}
if(r5.intersects(r3))
{
running = false;
}
}
}
private void levelUpJets() {
for (EnemyJet e : enemies) {
e.levelUp();
}
}
private class TAdapter extends KeyAdapter {
#Override
public void keyReleased(KeyEvent e) {
craft.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
craft.keyPressed(e);
restart();
}
}
}
It's not a problem of NullPointerException but i think more conceptional problem, about how to restart the game... I only suggested that one of my tries gave that error but I did it to show an effort in findin the solution.
I can't answer why you are getting a null pointer. I would suggest that you would just create a method that would reset the game instead of creating a new game object. As for the JPanel not resetting itself, it doesn't seem that you actually reset anything. Consider writing a method that would reset all your fields. Hope this is helpful!
There is no need to reinitialize everything, like you do in your initBoard (listener). Those are fine. Try to separate your functions. You are setting size and creating a craft and so on in the same method. All you need is to reinitialize your positions, some values, bool states, only stuffs that affects the game play. Make a separated method for these, and call them whenever you want, and don't forget to clear your arraylists.
In a Java applet, I'm trying to slow down the painting of an image made up of parts, so I wrote a test program to get the basic concept working. I'm using a thread to draw a number of boxes one at a time instead of a timer because I want to be able to click the go button to reset the drawing process at any time.
The problem is, after drawing a box, it moves down a bit and an extra of the label shows up at the top of the screen. When the mouse moves off the button at the bottom, a dummy button also shows up at the top of the screen. The dummy button doesn't respond to clicks (only the real one at the bottom does), it's just there.
I'm still pretty new at this, so any help would be greatly appreciated.
Here's the JApplet class:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class TestDraw extends JApplet implements ActionListener
{
private DrawPanel panel;
private JLabel lbl1;
JButton go;
Thread t;
public void init()
{
lbl1 = new JLabel("hi");
go = new JButton("GO");
go.addActionListener(this);
panel = new DrawPanel();
getContentPane().setBackground(Color.yellow);
add(lbl1, BorderLayout.NORTH);
add(panel, BorderLayout.CENTER);
add(go, BorderLayout.SOUTH);
}
public void actionPerformed(ActionEvent ae){
// tried adding these. didnt help
//panel.validate();
//panel.repaint();
//validate();
panel.resetBoxes();
repaint();
}
public void start(){
t = new Thread(panel);
t.start();
}
}
Here's the DrawPanel Class:
import java.awt.*;
import java.security.SecureRandom;
import javax.swing.*;
public class DrawPanel extends JPanel implements Runnable
{
private SecureRandom randGen = new SecureRandom();
private Box[] boxes;
private int box2draw = 0;
public DrawPanel()
{
setBackground(Color.WHITE);
boxes = new Box[5];
for (int count = 0; count < boxes.length; count++){
int x = randGen.nextInt(300);
int y = randGen.nextInt(300);
int w = randGen.nextInt(300);
int h = randGen.nextInt(300);
Color color = new Color(randGen.nextInt(256), randGen.nextInt(256), randGen.nextInt(256));
boxes[count] = new Box(x,y,w,h,color);
}
}
public void paintComponent(Graphics g)
{
boxes[box2draw].draw(g);
box2draw++;
}
public void resetBoxes(){
boxes = new Box[5];
for (int count = 0; count < boxes.length; count++){
int x = randGen.nextInt(300);
int y = randGen.nextInt(300);
int w = randGen.nextInt(300);
int h = randGen.nextInt(300);
Color color = new Color(randGen.nextInt(256), randGen.nextInt(256), randGen.nextInt(256));
boxes[count] = new Box(x,y,w,h,color);
box2draw = 0;
}
}
public void run(){
while(true){
try{
Thread.sleep(750);
}
catch(InterruptedException e){
JOptionPane.showMessageDialog(null, "interrupted");
}
repaint();
}
}
}
And finally, the Box class:
import java.awt.Color;
import java.awt.Graphics;
public class Box
{
private int x;
private int y;
private int w;
private int h;
private Color color;
public Box(int x,int y,int w,int h,Color color)
{
// initialise instance variables
this.x = x;
this.y=y;
this.w=w;
this.h = h;
this.color=color;
}
public void draw(Graphics g)
{
g.setColor(color);
g.drawRect( x, y, w, h);
}
}
Thank you for your time!
Problems:
You've got code logic within a painting method -- something that you should never do -- including your incrementing an array index. You don't have full control of when or even if this method is called and so program logic does not belong there, just painting. If you need to increment your array index, do it elsewhere, perhaps within your thread's while (true) loop. Also take care not to have the index go beyond the size of the array.
You never call the super's paintComponent method within your override, and this will prevent the component from doing housekeeping painting, probably your main problem.
If you need to display multiple items, then consider either drawing to a BufferedImage and displaying that within paintComponent, or creating a collection of Shape objects and drawing all of them within paintComponent via a for-loop.
I prefer to use the Swing-safer Swing Timer. While it doesn't matter if only calling repaint() if you want to make any other Swing calls intermittently, it makes life much easier and coding safer.
For example
package foo1;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TestDraw2 {
#SuppressWarnings("serial")
private static void createAndShowGui() {
final DrawPanel2 drawPanel = new DrawPanel2();
JButton drawButton = new JButton(new AbstractAction("Draw!") {
#Override
public void actionPerformed(ActionEvent e) {
drawPanel.resetBoxes();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(drawButton);
JFrame frame = new JFrame("TestDraw2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawPanel);
frame.getContentPane().add(btnPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class DrawPanel2 extends JPanel {
private static final int BOX_COUNT = 5;
private static final int TIMER_DELAY = 750;
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private Random randGen = new Random();
private Box[] boxes;
private int box2draw = 0;
public DrawPanel2() {
setBackground(Color.YELLOW);
boxes = new Box[BOX_COUNT];
for (int count = 0; count < boxes.length; count++) {
int x = randGen.nextInt(300);
int y = randGen.nextInt(300);
int w = randGen.nextInt(300);
int h = randGen.nextInt(300);
Color color = new Color(randGen.nextInt(256), randGen.nextInt(256),
randGen.nextInt(256));
boxes[count] = new Box(x, y, w, h, color);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < box2draw; i++) {
boxes[i].draw(g);
}
}
public void resetBoxes() {
boxes = new Box[BOX_COUNT];
for (int count = 0; count < boxes.length; count++) {
int x = randGen.nextInt(300);
int y = randGen.nextInt(300);
int w = randGen.nextInt(300);
int h = randGen.nextInt(300);
Color color = new Color(randGen.nextInt(256), randGen.nextInt(256),
randGen.nextInt(256));
boxes[count] = new Box(x, y, w, h, color);
box2draw = 0;
}
repaint();
new Timer(TIMER_DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
box2draw++;
if (box2draw > BOX_COUNT) {
box2draw = BOX_COUNT;
((Timer) e.getSource()).stop();
}
repaint();
}
}).start();
}
}
I have a JFrame with a subclass, Paint_Panel. Paint_Panel extends JPanel and implements a MouseListener.
I need to place three circles with mouse clicks. No problem. I have a button (Draw) that should draw lines from each circle's center to the other (thus - a triangle). I can maintain the coordinates within an ArrayList - no problem. However, when I try to reference the ArrayList by clicking the button, the list is returned empty. The Array isn't in memory at the time it is needed to draw the lines. Thoughts?
Note- Circles are hard-coded at 40.
Code:
public class Paint_Panel extends JPanel implements MouseListener {
public static int flag = 0;
boolean drawCircles = false;
boolean drawLines = false;
private final ArrayList<Point> points = new ArrayList<>();
public Paint_Panel() {
addMouseListener(this);
}
//Method to draw lines from point to point
public void drawLines() {
Graphics g = getGraphics();
drawLines = true;
paintComponent(g);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (drawCircles) {
for (int i = 0; i < points.size(); i++) {
//Circle number 1
g.setColor(Color.RED);
g.fillOval(points.get(0).x - 20, points.get(0).y - 20, 40, 40);
//Circle number 2
if (points.size() >= 2) {
g.setColor(Color.GREEN);
g.fillOval(points.get(1).x - 20, points.get(1).y - 20, 40, 40);
}
//Circle number 3
if (points.size() >= 3) {
g.setColor(Color.BLUE);
g.fillOval(points.get(2).x - 20, points.get(2).y - 20, 40, 40);
}
}
} else if (drawLines) {
g.setColor(Color.BLACK); //Set line color
g.drawLine(points.get(0).x, points.get(0).y, points.get(1).x, points.get(1).y);
g.drawLine(points.get(1).x, points.get(1).y, points.get(2).x, points.get(2).y);
g.drawLine(points.get(2).x, points.get(2).y, points.get(0).x, points.get(0).y);
}
}
public void mouseClicked(MouseEvent evt) { //Place circles for click event
Graphics g = getGraphics();
if (!drawCircles) {
prevX = evt.getX() - 20; //Allows placement at center. Size - radius
prevY = evt.getY() - 20;
points.add(evt.getPoint()); //Add point to ArrayList
if (flag < 3) { //Keep track of how many circles are placed
flag += 1;
drawCircles = true;
paintComponent(g);
} else if (flag == 3) { //If additional circles attempted, inform user
flag = 4;
System.out.println("Only 3 circles allowed."); //Debug
drawCircles = false;
}
}
drawCircles = false;
}
#Override
public void mousePressed(MouseEvent evt) { //Unused
}
#Override
public void mouseReleased(MouseEvent evt) { //Unused
}
#Override
public void mouseEntered(MouseEvent evt) { //Unused
}
#Override
public void mouseExited(MouseEvent evt) { //Unused
}
}
Here's one way to draw 3 circles and 3 lines. Edited to draw the circles first, then the lines. Edited again to check for an invalid button press.
I separated the view and controller logic.
Here's the runnable code.
package com.ggl.testing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CirclePaintTest implements Runnable {
private JFrame frame;
private PaintPanel paintPanel;
#Override
public void run() {
frame = new JFrame("Circle Paint Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
paintPanel = new PaintPanel();
mainPanel.add(paintPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
JButton lineButton = new JButton("Draw Lines");
lineButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if (paintPanel.isComplete()) {
paintPanel.setDrawLines(true);
paintPanel.repaint();
}
}
});
buttonPanel.add(lineButton);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new CirclePaintTest());
}
public class PaintPanel extends JPanel {
private static final long serialVersionUID = 6481890334304291711L;
private final Color[] colors = { Color.RED, Color.GREEN, Color.BLUE,
Color.ORANGE, Color.CYAN, Color.YELLOW };
private boolean drawLines;
private final int pointLimit;
private final List<Point> points;
public PaintPanel() {
this.points = new ArrayList<Point>();
this.pointLimit = 3;
this.drawLines = false;
this.addMouseListener(new CircleMouseListener());
this.setPreferredSize(new Dimension(400, 400));
}
public void setDrawLines(boolean drawLines) {
this.drawLines = drawLines;
}
public boolean isComplete() {
return points.size() >= pointLimit;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Point pp = null;
Point p0 = null;
for (int i = 0; i < points.size(); i++) {
g.setColor(colors[i]);
Point p = points.get(i);
g.fillOval(p.x - 20, p.y - 20, 40, 40);
pp = p;
}
if (drawLines && (points.size() > 1)) {
p0 = points.get(0);
pp = p0;
g.setColor(Color.BLACK);
for (int i = 1; i < points.size(); i++) {
Point p = points.get(i);
g.drawLine(pp.x, pp.y, p.x, p.y);
pp = p;
}
g.drawLine(pp.x, pp.y, p0.x, p0.y);
}
}
public class CircleMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent event) {
if (points.size() < pointLimit) {
points.add(event.getPoint());
PaintPanel.this.repaint();
}
}
}
}
}
You don't call repaint when flag equals 3, so there is no call to the paintComponent method with the right condition (drawCircles false and drawLines true).
I suggest you to call repaint either when flag equals to 3 or and the end of mouseClicked.
I am attempting to create a game of life simulator:
My code basically consists of a JFrame holding a grid of JPanels, and a corresponding sized 2d boolean array where each JPanel is specifically an instance of a class that extends JPanel
This class:
initializes the JPAnel to a set Size, makes it opaque, sets its background color (this all works) and adds a mouseListener to it which changes the color of the JPanel based on the value of the 2d boolean array in corresponding location before switching the value of the array.
I also pass the boolean array as a reference so that way each tile is carrying the same boolean array and they all can flip its values.
For some reason, the only background color the JPanel holds is the one I set during initialization. After that the JPanel does not change its background color, despite the mouseListener registering that it has been pressed, and furthermore despite the successful call of a repaint() method. Can someone please explain what on earth is going on? I don't have anything to go off of for debugging since everything seems to be right in place.
(the individual Conway Tile)
package conweezy;
import java.awt.Color;
import java.awt.event.*;
import javax.swing.*;
public class TheTile extends JPanel implements MouseListener
{
boolean[][] thearray;
int xindex;
int yindex;
public TheTile(double width, double height, int xloc, int yloc, boolean[][] inputworld, int i, int j)
{
super();
setSize((int)width, (int)height); setLocation(xloc, yloc);
thearray = inputworld; xindex = i; yindex = j; setLayout(null);
setOpaque(true);
if(!thearray[xindex][yindex])
{
setBackground(Color.BLACK);
}
if(thearray[xindex][yindex])
{
setBackground(Color.WHITE);
}
setVisible(true);
//addMouseListener(this);
}
public void mousePressed(MouseEvent e)
{
if(!thearray[xindex][yindex])
{
setBackground(Color.WHITE);
System.out.println(xindex + " " + yindex);
repaint();
}
if(!thearray[xindex][yindex])
{
setBackground(Color.BLACK);
repaint();
}
thearray[xindex][yindex] = !thearray[xindex][yindex];
repaint();
}
public void mouseClicked(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
}
.
(The Conway Grid):
package conweezy;
import java.awt.Event.*;
import java.awt.event.*;
import javax.swing.*;
public class TheUniverseFrame extends JFrame implements ActionListener
{
public static boolean[][] universalframe;
public TheTile[][] universaltiles;
boolean threadstate = false;
TheUniverseFrame(double xsize, double ysize, int tilexcount, int tileycount)
{
//set constants
setTitle("Welcome to the Game of Life: Datatronic Existence");
universalframe = new boolean[tilexcount][tileycount];
universaltiles = new TheTile[tilexcount][tileycount];
setSize((int)xsize+100, (int)ysize);
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
//initialize tiles and boolean array
int i = 0;
int j;
setVisible(true);
while(i < tilexcount)
{
j = 0;
while(j < tileycount)
{
universalframe[i][j] = false;
universaltiles[i][j] = new TheTile(xsize/((double)tilexcount), //tile width
ysize/((double)tileycount), //tile height
(int)(xsize/((double)tilexcount))*i, //tile x position
(int)(ysize/((double)tileycount))*j, //tile y position
universalframe, //boolean array
i, j); //tile position on array
try
{
Thread.sleep(0);
}
catch(InterruptedException e)
{
}
//universaltiles[i][j].addMouseListener(universaltiles[i][j]);
add(universaltiles[i][j]);
repaint();
j++;
}
i++;
}
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
}
}
The Main Class:
package conweezy;
public class Conweezy
{
public static void main(String[] args)
{
TheUniverseFrame theGame = new TheUniverseFrame(500,500,20,20);
}
}
Here's a working variation of your example that toggles a pixel's background color when clicked. Note,
Use invokeLater() to run on the EDT.
Remember to pack() the enclosing frame.
Call setVisible() once.
Override getPreferredSize() to establish a tile's size.
As tested:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
public class Conweezy {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TheUniverseFrame theGame = new TheUniverseFrame(500, 500, 20, 20);
}
});
}
private static class TheUniverseFrame extends JFrame {
public static boolean[][] universalframe;
public TheTile[][] universaltiles;
boolean threadstate = false;
TheUniverseFrame(double xsize, double ysize, int tilexcount, int tileycount) {
//set constants
setTitle("Welcome to the Game of Life: Datatronic Existence");
universalframe = new boolean[tilexcount][tileycount];
universaltiles = new TheTile[tilexcount][tileycount];
setLayout(new GridLayout(tilexcount, tileycount));
setDefaultCloseOperation(EXIT_ON_CLOSE);
//initialize tiles and boolean array
int i = 0;
int j;
while (i < tilexcount) {
j = 0;
while (j < tileycount) {
universalframe[i][j] = false;
universaltiles[i][j] = new TheTile(xsize / ((double) tilexcount), //tile width
ysize / ((double) tileycount), //tile height
(int) (xsize / ((double) tilexcount)) * i, //tile x position
(int) (ysize / ((double) tileycount)) * j, //tile y position
universalframe, //boolean array
i, j); //tile position on array
add(universaltiles[i][j]);
j++;
}
i++;
}
pack();
setVisible(true);
}
}
private static class TheTile extends JPanel {
boolean[][] thearray;
int xindex;
int yindex;
#Override
public Dimension getPreferredSize() {
return new Dimension(25, 25);
}
public TheTile(double width, double height, int xloc, int yloc, boolean[][] inputworld, int i, int j) {
thearray = inputworld;
xindex = i;
yindex = j;
setOpaque(true);
setBackground(Color.BLACK);
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
thearray[xindex][yindex] = !thearray[xindex][yindex];
if (thearray[xindex][yindex]) {
setBackground(Color.WHITE);
} else {
setBackground(Color.BLACK);
}
repaint();
System.out.println(xindex + " " + yindex);
}
});
}
}
}