Adding a JButton to a Canvas - java

I've tried rearranging this a whole bunch and using different methods that weren't static but the button never appears. all of this code is meant for chess but I working on adding buttons to make it playable, and I've been having a hard time with this for the past few days. there is other issues like the mouse not doing anything, but i jut removed everything to try and focus on the buttons.
a
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class Main extends Canvas implements ActionListener, MouseListener {
private static JButton try144Button = new JButton();
public static void main(String[] args) {
JFrame frame = new JFrame("Chess");
Canvas canvas = new Main();
canvas.setSize(1000, 1000);
frame.add(canvas);
frame.add(try144Button);
frame.pack();
frame.setVisible(true);
}
public Main(){
try144Button.setBounds(0, 0, 500, 500);
try144Button.setText("CLICK ME");
try144Button.setBounds(210, 60, 150, 150);}
private void add(JButton try144Button) {
}
public void paint(Graphics g) {
int xshift;
int yshift = 0;
g.setColor(new Color(0, 0, 0));
for (int i = 0; i < 4; i++) {
xshift = 125;
for (int j = 0; j < 4; j++) {
g.fillRect(xshift, yshift, 125, 125);
xshift += 250;
}
xshift = 0;
yshift += 125;
for (int k = 0; k < 4; k++) {
g.fillRect(xshift, yshift, 125, 125);
xshift += 250;
}
yshift += 125;
}
initalprnt(g);
}
public void initalprnt(Graphics g) {
int xshift = 125;
int yshift = 0;
g.setColor(new Color(0, 100, 0));
for (int i = 0; i < 3; i++) {
if (i == 2) {
xshift = 125;
}
for (int j = 0; j < 4; j++) {
g.fillOval(xshift, yshift, 125, 125);
xshift += 250;
}
xshift = 0;
yshift += 125;
}
yshift += 250;
g.setColor(new Color(0, 0, 100));
for (int k = 0; k < 3; k++) {
if (k == 2) {
xshift = 0;
}
for (int j = 0; j < 4; j++) {
g.fillOval(xshift, yshift, 125, 125);
xshift += 250;
}
xshift = 125;
yshift += 125;
}
}
public void actionPerformed(ActionEvent evt) {
Object src = evt.getSource();
if (src == try144Button)
System.out.println("this worked");
}
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}

