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
Related
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) {
}
}
}
I'm writing a GUI for my neural network(https://github.com/banana01/Neural-Network If you need to see any other classes) to show a map of the network and I have a map organised by layers. I would like to be able to draw connections between the nodes on a transparent JPanel that is on top of the JPanel that has the layers and nodes in it.
I have read the following question but that requires the class be a JFrame, I would like to be able to do it in a JPanel so I can add it to a tab so I can have different tabs for different things such as the map, the input, setting etc.
placing a transparent JPanel on top of another JPanel not working
Here is my current class, lacking any sort of overlay layer.
public class NeuralNetworkDisplay extends JPanel //implements MouseListener
{
private Network ntk;
JPanel[] layerPanels;
JPanel[] layerSubPanels;
JButton[] nodeButtons;
JSplitPane splitPane;
JLayeredPane NNMap;
JPanel test;
ArrayList<Layer> layers = new ArrayList<Layer>();
ArrayList<Node[]> nodes = new ArrayList<Node[]>();
public NeuralNetworkDisplay(Network ntk)
{
setNtk(ntk);
parseNetworkDesign();
splitPane = new JSplitPane();
NNMap = new JLayeredPane();
test = new JPanel();
NNMap.setLayout(new GridLayout(3,1,5,5));
splitPane.setRightComponent(NNMap);
add(splitPane);
}
public void init()
{
drawLayers();
drawNodes();
}
public void parseNetworkDesign()
{
for (int i = 0;i < ntk.getLayers().size(); i++)
{
layers.add(ntk.getLayers().get(i));
}
for (int i = 0; i < layers.size(); i++)
{
nodes.add(layers.get(i).getNodes().toArray(new Node[layers.get(i).getNodes().size()]));
}
}
public Network getNtk() {
return ntk;
}
public void setNtk(Network ntk) {
this.ntk = ntk;
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
}
public ArrayList<Layer> getLayers() {
return layers;
}
public void setLayers(ArrayList<Layer> layers) {
this.layers = layers;
}
public ArrayList<Node[]> getNodes() {
return nodes;
}
public int getNodesSize() {
return nodes.size();
}
public int getLayersSize() {
return layers.size();
}
public void setNodes(ArrayList<Node[]> nodes) {
this.nodes = nodes;
}
public void drawLayers()
{
layerPanels = new JPanel[getLayersSize()];
layerSubPanels = new JPanel[getLayersSize()];
for (int i = 0; i < layerPanels.length; i++)
{
layerPanels[i] = new JPanel();
layerSubPanels[i] = new JPanel();
layerPanels[i].setLayout(new FlowLayout());
layerSubPanels[i].setLayout(new GridLayout(3,5,5,5));
layerPanels[i].add(new JLabel("Layer::"+i));
layerPanels[i].add(layerSubPanels[i]);
NNMap.add(layerPanels[i]);
}
}
public void drawNodes()
{
int nod = 0;
for (int i = 0; i < getNodes().size(); i++)
{
nod += getNodes().get(i).length;
}
nodeButtons = new JButton[nod];
for (int i = 0; i < getLayersSize(); i++)
{
for (int j = 0; j < getNodes().get(i).length; j++)
{
//nodeButtons[j]
layerSubPanels[i].add(MyFactory.createNODEButton(getNodes().get(i)[j]));
}
}
}
}
This is a JPanel that is added to the main window in a split pane. That is all done in a different class.
Here is the Map Panel:
What would I use to create a transparent JPanel on top of the JPanel that contains the map. So I could draw connections between the nodes.
There's probably a few ways you could do this, but one way might be to create a custom JLayeredPane, which can maintain and paint the relationships between the components, for example...
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
GroupPane parent = new GroupPane("Parent", Color.RED);
GroupPane child1 = new GroupPane("Child 1", Color.BLUE);
GroupPane child2 = new GroupPane("Child 2", Color.CYAN);
parent.setBounds(10, 10, 100, 100);
child1.setBounds(10, 150, 100, 100);
child2.setBounds(150, 150, 100, 100);
ConnectionPane connectionPane = new ConnectionPane();
connectionPane.add(parent, child1);
connectionPane.add(parent, child2);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(connectionPane);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GroupPane extends JPanel {
public GroupPane(String name, Color background) {
setLayout(new GridBagLayout());
add(new JLabel(name));
setBackground(background);
}
}
public class ConnectionPane extends JLayeredPane {
private List<Component[]> connections;
public ConnectionPane() {
connections = new ArrayList<>();
MouseAdapter ma = new MouseAdapter() {
private Component dragComponent;
private Point clickPoint;
private Point offset;
#Override
public void mousePressed(MouseEvent e) {
Component component = getComponentAt(e.getPoint());
if (component != ConnectionPane.this && component != null) {
dragComponent = component;
clickPoint = e.getPoint();
int deltaX = clickPoint.x - dragComponent.getX();
int deltaY = clickPoint.y - dragComponent.getY();
offset = new Point(deltaX, deltaY);
}
}
#Override
public void mouseDragged(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
int xDelta = mouseX - offset.x;
int yDelta = mouseY - offset.y;
dragComponent.setLocation(xDelta, yDelta);
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
public void add(Component parent, Component child) {
if (parent.getParent() != this) {
add(parent);
}
if (child.getParent() != this) {
add(child);
}
connections.add(new Component[]{parent, child});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Component[] connection : connections) {
Rectangle parent = connection[0].getBounds();
Rectangle child = connection[1].getBounds();
g2d.draw(new Line2D.Double(parent.getCenterX(), parent.getCenterY(), child.getCenterX(), child.getCenterY()));
}
g2d.dispose();
}
}
}
http://www.youtube.com/watch?v=M0cNsmjK33E
I want to develop something similar to the link above using Java Swing. I have the sorting method and did while repaint but when I triggered the sorting, instead of showing the bars slowly sorting itself, it freezes and then unfreezes when the array has been fully sorted.
How do I fix this?
Edit: sorry forgot about the codes. its a very simple gui. and another class for sorting which sorts the whole array
public class SortGUI {
JFrame frame;
int frameWidth = 1000, frameHeight = 1000;
int panelWidth, panelHeight;
DrawPanel panel;
JPanel panel2;
JScrollPane scroll;
JViewport view;
static int[] S = new int[50000];
public static void main(String[] args) throws InterruptedException {
SortGUI app = new SortGUI();
initializeArray();
app.go();
}
public static void initializeArray()
{
for (int i = 0; i < S.length; i++) {
S[i] = (int) (Math.random() * 16581375);
}
}
public void go() throws InterruptedException {
//Frame
frame = new JFrame();
frame.setSize(frameWidth, frameHeight);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//panel
panel = new DrawPanel();
scroll = new JScrollPane(panel,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
//Layout
frame.add(scroll);
frame.addKeyListener(new keyListener());
while(true)
{
panel.repaint();
}
}
public class DrawPanel extends JPanel
{
public DrawPanel()
{
this.setPreferredSize(new Dimension(50000,930));
}
public void paintComponent(Graphics g)
{
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
for(int i = 0; i < S.length; i++)
{
int red = S[i] / 65025;
int green = (S[i] > 65025)? S[i] % 65025 : 0;
int blue = green;
blue %= 255;
green /= 255;
g.setColor(new Color(red,green,blue));
g.fillRect(i, 900 - (S[i] / 18500), 1, S[i] / 18500);
}
}
}
public class keyListener implements KeyListener{
public void keyTyped(KeyEvent ke) {
}
public void keyPressed(KeyEvent ke) {
if(ke.getKeyChar() == '1')
{
sorter.bubbleSort(S);
}
}
public void keyReleased(KeyEvent ke) {
}
}
}
Note: I started writing this before the question was deleted
Most likely your using some looping mechanism and praying that each iteration, the ui with be updated. That's a wrong assumption. The UI will not be update until the loop is finished. What you are doing is what we refer to as blocking the Event Dispatch Thread(EDT)
See How to use a Swing Timer. Make "iterative" updates in the ActionListener call back. For instance, if you want to animate a sorting algorithm, you need to determine what needs to be updated per "iteration" of the timer callback. Then each iteration repaint the ui.
So your Timer timer could look something like
Timer timer = new Timer(40, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
if (sortingIsDone()) {
((Timer)e.getSource()).stop();
} else {
sortOnlyOneItem();
}
repaint();
}
});
Your sortOnlyOneItem method should only, well, perform a sort for just one item. And have some sort of flag to check if the sorting is done, then stop the timer.
Other notes:
You should be calling super.paintComponent in the paintComponent method, if you aren't going to paint the background yourself. Generally I always do though.
Here's a complete example. I'm glad you figured it out on your own. I was working on this example before I saw that you got it.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collections;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SelectionSortAnimate extends JPanel {
private static final int NUM_OF_ITEMS = 20;
private static final int DIM_W = 400;
private static final int DIM_H = 400;
private static final int HORIZON = 350;
private static final int VERT_INC = 15;
private static final int HOR_INC = DIM_W / NUM_OF_ITEMS;
private JButton startButton;
private Timer timer = null;
private JButton resetButton;
Integer[] list;
int currentIndex = NUM_OF_ITEMS - 1;
public SelectionSortAnimate() {
list = initList();
timer = new Timer(200, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (isSortingDone()) {
((Timer) e.getSource()).stop();
startButton.setEnabled(false);
} else {
sortOnlyOneItem();
}
repaint();
}
});
startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
resetButton = new JButton("Reset");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
list = initList();
currentIndex = NUM_OF_ITEMS - 1;
repaint();
startButton.setEnabled(true);
}
});
add(startButton);
add(resetButton);
}
public boolean isSortingDone() {
return currentIndex == 0;
}
public Integer[] initList() {
Integer[] nums = new Integer[NUM_OF_ITEMS];
for (int i = 1; i <= nums.length; i++) {
nums[i - 1] = i;
}
Collections.shuffle(Arrays.asList(nums));
return nums;
}
public void drawItem(Graphics g, int item, int index) {
int height = item * VERT_INC;
int y = HORIZON - height;
int x = index * HOR_INC;
g.fillRect(x, y, HOR_INC, height);
}
public void sortOnlyOneItem() {
int currentMax = list[0];
int currentMaxIndex = 0;
for (int j = 1; j <= currentIndex; j++) {
if (currentMax < list[j]) {
currentMax = list[j];
currentMaxIndex = j;
}
}
if (currentMaxIndex != currentIndex) {
list[currentMaxIndex] = list[currentIndex];
list[currentIndex] = currentMax;
}
currentIndex--;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < list.length; i++) {
drawItem(g, list[i], i);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(DIM_W, DIM_H);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Sort");
frame.add(new SelectionSortAnimate());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I want show on concerned cases (row 2 from the grid), my JLabel contained in my Pawn class.
if(i==1 && (j>-1 && j<8)) { new Pawn(colorr); }
generate the Pawn but on the grid, the JLabel named 'label' isn't showed.
EDIT:I corrected some things like the container usage but my problem about my JLabel showing and to move my Pawn piece is still here.
I would also enjoy to move later the Pawn to another position on the grid.
package coordboutons;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CoordBoutons extends JFrame {
JFrame frame;
private Color colorr=Color.RED;
//private Container[][] cp=new Container[8][8];
CoordBoutons() {
super("GridLayout");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container contenant = getContentPane();
contenant.setLayout(new GridLayout(8, 8));
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
contenant.add(new CaseEchiquier(i, j));
}
}
pack();
setVisible(true);
}
class CaseEchiquier extends JPanel {
private int lin, col;
protected Color color;
CaseEchiquier(int i, int j) {
lin = i;
col = j;
setPreferredSize(new Dimension(80, 75));
setBackground((i + j) % 2 == 0 ? Color.WHITE : Color.GRAY);
if(i==1 && (j>-1 && j<8)) { new Pawn(colorr); }
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e){
CaseEchiquier current =(CaseEchiquier)e.getSource(); // get the object that the user pressed
// int linX = current.getLin();
// int colY = current.getCol();
System.out.println(lin+" "+col);
}
});
}
public int getCol() {
return col;
}
public int getLin() {
return lin;
}
}
public class ChessPiece
{
Color color;
JLabel label;
}
public class Pawn extends ChessPiece
{
public Pawn(Color c)
{
this.color = c;
setBackground(colorr);
System.out.println("YATAAA !");
this.label = new JLabel(new ImageIcon("bp.png"));
//I need to show this label !;
}
public Color getColor()
{
return this.color;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame.setDefaultLookAndFeelDecorated(true);
CoordBoutons coordBoutons = new CoordBoutons();
}
});
}
}
I like to point out two major problems I saw in your code (there can be more :))
In your CoordButtons constructor you are doing the same thing 64
times. According to what I understood you want to create a grid of
8x8. So set the content pane layout to a 8x8 grid and add panels to
it.
CoordBoutons() {
super("GridLayout");
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setLayout(new GridLayout(8, 8));
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
getContentPane().add(new CaseEchiquier(i, j));
}
}
pack();
setVisible(true);
}
In your CaseEchiquier class just creating a Pawn object will
not help you to display it. Instead add the label of Pawn object to
your JPanel
if(i==1 && (j>-1 && j<8)) {
Pawn p = new Pawn(colorr);
add(p.label);
}
I'm trying to write the game of life. However, no matter how hard I try, I can't seem to add Cell components onto the frame with the buttons. They do appear if I make a new frame and add them, but even so, I can't seem to add more than one component.
So I how I add the components to the frame with all the stuff on it and how do I add multiple components?
Thanks!
Here's my code:
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class Visuals extends JFrame implements ActionListener{
private static Board b;
private GameOfLife g;
private JButton nextGen;
private JButton random;
public Visuals(Board b){
super("The Game of Life");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel=new JPanel();
nextGen = new JButton("Next Generation");
panel.add(nextGen);
nextGen.addActionListener(this);
random = new JButton("Random");
panel.add(random);
random.addActionListener(this);
this.add(panel);
this.setSize(800, 700);
this.setVisible(true);
/*for(int i=0, yShift=80; i<b.getRow(); i++, yShift+=20){
for (int j=0, xShift=30; j<b.getCol(); j++, xShift+=20){
Cell c= new Cell(xShift,yShift,i,j);
this.add(c);
}
}*/
Cell c= new Cell(100,100,1,1);
Cell d= new Cell(200,200,1,1);
this.add(c);
this.add(d);
JFrame frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 700);
frame.setVisible(true);
frame.add(c);
frame.add(d);
}
public void paint(Graphics g){
super.paint(g);
for(int i=0, yShift=80; i<b.getRow(); i++, yShift+=20){
for (int j=0, xShift=30; j<b.getCol(); j++, xShift+=20){
if(b.getSpot(i, j)==1){
g.setColor(Color.red);
g.fillRect(xShift, yShift, 10, 10);
}
else{
g.setColor(Color.white);
g.fillRect(xShift, yShift, 10, 10);
}
}
}
}
public static void main(String[] cnbe){
b= new Board (30,30);
Visuals v = new Visuals(b);
}
public void actionPerformed(ActionEvent event) {
Object cause = event.getSource();
if(cause == nextGen){
GameOfLife g=new GameOfLife(b);
g.nextGeneration();
System.out.println(g);
this.repaint();
}
if(cause == random){
GameOfLife g=new GameOfLife(b);
g.random();
System.out.println(g);
this.repaint();
}
}
public class Cell extends JComponent{
int row;
int col;
int x;
int y;
Rectangle r;
public Cell(int x, int y, int row, int col){
r= new Rectangle(x,y,10,10);
this.row=row;
this.col=col;
this.x=x;
this.y=y;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("DRAW ME",200,200);
Graphics2D g2= (Graphics2D) g;
g2.setColor(Color.green);
r= new Rectangle(x,y,100,100);
g2.fill(r);
/*if(b.getSpot(row, col)==1){
g.setColor(Color.red);
g.fillRect(x, y, 10, 10);
}
else{
g.setColor(Color.white);
g.fillRect(x, y, 10, 10);
}*/
}
class MousePressListener implements MouseListener{
public void mousePressed(MouseEvent event) {
/*int x= event.getX();
int y= event.getY();
if(x>r.getX() && x<r.getX()+10 && y>r.getY() && y<r.getY()+10){
if(b.getSpot(row, col)==1){
b.setSpot(row, col, 0);
repaint();
}
else{
b.setSpot(row, col, 1);
repaint();
}
}*/
}
public void mouseReleased(MouseEvent arg0) {
}
public void mouseClicked(MouseEvent arg0) {
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
}
}
}
You have an issue with Layout Managers. Each time you add a component to the JFrame you overwrite what was already there. I'm not too familiar with Game of Life, but I don't think you want your cells to be JComponents. You can represent your board as an array of booleans, representing the alive and dead state, so your Visual constructor becomes:
public Visuals(Board b) {
super("The Game of Life");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container container = getContentPane(); // 1
JPanel panel = new JPanel(new FlowLayout()); // 2
nextGen = new JButton("Next Generation");
panel.add(nextGen);
nextGen.addActionListener(this);
random = new JButton("Random");
panel.add(random);
random.addActionListener(this);
container.add(panel); // 3
setSize(800, 700);
setVisible(true);
}
In your Board class you would represent the board as an array:
public class Board{
private boolean[][] board;
public Board(int x, int y) {
board = new boolean[x][y];
}
}
Then in the nextGeneration method of your GameOfLife class, perform whatever calculations you're doing and set the true/false (or alive/dead) state of the positions on the Board.
Your Visuals.paint method then becomes something like:
public void paint(Graphics g) {
super.paint(g);
for (int i = 0, yShift = 80; i < b.getRow(); i++, yShift += 20) {
for (int j = 0, xShift = 30; j < b.getCol(); j++, xShift += 20) {
if (b.isAlive(i, j)) {
g.setColor(Color.red);
g.fillRect(xShift, yShift, 10, 10);
} else {
g.setColor(Color.white);
g.fillRect(xShift, yShift, 10, 10);
}
}
}
}
iaAlive is just returning the value of the board array at that position:
public boolean isAlive(int i, int j) {
return board[i][j];
}
But like I say, I'm not familiar with the game.