Reputation: 53
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) {}
}
}
Upvotes: 3
Views: 121
Reputation: 347334
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 JButton
s 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
Upvotes: 4