Unless you're doing some super low level work, you should avoid using Canvas, in your case, a JPanel will do just fine.
If you override a method of a class, you should beware of what that method does and either be prepared to replicate its work (as much as your implementation requires it to) or call it's super method.
I would recommend you start by looking at Painting in AWT and Swing and Performing Custom Painting to get a better understand of how painting works in Swing.
I would also encourage you to decouple the workflow, separating the various aspects of your system, to the point you have a "game board" component, which, all it does it what ever is needed of the game board and a seperate component for dealing with things like, "try again".
If you're clever, you can easily overlay this panels on top of each other and even do some neat effects with them
This is an extremely overly simplified example, but it's intention is to demonstrate:
Decoupling of responsibility
The utilisation of the "observer pattern" to achieve point 1
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.RadialGradientPaint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Chess");
JPanel contentPane = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = gbc.BOTH;
GameListener listener = new GameListener() {
private AlertPane alertPane;
private AlertPane getAlertPane() {
if (alertPane != null) {
return alertPane;
}
alertPane = new AlertPane();
alertPane.setGameListener(this);
return alertPane;
}
#Override
public void gameWasCompleted() {
contentPane.add(getAlertPane(), gbc);
contentPane.setComponentZOrder(getAlertPane(), 0);
contentPane.revalidate();
contentPane.repaint();
}
#Override
public void startNewGame() {
contentPane.remove(getAlertPane());
contentPane.revalidate();
contentPane.repaint();
}
};
MainPane mainPane = new MainPane();
mainPane.setGameListener(listener);
contentPane.add(mainPane, gbc);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface GameListener {
public void gameWasCompleted();
public void startNewGame();
}
public class AlertPane extends JPanel {
private GameListener gameListener;
private JButton try144Button;
public AlertPane() {
setLayout(new GridBagLayout());
setOpaque(false);
try144Button = new JButton();
try144Button.setText("CLICK ME");
try144Button.setBounds(210, 60, 150, 150);
add(try144Button);
try144Button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
gameListener.startNewGame();
}
});
}
public void setGameListener(GameListener gameListener) {
this.gameListener = gameListener;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Color startColor = new Color(255, 255, 0, 0);
Color endColor = new Color(255, 255, 0, 192);
RadialGradientPaint rgp = new RadialGradientPaint(
getWidth() / 2, getHeight() / 2,
Math.max(getWidth(), getHeight()),
new float[]{0f, 0.25f},
new Color[]{startColor, endColor});
g2d.setPaint(rgp);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
}
}
public class MainPane extends JPanel implements MouseListener {
private GameListener gameListener;
public MainPane() {
addMouseListener(this);
}
public void setGameListener(GameListener gameListener) {
this.gameListener = gameListener;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 1000);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int xshift;
int yshift = 0;
g.setColor(new Color(0, 0, 0));
for (int i = 0; i < 4; i++) {
xshift = 125;
for (int j = 0; j < 4; j++) {
g.fillRect(xshift, yshift, 125, 125);
xshift += 250;
}
xshift = 0;
yshift += 125;
for (int k = 0; k < 4; k++) {
g.fillRect(xshift, yshift, 125, 125);
xshift += 250;
}
yshift += 125;
}
initalprnt(g);
}
protected void initalprnt(Graphics g) {
int xshift = 125;
int yshift = 0;
g.setColor(new Color(0, 100, 0));
for (int i = 0; i < 3; i++) {
if (i == 2) {
xshift = 125;
}
for (int j = 0; j < 4; j++) {
g.fillOval(xshift, yshift, 125, 125);
xshift += 250;
}
xshift = 0;
yshift += 125;
}
yshift += 250;
g.setColor(new Color(0, 0, 100));
for (int k = 0; k < 3; k++) {
if (k == 2) {
xshift = 0;
}
for (int j = 0; j < 4; j++) {
g.fillOval(xshift, yshift, 125, 125);
xshift += 250;
}
xshift = 125;
yshift += 125;
}
}
public void mouseClicked(MouseEvent e) {
gameListener.gameWasCompleted();
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
}

Related

Program adding too many buttons

