SOLVED: The set setRoomImage method was never called on the RoomTile Object. Thanks to #sorifiend for noticing this!
I currently place JLabels using this method:
public void spawnItem(Entity e, int x, int y, int i, int j) {
bgLabel[i][j] = new JLabel();
bgLabel[i][j].setBounds(x,y,e.width,e.height);
bgLabel[i][j].setIcon(e.sprite);
layeredPane.add(bgLabel[i][j], e.layer);
}
Where bgLabel[][] is an array of JLabels and e.sprite is an imageIcon as shown in the Entity Class below. As well, e.layer is the appropriate Integer (i.e. 0, 100, 200).
The Entity Class looks like this:
import javax.swing.*;
public class Entity {
public int width, height;
ImageIcon sprite;
Integer layer;
}
And I extend the entity class like this:
import java.net.URL;
public class RoomTile extends Entity{
boolean light;
public RoomTile(boolean isLight) {
height = 52;
width = 52;
layer = 0;
light = isLight;
}
public void setRoomImage(String s) {
URL url;
if (light) {
url = getClass().getResource("Assets/" + s + ".png");
} else {
url = getClass().getResource("Assets/Dark" + s + ".png");
}
sprite = new ImageIcon(url);
}
}
All JLabels are placed by nested for loop iterating over a 2d array, the object is then added to the layered pane using the spawnItem method. This all works properly and a grid of objects, such as rooms, are placed and visible. However, when attempting to change the icon of these JLabels, they simply disappear.
I am using the method setLight to receive the label that is desired to be changed:
public void setLight(int i, int j) {
RoomTile lightRoom = new RoomTile(true);
bgLabel[i][j].setIcon(lightRoom.sprite);
repaint();
revalidate();
}
The setLight method is within a class which extends JFrame.
When setLight is called, the JLabel at the grid position provided, simply disappears, rather than its icon changing. I'm not sure where I've gone wrong and any help would be greatly appreciated.
Related
Very new here. Trying to learn Java.
I figured I'd write a very simple "Game Of Life" auto-algorithm to see if I could grasp some of the basics - (The syntax and concepts are pretty straightforward from other languages etc.)
I've managed to muddle through and seem to be "getting the hang of it" but I've reached a pretty steep hill now.
The code described here will compile and is executable, but as you will see, despite the #override to DrawComponent and the repaint() call, the actual image displayed on-screen does not appear to change...
DIRECT QUESTION IS:
How can I ensure the display is updated every "loop"?
FLUFF & SAMPLE SOURCE:
I appreciate the procedural and non-distributed // rigid single encapsulated class here is not the ideal approach for Java, nor is this "game of life" a particularly appropriate use fothe language - BUT Iwanted to focus on getting core elements and understanding first before I 'advance' onto other things. Secondly, I appreciate this is not a very efficient solution either, but again, I wanted to learn by trying something straightforward and readable so I could easily SEE what was happening and ensure it was working properly as expected.
Third, my naming or formatting conventions may be unusual or non-standard, for this I apologise and again appreciate there are preferred ways. This was not necessarily a priority for me in learning how the language works at this time.
I welcome any advice and tips but please consider I am a complete newcomer to using Java so may not be familiar with concepts and terminologies etc.
/*
Project.java
By: PJ Chowdhury
Entire program encapsulated in single class
Created 29-Oct-2018
Updated: 07-Nov-2018
Added graphics library
*/
//Import the basic required graphics classes.
import java.awt.image.BufferedImage;
import java.awt.*;
//Import the basic applet classes.
import javax.swing.*;
//Core class
public class project
{
//Control value - determines when overpopualted or extinct
private static int supercount;
//Control value - how many surrounding cells must be alive for the central cell to survive
private static byte thrive=4;
//Define & declare effective constant size values
private static byte size=64;
private static byte cellsize=4;
//Declare effective singleton arrays of cells
private static boolean[][] cells;
private static boolean[][] prolif;
//Declare Window Frame
public static JFrame frame;
//Declare Graphics
public static JPanel panel;
//main entry-point. Execution must include parameter argument.
public static void main(String[] args)
{
initialise();
do
{
runtime();
defaultcells();
}
while (1>0); //Bad form of course. I wanted an infinite loop. The window can be closed at user request.
}
//Initialises window & graphics frame
public static void initialiseframe()
{
//Create Window
frame = new JFrame("Life Cells");
//Define window parameters
frame.setSize((int)cellsize*size,(int)cellsize*size);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//Create a window panel to accept graphics
panel = new JPanel()
{
//Overload PaintComponent method to redraw image when the frame panel is redrawn
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
}
};
//attach this panel as a gadget to the frame window
frame.add(panel);
//frame.pack();// Deprecated as this resizes frame window to a minimal size
frame.validate(); // required since panel was added after setVisible was called
frame.repaint(); // required since panel was added after setVisible was called
}
//Initialises & defaults cells
public static void initialisecells()
{
//Define array sizes
cells = new boolean[size][size];
prolif = new boolean[size][size];
// Populate with defaults
defaultcells();
}
//Sets randomised state for each cell
public static void defaultcells()
{
byte x;
byte y;
for (y=0;y<size;y++)
{
for (x=0;x<size;x++)
{
if (Math.random()>=0.5)
{
}
else
{
}
}
}
}
//Wraps initialisation routines
public static void initialise()
{
initialiseframe();
initialisecells();
}
//iterates cells (twice) to determine if they survive or decline and draw to image
public static void process()
{
//Prepare image for cell drawing
Graphics g=panel.getGraphics();
byte x;
byte y;
supercount=0;
//First pass - check if cell will thrive
for (y=0;y<size;y++)
{
for (x=0;x<size;x++)
{
checkcell(x,y);
}
}
//Second pass - apply thrive or wither
for (y=0;y<size;y++)
{
for (x=0;x<size;x++)
{
if (updatecell(x,y))
{
}
if (cells[x][y])
{
}
}
}
}
//sets prolif equivalent depending on status of surrounding cells. This is used in update to set these cells to thrive
public static void checkcell(byte x, byte y)
{
byte count=getsurrounding((int)x,(int)y);
if (count>thrive)
{
prolif[x][y]=true;
}
else
{
if (count<thrive)
{
prolif[x][y]=false;
}
else
{
prolif[x][y]=cells[x][y];
}
}
}
//updates cell with prolif equivalent and returns true if cahnged
public static boolean updatecell(byte x, byte y)
{
if (cells[x][y]!=prolif[x][y])
{
cells[x][y]=prolif[x][y];
return true;
}
return false;
}
//returns number of thriving "cells" surrounding cell at given coords
public static byte getsurrounding(int x, int y)
{
int u=(x-1);
int v=(y-1);
int ux;
int vy;
byte count=0;
for (v=(y-1);v<(y+2);v++)
{
//Use wraparound for edge cells
vy=(v+size) % size;
for (u=(x-1);u<(x+2);u++)
{
//Use wraparound for edge cells
ux=(u+size) % size;
//Only for surrounding cells, not this cell
if ((ux!=x) & (vy!=y))
{
}
}
}
return count;
}
//Draw cell at x,y : not the most efficient nor elegant method...
public static void drawcell(Graphics g, int x, int y, boolean live)
{
if (live)
{
// Draw this cell alive
//g.setColor(Color.GREEN);
}
else
{
// Draw this cell dead
g.setColor(Color.BLACK);
}
g.fillRect(x*cellsize, y*cellsize,cellsize,cellsize);
panel.repaint(x*cellsize, y*cellsize,cellsize,cellsize);
}
//Returns true if population is healthy. False if extinct or overcrowded
public static boolean populationanalysis()
{
return ((supercount<thrive)||(supercount>(int)(size*size)<<1));
}
//Main Loop method
public static void runtime()
{
int sanity=5000;
int loopcount=0;
do
{
process();
loopcount++;
if (populationanalysis())
{
break;
}
}
while (loopcount<sanity);
}
}
I have no idea how to fix this problem. What I am doing is trying to break up a monster class I have into different things, like one class for player, one for fireball, etc. I had everything working before I tried to break up the class but now I am getting an error. I was wondering if anyone could help me solve it and explain to me how not to repeat this error again. Thank you in advance.
EDIT: The error is on: animationTimer = new Timer(animationDelay, this);
EDIT:1 error found:
File: C:\Users\jozef\Java\Dragon Ball Z\Player.java [line: 45]
Error: incompatible types: Player cannot be converted to java.awt.event.ActionListener
Also, I do format properly but when i try to copy and paste my code into the box to post here it doesn't count it as code so i have to indent every line to get it to appear as code and no normal text.
import java.awt.Graphics;
import java.awt.MediaTracker;
import javax.swing.ImageIcon;
import java.awt.Image;
import java.awt.event.ActionEvent;
import javax.swing.Timer;
public class Player {
int x;
int y;
ImageIcon pictures[];
int total;
int current;
boolean sideMove;
int move;
Timer animationTimer;
int animationDelay = 80;
public Player(int startX, int startY, ImageIcon image[], boolean sideMove, int move) {
x = startX;
y = startY;
pictures = image;
total = pictures.length;
this.sideMove = sideMove;
this.move = move;
startAnimation();
}
public void draw(Graphics g) {
if (pictures[current].getImageLoadStatus() == MediaTracker.COMPLETE) {
Image img = pictures[current].getImage();
g.drawImage(img, x, y, null);
current = (current + 1) % total;
}
update();
}
public void update() {
if (sideMove == true) {
x += move;
} else {
y += move;
}
}
public void startAnimation() {
if (animationTimer == null) {
current = 0;
animationTimer = new Timer(animationDelay, this); // *** error ***
animationTimer.start();
} else if (!animationTimer.isRunning())
animationTimer.restart();
}
public void stopAnimation() {
animationTimer.stop();
}
}
Here:
animationTimer = new Timer(animationDelay, this);
Since the Player class does not implement ActionListener this can not be passed in to the Timer constructor as a valid parameter. A possible solution is to have your Player class implement ActionListener giving it an appropriate actionPerformed method:
public class Player implements ActionListener {
#Override
protected void actionPerformed(ActionEvent e) {
// your coded here
}
// .... rest of your code
or better still, use a different ActionListener such as an anonymous inner class.
e.g.,
public void startAnimation() {
if (animationTimer == null) {
current = 0;
animationTimer = new Timer(animationDelay, e -> timerActionPerformed(e));
animationTimer.start();
} else if (!animationTimer.isRunning()) {
animationTimer.restart();
}
}
private void timerActionPerformed(ActionEvent e) {
// TODO repeated code goes here
}
Side recommendations:
You've got code within your painting method that changes your Player object's state, something that you'll want to avoid. Understand that you can only partially control when or even if an object will be painted, and so it would be best to keep these separate.
Myself, I'd get the Timer out of the Player class and instead use a Timer as your game loop or animation controller in a more general overall control class, perhaps the Game class (or whatever your "universe" class is called), the class that holds and controls all of your logical entities such as your Player objects.
This is the signature of javax.swing.Timer constructor:
public Timer(int delay, ActionListener listener)
You are providing an int and a Player..
You should create an ActionListener as well and provide it to the constructor or you could pass this but Player class should implements ActionListener inteface (you should write actionPerformed method in the Player class).
Read more info about Timer Here (official java doc).
I am creating an app where bubbles bounce around the screen, you get points for popping them, and then they re-spawn.
Each bubble is exactly identical except for the speed and direction integers used to control their motion around the screen.
As of now I have a single ImageView called "bubble". Then I run the method randoms() which I created.
Code for randoms():
public void randoms(){
ySpeedRand = new Random();
xSpeedRand = new Random();
yPolarityRand = new Random();
xPolarityRand = new Random();
ySpeed = ySpeedRand.nextInt(5) + 4;
xSpeed = xSpeedRand.nextInt(5) + 4;
yPolarity = yPolarityRand.nextInt(3) + 1;
xPolarity = xPolarityRand.nextInt(3) + 1;
if (xPolarity == 1){
xSpeed*=-1;
}
if (yPolarity == 2){
ySpeed*=-1;
}
}
Then I have a listener to check when the bubble is tapped and then I make it invisible, rerun the randoms() block, and then make it visible.
This is the handler that controls the position of the bubbles:
final Handler handler = new Handler();
Runnable run = new Runnable() {
#Override
public void run() {
bubble.setX(bubble.getX()+xSpeed);
bubble.setY(bubble.getY()+ySpeed);
handler.postDelayed(this, 5);
}
};handler.post(run);
And I use this code to check if the bubble is still on the screen:
final Handler checkHandler = new Handler();
Runnable check = new Runnable() {
#Override
public void run() {
if (bubble.getX()>SCREEN_WIDTH-bubble.getWidth()/2){xSpeed*=-1;}
if (bubble.getX()<0){xSpeed*=-1;}
if (bubble.getY()>SCREEN_HEIGHT-bubble.getHeight()){ySpeed*=-1;}
if (bubble.getY()<bubble.getHeight()/2+barHeight+actionBorder.getHeight()){ySpeed*=-1;}
handler.postDelayed(this, 50);
}
};checkHandler.post(check);
Is there an easy way to simply expand this system so I can call a method createbubble() and then have the new bubbles assume the exact properties as the old ones, but with newly generated randoms?
I am 100% stuck and I cant find anything. Any help is extremely appreciated!
I was a little bit confused reading your question. Not sure why you're trying to use ImageView. Going with this as your goal:
Create a game which spawns bubbles which can be popped
When popped, bubbles should be moved to a random space on the screen
When bubbles move off the screen, reverse their direction.
I would make the following classes at least:
Launcher, where your main() method is stored and your game loop run
Window, which extends Canvas and wherein you'll setup a JFrame
Control, where physics are calculated every time Launcher completes a loop
Entity, an abstract java object
Bubble
Here's one way to make a game loop: http://www.java-gaming.org/index.php?topic=24220.0
Here's an example of how to make a JFrame:
import java.awt.Canvas;
import javax.swing.JFrame;
public class Window extends Canvas{
public Window(Launcher launcher){
JFrame frame = new JFrame("Title");
frame.setSize(700,500);
frame.setResizable(false);
frame.setLocationRelativeTo(null);;
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(launcher);
frame.setVisible(true);
launcher.setFrame(frame);
}
}
To keep track of the bubbles, I would declare and initialize a LinkedList<> in the Control class. To create bubbles run something like this in Control:
public class Control{
public LinkedList<Entity> entity = new LinkedList<Entity>();
Random rand = new Random();
public Control(){
//You will have to define these constants in the Launcher class
entity.add(
rand.nextInt(Launcher.WINDOW_WIDTH),
rand.nextInt(Launcher.WINDOW_HEIGHT)
);
}
//Called every time Launcher completes a game loop
tick(){
for(int i=0; i<entity.size(); i++){
entity.get(i).tick();
}
}
}
In the Entity class:
public abstract class Entity{
protected double x;
protected double y;
public Entity(int x, int y){
this.x = x;
this.y = y;
}
public abstract void tick();
public abstract void render(Graphics g);
//Getters and setters here ...
}
In the Bubble class:
public class Bubble extends Entity{
public double x = 0;
public double y = 0;
public Bubble(int x, int y){
super(x,y);
}
public void tick(){
//Physics go here
}
public void render(){
//Graphics functions go here
}
}
If any of this doesn't make sense, let me know and I'll explain in more detail and even go as far as to make the entire program for you considering the simplicity of the task.
I am working to develop a GUI in which I paint some 2D shapes repeatedly on different locations. Currently I am having a method createGUI() that creates the basic layout and the panels and then I call the constructor for the content_panel to create 2D shapes in the content_panel.
But, I want to use another method to create the shapes in the main JPanel. Is there a way in Java, so that I can have two method calls in main. First method createGUI() creates the GUI including JFrames and JPanel. While the second method createShapes() creates shapes in the one specific JPanel - content_panel. I would like to call this createShapes() method repeatedly and pass different arguments to see shapes at different locations.
Please let me know if you need some more info or the question is unclear. Thanks
Code:
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class Board{
public static void main(String[] args)
{
createGUI();
drawShapes();
}
//This method creates the basic GUI
private static void createGUI()
{
//Creating the JFrame main window
JFrame mainFrame = new JFrame();
mainFrame.setSize(800, 500);
mainFrame.setTitle("Particle Filter");
mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mainFrame.setLocation(100, 100);
mainFrame.getContentPane().setLayout(new BoxLayout(mainFrame.getContentPane(), BoxLayout.X_AXIS));
//creates two panels content and sidebar. Sidebar has null layout
JPanel content = new JPanel();
content.setPreferredSize(new Dimension(700,500));
content.setBackground(Color.LIGHT_GRAY);
mainFrame.getContentPane().add(content);
JPanel sidebar = new JPanel();
sidebar.setBackground(Color.LIGHT_GRAY);
sidebar.setPreferredSize(new Dimension(100,500));
mainFrame.getContentPane().add(sidebar);
sidebar.setLayout(null);
//creates three buttons in sidebar
JButton start_button = new JButton("START");
start_button.setBounds(10, 75, 77, 23);
sidebar.add(start_button);
JButton stop_button = new JButton("STOP");
stop_button.setBounds(10, 109, 77, 23);
sidebar.add(stop_button);
JButton reset_button = new JButton("RESET");
reset_button.setBounds(10, 381, 77, 23);
sidebar.add(reset_button);
//calls the content_Walls class and sends the number of ovals to be generated
int n=1000; // n denotes the number of ovals
content.add( new Content_Walls(n));
mainFrame.setVisible(true);
}
private static void drawShapes()
{
}
}
class Content_Walls extends JPanel
{
ArrayList<Integer> list;
Content_Walls(int n)
{
setPreferredSize(new Dimension(680,450));
setBackground(Color.WHITE);
list = new ArrayList<Integer>(Collections.nCopies(n, 0));
}
public void paintComponent(Graphics g)
{
int x=0,y=0;
super.paintComponent(g);
createObstacles(g,150,225,100,40);
createObstacles(g,500,300,40,100);
for(int i=0;i<list.size();i++)
{
x=randomInteger(11,670); // bounds of x between which the particles should be generated
y=randomInteger(11,440); // bounds of y between which the particles should be generated
int radius = 4;
x=x-(radius/2);
y=y-(radius/2);
g.fillOval(x, y, radius, radius);
}
private void createObstacles(Graphics g, int x, int y, int width, int height)
{
g.setColor(Color.BLACK);
g.fillRect(x, y, width, height);
}
private static int randomInteger(int min, int max)
{
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
}
There are all sorts of problems with your code.
You're creating Swing components on the main thread instead of the Event Dispatch Thread. Search for help on this.
Have Board subclass JFrame and do the GUI initialization in the constructor or an instance method instead of a static method.
Make drawShapes() an instance method.
When you create the JPanel, store its reference in an instance variable (e.g., myPanel). This will be easier to do and will be a lot less messy if you fix #2.
If you do #2 and #3, just pass the reference to the drawShapes() method.
drawShapes()might not even be needed, if all the logic is in the paintComponent() method. Call myPanel.repaint() to invoke the paintComponent() method.
You should use event dispatching to let different JPanels component to act on the event.
e.g. You could attach a custom event with an event type and jpanel id; and then fire the event from the main. The panel listening to the event do something based on the logic.
Each JPanel listening to the event will intercept the event and if the jpanelid in the event matches to its own jpanel id, it will draw the shape.
I hope you get a pointer.
Here is a sample code, which I have not tested, but it shows how could you use event dispatching/listening to communicate between GUI components.
Define a ChangeEventListener interface
public interface ChangeEventListener {
public void stateChanged(ChangeEvent e);
}
And define an Event
public class ChangeEvent {
private Object source;
private int jPanelId;
public ChangeEvent(Object source, int jPanelId) {
this.source = source;
this.jPanelId= jPanelId;
}
public Object getSource() {
return source;
}
public int getJPanelId() {
return jPanelId;
}
}
Define your panel like
public class ShapePanel extends JPanel {
private int jPanelId;
private ChangeEventListener changeEventListener;
public void ShapePanel(int jPanelId){
this.jPanelId = jPanelId;
}
/*
.............
.............. Other code
.................
*/
public void addChangeEventListener(ChangeEventListener changeEventListener) {
this.changeEventListener = changeEventListener;
}
public int getJPanelId(){
return jPanelId;
}
public getChangeEventListener(){
return changeEventListener;
}
}
Your main should contain something like;
// Craete different Jpanel
JPanel squareShapePanel = new ShapePanel(1);
JPanel roundShapePanel = new ShapePanel(2);
JPanel triangleShapePanel = new ShapePanel(3);
// Attach event listener with each one like
squareShapePanel.addChangeEventListener(new ChangeEventListener() {
#Override
public void stateChanged(ChangeEvent e) {
if(e.getJPanelId() == squareShapePanel.getJPanelId()){
// Createshape method can be available inside JPanel code
// something like squareShapePanel.craeteShape();
// All in one it is a method which could do something for you on the event.
// Assuming that it is available in current class
createShape("square");
}
});
/*
Similarly attach eventlistener with each panels.
*/
// to draw the square shape, Fire change event
ChangeEvent event = new ChangeEvent(new String("Main"),1);
squareShapePanel.getChangeEventListener().stateChanged(event);
Hope this helps.
Check out Custom Painting Approaches for the two common ways to do custom painting:
Keep the Shapes you want to paint in an List and then just paint all the Shapes in the List
Use a BufferedImage and just draw the Shapes onto the BufferedImage.
Both examples contain an addRectangle(...) method that allows you to dynamically add a Rectangle to be painted.
This is my first attempt at using a GUI layout in Java. I am trying to create a simple memory card game, where the user flips over two cards, and tries to get a match, and if there's no match they flip back over, if there's a match they stay flipped until you get all the matches. I might have made it hard on myself though in that I made the whole game dynamic to the constructor variables that define the number of columns and rows of cards. I thought this was better than hard-coding a certain value in, but now I'm having trouble putting the images in my img folder onto my cards.
I understand that variables of variables are not permitted in Java & this is really hard for me to adapt to as a ColdFusion developer. Can you help me think of ways to accomplish this this the proper way in Java?
Here is a simplified version of my code.
import javax.swing.JFrame;
public class MemoryApp
{
public static void main(String args[])
{
//Creates a new game with 3 columns and 4 rows
final CardGame myGame = new CardGame(3, 4);
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI(myGame.getCols(), myGame.getRows());
}
});
}
private static void createAndShowGUI(int c, int r) {
//Create and set up the window.
Window frame = new Window("GridLayoutDemo", c, r);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up the content pane.
frame.addComponentsToPane(frame.getContentPane());
//Display the window.
frame.pack();
frame.setVisible(true);
}
}
Card game class:
public class CardGame
{
private int cols, rows;
public CardGame(int c, int r)
{
cols = c;
rows = r;
}
public int getCols(){
return cols;
}
public int getRows(){
return rows;
}
}
The window with the grid layout:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSeparator;
public class Window extends JFrame
{
private int cols, rows;
GridLayout windowGrid = new GridLayout(1,1);
public Window(String t, int c, int r)
{
super(t);
cols = c;
rows = r;
windowGrid.setColumns(c);
windowGrid.setRows(r);
}
public void addComponentsToPane(final Container pane)
{
final JPanel compsToExperiment = new JPanel();
compsToExperiment.setLayout(windowGrid);
JPanel controls = new JPanel();
controls.setLayout(new GridLayout(cols,rows));
int countCard = (cols * rows) / 2;
/**
* Add buttons to experiment with Grid Layout.
* This is where I'd like to be able to loop through
* countCard and create the required number of buttons
* as well as put images on the buttons like so:
*
* ImageIcon image1 = new ImageIcon(getClass().getResource("card1.png"));
* through
* ImageIcon image1 = new ImageIcon(getClass().getResource("card" & cardCount & ".png"));
*
* Below is how I would attempt this in ColdFusion- I know
* the variable of variables syntax is invalid, it is just
* to show you what I mean.
*/
// for(int i = 0; i < countCard; i++;)
// {
// compsToExperiment.add(new JButton("../img/card" & i & ".png"));
// ImageIcon variables["image" & i] = new ImageIcon(getClass().getResource("card" & i & ".png"));
// imageButton.setIcon(variables["image" & i]);
// etc. with ButtonClickEventHandler, haven't gotten that far yet
// }
pane.add(compsToExperiment, BorderLayout.NORTH);
pane.add(new JSeparator(), BorderLayout.CENTER);
}
}
Based on the code commented-out code that you posted so far, one approach could be like this:
public class Window extends JFrame
{
...
// A java.util.List that stores all the buttons, so
// that their icons may be changed later
private List<JButton> buttons = new ArrayList<JButton>();
// A java.util.List that stores all the ImageIcons that
// may be placed on the buttons
private List<ImageIcon> imageIcons = new ArrayList<ImageIcon>();
public void addComponentsToPane(final Container pane)
{
...
for(int i = 0; i < countCard; i++;)
{
// String concatenation is done with "+" in Java, not with "&"
String fileName = "card" + i + ".png";
// Create the icon and the button containing the icon
ImageIcon imageIcon = new ImageIcon(getClass().getResource(fileName));
JButton button = new JButton(imageIcon);
// Add the button to the main panel
compsToExperiment.add(button);
// Store the button and the icon in the lists
// for later retrieval
imageIcons.add(imageIcon);
buttons.add(button);
// Attach an ActionListener to the button that will
// be informed when the button was clicked.
button.addActionListener(createActionListener(i));
}
}
private ActionListener createActionListener(final int cardIndex)
{
return new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
clickedCardButton(cardIndex);
}
};
}
private void clickedCardButton(int cardIndex)
{
System.out.println("Pressed button for card "+cardIndex);
// Here you can change the icons of the buttons or so...
JButton button = buttons.get(cardIndex);
ImageIcon imageIcon = imageIcons.get(cardIndex);
....
}
You mentioned that this is your first attempt to build a GUI with Java. So I assume that this is only intended for "practicing". If your intention was to build a "real application", you should rather consider some Model-View-Controller (MVC) approach for this.