I'm trying to make a checkers game and and all seams well so far, but when I hover over the button the graphics glitch out and I don't know why. Also it adds a lot of buttons to the top and when I move it around (resize) it adds more. It also adds more when I press any green buttons. And they are very tiny buttons at the top and I don't see where they pop up in my code.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
private JButton Green;
private JButton Blue;
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Checkers");
JPanel contentPane = new JPanel();
GameListener listener = new GameListener() {
#Override
public void gameWasCompleted() {
contentPane.repaint();
}
#Override
public void startNewGame() {
System.out.println("button worked");
contentPane.repaint();
}
};
MainPane mainPane = new MainPane();
mainPane.setGameListener(listener);
contentPane.add(mainPane);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface GameListener {
void gameWasCompleted();
void startNewGame();
}
public class MainPane extends JPanel implements MouseListener {
private GameListener gameListener;
public MainPane() {
addMouseListener(this);
}
public void setGameListener(GameListener gameListener) {
this.gameListener = gameListener;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 1000);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int xshift;
int yshift = 0;
g.setColor(new Color(0, 0, 0));
for (int i = 0; i < 4; i++) {
xshift = 125;
for (int j = 0; j < 4; j++) {
g.fillRect(xshift, yshift, 125, 125);
xshift += 250;
}
xshift = 0;
yshift += 125;
for (int k = 0; k < 4; k++) {
g.fillRect(xshift, yshift, 125, 125);
xshift += 250;
}
yshift += 125;
}
initalprnt(g);
}
protected void initalprnt(Graphics g) {
int xshift = 125;
int yshift = 0;
g.setColor(new Color(0, 100, 0));
for (int i = 0; i < 3; i++) {
if (i == 2) {
xshift = 125;
}
for (int j = 0; j < 4; j++) {
g.fillOval(xshift, yshift, 125, 125);
Green = new JButton();
Green.setBackground(new Color(0, 100, 0, 0));
Green.setBounds(xshift, yshift, 125, 125);
add(Green);
xshift += 250;
}
xshift = 0;
yshift += 125;
}
yshift += 250;
g.setColor(new Color(0, 0, 100));
for (int k = 0; k < 3; k++) {
if (k == 2) {
xshift = 0;
}
for (int j = 0; j < 4; j++) {
g.fillOval(xshift, yshift, 125, 125);
Blue = new JButton();
Blue.setBackground(new Color(0, 0, 100, 0));
Blue.setBounds(xshift, yshift, 125, 125);
add(Blue);
xshift += 250;
}
xshift = 125;
yshift += 125;
}
buttons();
}
public void buttons() {
Green.addActionListener(e -> {
System.out.println("this does something");
gameListener.startNewGame();
});
Blue.addActionListener(e -> {
System.out.println("this did something");
gameListener.startNewGame();
});
}
public void mouseClicked(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
}
Basic rule of thumb, do not, under any circumstances, modify the state of the component (or any other component) during a paint pass. This can (and probably will) cause the component to be rescheduled for another paint pass and you'll end up in an infinite loop.
There are so many ways you "might" achieve this, for example, you could use JButtons in a GridLayout.
Then all you need to is devise an appropriate model and delegation/observer workflow to keep the UI in sync with the model
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
BoardPane boardPane = new BoardPane();
boardPane.setBoardListener(new BoardListener() {
#Override
public void cellWasSelected(Point p) {
System.out.println("Cell selected " + p);
}
});
frame.add(boardPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface BoardListener {
public void cellWasSelected(Point p);
}
public class BoardPane extends JPanel {
private Map<Point, JButton> cells = new HashMap<>();
private BoardListener boardListener;
public BoardPane() {
int gridSize = 8 * 8;
setLayout(new GridLayout(8, 8));
int index = 0;
for (int row = 0; row < 8; row++) {
int xPos = (row % 2 == 0) ? gridSize : 0;
for (int col = 0; col < 8; col++) {
index++;
JButton btn = new JButton();
btn.setOpaque(true);
btn.setFocusPainted(false);
btn.setBorderPainted(false);
// I'd prefer to rely on something like
// an image, such as an empty image for
// cells which are empty
btn.setPreferredSize(new Dimension(100, 100));
if (index % 2 == 0) {
btn.setBackground(Color.BLACK);
btn.setForeground(Color.WHITE);
} else {
btn.setBackground(Color.WHITE);
btn.setForeground(Color.BLACK);
}
Point p = new Point(col, row);
btn.putClientProperty("cell", p);
cells.put(p, btn);
add(btn);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
BoardListener listener = getBoardListener();
if (listener == null) {
return;
}
Point p = (Point)btn.getClientProperty("cell");
listener.cellWasSelected(p);
}
});
}
index++;
}
}
public void setBoardListener(BoardListener boardListener) {
this.boardListener = boardListener;
}
public BoardListener getBoardListener() {
return boardListener;
}
}
}
Generally, I would use either a completely component based or custom painting based solution and avoid mixing the two.
Remember, the board should be focused only on what the board needs to do and shouldn't be doing anything else. This is the point of "separation of concerns/responsibility"
A far more complex solution might use a custom layout to manage components on top of a custom painted board, but that is, simply way beyond the scope of the question or your abilities at this time

Changing the frame's display after every interval, like an animation

How can I use repaint here, that it changes the display after some interval, like an animation?
Ouput:
(Like initially and randomly it is) this-1 (after some short interval and randomly it changes to) this-2 and continued...
import java.awt.*;
import java.util.Random;
import javax.swing.*;
class MatrixPanel extends JPanel {
private final int sqW = 15;
private final int sqH = 15;
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
public void paintComponent(Graphics g) {
Random rand = new Random();
for (int i = 0; i < 300; i += this.sqW) {
for (int j = 0; j < 300; j += this.sqH) {
if (rand.nextInt(2) == 1) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.GRAY);
}
g.fillRect(i, j, this.sqW, this.sqH);
g.setColor(Color.BLACK);
g.drawRect(i, j, this.sqW, this.sqH);
}
}
}
}
class GameOfLifeGUI extends JFrame {
public GameOfLifeGUI() {
JSplitPane splitPane = new JSplitPane();
/*Panels*/
JPanel topPanel = new JPanel();
JPanel bottomPanel = new JPanel();
/*Label - 1*/
JLabel generationLabel = new JLabel("GenerationLabel");
generationLabel.setText("Generation #");
generationLabel.setFont(new Font("Comic Sans MS", Font.PLAIN, 14));
generationLabel.setBounds(10, 5, 300, 20);
/*Label - 2*/
JLabel aliveLabel = new JLabel("AliveLabel");
aliveLabel.setText("Alive: ");
aliveLabel.setFont(new Font("Comic Sans MS", Font.PLAIN, 14));
aliveLabel.setBounds(10, 25, 300, 20);
topPanel.setLayout(null);
topPanel.add(generationLabel);
topPanel.add(aliveLabel);
bottomPanel.add(new MatrixPanel());
setPreferredSize(new Dimension(315, 405));
getContentPane().setLayout(new GridLayout());
getContentPane().add(splitPane);
splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
splitPane.setDividerLocation(50);
splitPane.setTopComponent(topPanel);
splitPane.setBottomComponent(bottomPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
pack();
}
public static void main(String[] args) {
new GameOfLifeGUI().setVisible(true);
}
}
Specifically not repaint, if there are other components that I can use and meet my requirements will be most welcome.
Thank you.
You don't want to do the following:
public void paintComponent(Graphics g) {
Random rand = new Random();
for (int i = 0; i < 300; i += this.sqW) {
for (int j = 0; j < 300; j += this.sqH) {
if (rand.nextInt(2) == 1) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.GRAY);
}
g.fillRect(i, j, this.sqW, this.sqH);
g.setColor(Color.BLACK);
g.drawRect(i, j, this.sqW, this.sqH);
}
}
}
Since painting is done on the EDT, you need to keep your processing to a minimum, otherwise performance will suffer and you may even lock up your application.
Use a Swing timer and create the image in a BufferedImage object. BufferedImages provide a graphics context so you can use the same methods you are using in paintComponent.
You can set the timer interval to whatever works for you and then issue a repaint when the image is created. So it could look similar to the following:
final BufferedImage image = new BufferedImage(300,300,BufferedImage.TYPE_INT_RGB);
...
Timer timer = new Timer(0, ae->createImage());
timer.setDelay(300);
timer.start();
...
public void createImage(BufferedImage image) {
Random rand = new Random();
Graphics g = image.getGraphics();
for (int i = 0; i < 300; i += this.sqW) {
for (int j = 0; j < 300; j += this.sqH) {
if (rand.nextInt(2) == 1) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.GRAY);
}
g.fillRect(i, j, this.sqW, this.sqH);
g.setColor(Color.BLACK);
g.drawRect(i, j, this.sqW, this.sqH);
}
}
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Image observer not required so it can be set to null.
g.drawImage(image, 0,0, null);
}
Finally, you need to set your MatrixPanel size large enough to hold the image. Probably 300 x 300.

Brick Bracker Game with Java

I'm new to Java and trying build a brick breaker game with Java. I've searched many instructions from online to build this. I have a problem here that I can't find the solution online anymore.
When I run my code, it works fine, but when the ball hit the top of the frame, it just go through it and never come back. I want let the ball to hit the top and reflect from it. Can anyone help me to solve this problem. I've wrote three classes. Please let me know anything could be helpful!
This is main class:
package brickBreaker;
import javax.swing.JFrame;
class Main {
public static void main(String[] args) {
JFrame obj = new JFrame();
Gameplay gamePlay = new Gameplay();
obj.setBounds(10, 10, 700, 600);
obj.setTitle("Breakout Ball");
obj.setResizable(false);
obj.setVisible(true);
obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
obj.add(gamePlay);
}
}
This is Gameplay class:
package brickBreaker;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.Timer;
import javax.swing.JPanel;
public class Gameplay extends JPanel implements KeyListener, ActionListener{
private boolean play = false;
private int score = 0;
private int totalBricks = 21;
private Timer timer;
private int delay = 8;
private int playerX = 310;
private int ballposX = 120;
private int ballposY = 350;
private int ballXdir = -1;
private int ballYdir = -2;
private MapGenerator map;
public Gameplay() {
map = new MapGenerator(3, 7);
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
timer = new Timer(delay, this);
timer.start();
}
public void paint(Graphics g) {
//background
g.setColor(Color.black);
g.fillRect(1, 1, 692, 592);
// drawing map
map.draw((Graphics2D) g);
// scores
g.setColor(Color.white);
g.setFont(new Font("serif", Font.BOLD, 25));
g.drawString(""+score, 590, 30);
// borders
g.setColor(Color.yellow);
g.fillRect(0, 0, 3, 592);
g.fillRect(0 , 0, 692, 3);
g.fillRect(692, 0, 3, 592);
// the paddle
g.setColor(Color.green);
g.fillRect(playerX, 550, 100, 8);
// the ball
g.setColor(Color.yellow);
g.fillOval(ballposX, ballposY, 20, 20);
if (ballposY > 570) {
play = false;
ballXdir = 0;
ballYdir = 0;
g.setColor(Color.red);
g.setFont(new Font("serif", Font.BOLD, 30));
g.drawString("Game Over, Scores: ", 190, 300);
g.setFont(new Font("serif", Font.BOLD, 20));
g.drawString("Press Enter to Restart ", 230, 350);
}
if (totalBricks <= 0) {
play = false;
ballXdir = 0;
ballYdir = 0;
g.setColor(Color.red);
g.setFont(new Font("serif", Font.BOLD, 30));
g.drawString("You Won, Scores: ", 190, 300);
g.setFont(new Font("serif", Font.BOLD, 20));
g.drawString("Press Enter to Restart ", 230, 350);
}
g.dispose();
}
#Override
public void actionPerformed (ActionEvent e) {
timer.start();
if (play) {
if (new Rectangle(ballposX, ballposY, 20, 20).intersects(new Rectangle(playerX, 550, 100, 8))) {
ballYdir = -ballYdir;
}
A: for (int i = 0; i <map.map.length; i++) {
for (int j = 0; j < map.map[0].length; j++) {
if (map.map[i][j] > 0) {
int brickX = j * map.brickWidth + 80;
int brickY = i * map.brickHeight + 50;
int brickWidth = map.brickWidth;
int brickHeight = map.brickHeight;
Rectangle rect = new Rectangle(brickX, brickY, brickWidth, brickHeight);
Rectangle ballRect = new Rectangle(ballposX, ballposY, 20, 20);
Rectangle brickRect = rect;
if (ballRect.intersects(brickRect)) {
map.setBrickValue(0, i, j);
totalBricks--;
score += 10;
if (ballposX + 19 <= brickRect.x || ballposX + 1 >= brickRect.x + brickRect.width) {
ballXdir = -ballXdir;
} else {
ballYdir = -ballYdir;
}
break A;
}
}
}
}
ballposX += ballXdir;
ballposY += ballYdir;
if (ballposX < 0) {
ballXdir = -ballXdir;
}
if (ballposY < 0) {
ballXdir = -ballYdir;
}
if (ballposX > 670) {
ballXdir = -ballXdir;
}
}
repaint();
}
#Override
public void keyReleased (KeyEvent e) {}
#Override
public void keyTyped (KeyEvent e) {}
#Override
public void keyPressed (KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
if (playerX >= 600) {
playerX = 600;
} else {
moveRight();
}
}
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
if (playerX < 10) {
playerX = 10;
} else {
moveLeft();
}
}
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
if (!play) {
play = true;
ballposX = 120;
ballposY = 350;
ballXdir = -1;
ballYdir = -2;
playerX = 310;
score = 0;
totalBricks = 21;
map = new MapGenerator (3, 7);
repaint();
}
}
}
public void moveRight() {
play = true;
playerX += 20;
}
public void moveLeft() {
play = true;
playerX -= 20;
}
}
This is MapGenerator class:
package brickBreaker;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
public class MapGenerator {
public int map[][];
public int brickWidth;
public int brickHeight;
public MapGenerator(int row, int col) {
map = new int [row][col];
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
map[i][j] = 1;
}
}
brickWidth = 540/col;
brickHeight = 150/row;
}
public void draw(Graphics2D g) {
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
if (map[i][j] > 0) {
g.setColor(Color.white);
g.fillRect(j * brickWidth + 80, i * brickHeight + 50, brickWidth,
brickHeight);
g.setStroke(new BasicStroke(3));
g.setColor(Color.black);
g.drawRect(j * brickWidth + 80, i * brickHeight + 50, brickWidth,
brickHeight);
}
}
}
}
public void setBrickValue(int value, int row, int col) {
map[row][col] = value;
}
}
At lines 140-142, you have
if (ballposY < 0) {
ballXdir = -ballYdir;
}
You are reversing the ballXdir rather than the ballYdir when the ball hits the top. Replace with
if (ballposY < 0) {
ballYdir = -ballYdir;
}
and it will bounce off the top correctly.

JPanel doesn't fit in the Frame

The panel doesn't fit in the frame, and when I change the size of the frame a new panel is painted. I want the panel to fit and also to change the size on the frame without painting a new panel.
Here is the code:
import java.awt.*;
import javax.swing.*;
public class ColorGrid extends JPanel {
int length=200;
int width=200;
double stokastik;
public ColorGrid(int x,int y) {
setSize(200,200);
width=18*x;
length=18*y;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(int row=0; row <=length;row+=20) {
for(int col=0; col <=width;col+=20) {
stokastik= Math.random();
if(stokastik < 0.25){
g.setColor(Color.YELLOW);
}
else if (stokastik < 0.5) {
g.setColor(Color.BLUE);
}
else if (stokastik < 0.75) {
g.setColor(Color.GREEN);
} else {
g.setColor(Color.RED);
}
g.fillRect(row, col, 18, 18);
}
}
}
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setBounds(300,300,300,300);
ColorGrid grid = new ColorGrid(10,10);
frame.add(grid);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
}
}
Your code is confusing because you call setBounds/setSize, but eventually, you call pack() which will just resize everything according to preferred size of components.
The proper way to go is to override getPreferredSize() in your custom component. By all means, avoid calling setSize/setBounds/setLocation. This is the job of the LayoutManager.
Regarding the repaint of the panel, you don't have a choice. A panel can get repainted many times independently of your will. So the only way to avoid the change of colors when the repaint occurs, is to pre-calculate the colors upfront and then only iterate over the same colors when performing the custom painting.
Small demo code illustrating this:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ColorGrid extends JPanel {
double stokastik;
private int width;
private int length;
private Dimension preferredSize;
private Color[][] colors;
public ColorGrid(int x, int y) {
width = 20 * x;
length = 20 * y;
preferredSize = new Dimension(width, length);
colors = new Color[x][y];
for (int row = 0; row < x; row++) {
for (int col = 0; col < y; col++) {
stokastik = Math.random();
if (stokastik < 0.25) {
colors[row][col] = (Color.YELLOW);
} else if (stokastik < 0.5) {
colors[row][col] = (Color.BLUE);
} else if (stokastik < 0.75) {
colors[row][col] = (Color.GREEN);
} else {
colors[row][col] = (Color.RED);
}
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int row = 0; row < colors.length; row++) {
for (int col = 0; col < colors[row].length; col++) {
g.setColor(colors[row][col]);
g.fillRect(row * 20, col * 20, 18, 18);
}
}
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ColorGrid grid = new ColorGrid(10, 10);
frame.add(grid);
frame.pack();
frame.setVisible(true);
}
});
}
}
In your constructor set the preferred size.
public ColorGrid(int x, int y) {
setSize(200, 200);
setPreferredSize(new Dimension(200, 200));
width = 18 * x;
length = 18 * y;
}
Then it will show correctly on initial load..
As mentioned by another answer, also have your length and width defined proportionally.

Adding/Removing from a JPanel

I am trying to make a basic map where pressing a button moves a character.
I am using Netbeans and so far it's going smoothly! Except for trying to remove a JLabel from a JPanel and then add a new JLabel to it.
Here is my full code:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class startMap extends JFrame {
public int locX = 1;
public int locY = 1;
ImageIcon tile = new ImageIcon("src/tile.png");
JLabel tileLabel = new JLabel(tile);
ImageIcon berry = new ImageIcon("src/berry.png");
JLabel berryLabel = new JLabel(berry);
ImageIcon blank = new ImageIcon("src/blank.png");
JLabel blankLabel = new JLabel(blank);
JLabel testL = new JLabel("LOL");
JPanel[][] map = new JPanel[7][7];
public startMap() {
setBackground(Color.BLACK);
setFocusable(true);
keyHandler kh = new keyHandler();
addKeyListener(kh);
mapGUI();
}
public void mapGUI() {
JPanel mainP = new JPanel();
mainP.setBackground(Color.BLACK);
mainP.setLayout(new FlowLayout());
for (int x = 0; x < 7; x++) {
for (int i = 0; i < 7; i++) {
map[x][i] = new JPanel();
System.out.println("1");
blankLabel = new JLabel(blank);
map[x][i].setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
map[x][i].add(blankLabel);
}
}
for (int x = 1; x < 6; x++) {
for (int i = 1; i < 6; i++) {
System.out.println("2");
map[x][i].removeAll();
revalidate();
repaint();
tileLabel = new JLabel(tile);
map[x][i].add(tileLabel);
revalidate();
repaint();
}
}
System.out.println("3");
map[locX][locY].removeAll();
revalidate();
repaint();
map[locX][locY].add(berryLabel);
revalidate();
repaint();
for (int x = 0; x < 7; x++) {
for (int i = 0; i < 7; i++) {
mainP.add(map[x][i]);
}
}
add(mainP);
}
#Override
public void paint(Graphics g) {
super.paint(g);
}
private class keyHandler extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
locY+=1;
map[locX][locY].removeAll();
revalidate();
repaint();
map[locX][locY].add(berryLabel);
revalidate();
repaint();
}
}
}
}
Here is what changes the squares when the user clicks Right.
Here is the KeyAdapter code:
private class keyHandler extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
locY+=1;
map[locX][locY].removeAll();
revalidate();
repaint();
map[locX][locY].add(berryLabel);
revalidate();
repaint();
}
}}
NOTE: the system out is just a debugging method I use to check what's being called when.
So when I run it looks like this
Move to the right and revalidate $ repaint:
Why does the box located in 1,1 go to being gray?
Help figuring out how to make the boxes stay with a white square instead of turning back to gray.
----------------------------SSCCE----------------------------------
Use the full code above
and this is the main class:
import javax.swing.*;
public class TestGame extends JFrame {
public static void main(String[] args) {
startMap sm = new startMap();
sm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sm.setVisible(true);
sm.setSize(380,415);
sm.setResizable(false);
}
}
Fixed Version:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class startMap extends JFrame {
public int locX = 1;
public int locY = 1;
ImageIcon tile = new ImageIcon("src/tile.png");
JLabel tileLabel = new JLabel(tile);
ImageIcon berry = new ImageIcon("src/berry.png");
JLabel berryLabel = new JLabel(berry);
ImageIcon blank = new ImageIcon("src/blank.png");
JLabel blankLabel = new JLabel(blank);
JLabel testL = new JLabel("LOL");
JPanel[][] map = new JPanel[7][7];
public startMap() {
setBackground(Color.BLACK);
setFocusable(true);
keyHandler kh = new keyHandler();
addKeyListener(kh);
mapGUI();
}
public void mapGUI() {
JPanel mainP = new JPanel();
mainP.setBackground(Color.BLACK);
mainP.setLayout(new FlowLayout());
for (int x = 0; x < 7; x++) {
for (int i = 0; i < 7; i++) {
map[x][i] = new JPanel();
System.out.println("1");
blankLabel = new JLabel(blank);
map[x][i].setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
map[x][i].add(blankLabel);
}
}
for (int x = 1; x < 6; x++) {
for (int i = 1; i < 6; i++) {
System.out.println("2");
map[x][i].removeAll();
tileLabel = new JLabel(tile);
map[x][i].add(tileLabel);
revalidate();
repaint();
}
}
System.out.println("3");
map[locX][locY].removeAll();
map[locX][locY].add(berryLabel);
revalidate();
repaint();
for (int x = 0; x < 7; x++) {
for (int i = 0; i < 7; i++) {
mainP.add(map[x][i]);
}
}
add(mainP);
}
#Override
public void paint(Graphics g) {
super.paint(g);
}
private class keyHandler extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
berryLabel = new JLabel(berry); //THIS
tileLabel = new JLabel(tile); //And THIS had to be RE initialized idk why.
map[locX][locY].removeAll();
map[locX][locY].add(tileLabel);
locY += 1;
map[locX][locY].removeAll();
map[locX][locY].add(berryLabel);
revalidate();
repaint();
}
}
}
}
Should be called after adding / removing
revalidate();
repaint();
Don't call repaint() from paint()

Categories

Resources