Java: Finding object reference while inside method - java

I am currently trying to set up a Tic Tac Toe GUI grid with 3x3 buttons, which change the button icon to a nought or cross whenever pressed.
I have set up an array of JButtons and have added a listener to check whenever the button is pressed.
My problem is getting access to the Button object inside the array, I have had to add a parameter to my custom listener constructor to save the button object reference for when I want to change it. It works as is, but doesn't feel very elegant. Is there a way to find the correct JButton object in buttons while inside actionPerformed, or is there a better way to do this altogether?
Thanks in advance
class BigPanel
{
public JPanel bigPanel= new JPanel(new GridLayout(3,3));
public JButton[][] buttons = new JButton[3][3];
public BigPanel()
{
for (int i=0; i<3; i++)
{
for (int j=0; j<3; j++)
{
buttons[i][j] = new JButton();
buttons[i][j].setPreferredSize(new Dimension(75,75));
// Line of interest, adding the listener
buttons[i][j].addActionListener(new CustomActionListener(buttons[i][j]));
bigPanel.add(buttons[i][j]);
}
}
}
}
class CustomActionListener implements ActionListener
{
public int a;
public int b;
public JButton button;
CustomActionListener(JButton a)
{
button = a;
}
public void actionPerformed(ActionEvent e)
{
changeButton(a, b, CurrPlayer.CROSSES);
}
public void changeButton(int a, int b, CurrPlayer player)
{
if (player == CurrPlayer.NOUGHTS)
{
Icon icon = new ImageIcon("Nought.jpg");
button.setIcon(icon);
}
else
{
Icon icon = new ImageIcon("Cross.jpg");
button.setIcon(icon);
}
}
}

Change your CustomActionListener to following will solve this problem
class CustomActionListener implements ActionListener {
public int a;
public int b;
CustomActionListener()
{
}
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton) e.getSource();
changeButton(a, b, CurrPlayer.CROSSES, button);
}
public void changeButton(int a, int b, CurrPlayer player, JButton button)
{
if (player == CurrPlayer.NOUGHTS)
{
Icon icon = new ImageIcon("Nought.jpg");
button.setIcon(icon);
}
else
{
Icon icon = new ImageIcon("Cross.jpg");
button.setIcon(icon);
}
}
}
You can get JButton reference using actionEvent.getSource() method.
And add action listener to buttons as below
buttons[i][j].addActionListener(new CustomActionListener());
Hope this'll help you.

Related

Java game involving adjacent JButtons

I'm making a small game involving a grid of JButtons (MxN) and the main premise is to click on buttonA and then on buttonB, coloring buttonB and adjacent buttons of the same color as buttonB with the color of buttonA. I have made it so you are able to choose 3 possible difficulties. The colors are randomly generated. The main problem is getting the colors to change.
This is the method that I call after selecting the difficulty of the game:
public static void gameMechanics(int m, int n) {
final String[] pickedColour = {""};
final String[] placedColour = {""};
JButton[][] picked = new JButton[m][n];
JButton[][] placed = new JButton[m][n];
picked[m][n].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pickedColour[0] = picked[m][n].getText();
}
});
placed[m][n].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
placedColour[0] = placed[m][n].getText();
}
});
if (pickedColour[0] == "R" && placedColour[0] != "R") {
placed[m][n].setBackground(Color.RED);
placed[m][n].setText("R");
}
else if (pickedColour[0] == "G" && placedColour[0] != "G") {
placed[m][n].setBackground(Color.GREEN);
placed[m][n].setText("G");
}
else if (pickedColour[0] == "B" && placedColour[0] != "B") {
placed[m][n].setBackground(Color.BLUE);
placed[m][n].setText("B");
}
}
I would consider using JPanels and painting them, using a MouseListener instead.
However, if you're set on using JButtons, try this:
button.setBackground(Color.GREEN);
button.setOpaque(true);
Note that this might not work if you're setting the look and feel using UIManager.
Also, you're doing a ton of extra work to map the color to the button - it could get confusing and cause errors down the road. Instead, you might try creating your own class:
class ColoredButton extends JButton {
private static final long serialVersionUID = 3040767030924461426L;
private Color color;
public ColoredButton(Color c) {
this.color = c;
this.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
changeColor();
}
});
}
public void changeColor() {
this.setBackground(this.color);
this.setOpaque(true);
}
}
Now, you can construct a new ColoredButton:
// Now, this button will turn green when clicked
ColoredButton temp = new ColoredButton(Color.GREEN);

Java: Array of Buttons - get the source

Suppose I have an array of buttons
private JButton[] myButtons = new JButton[5];
for (int i=0; i<5; i++)
{
myButtons[i] = new JButton(Integer.toString(i));
myButtons[i].setSize(50, 50);
panel.add(myButtons[i]);
}
How can I add a listener to these buttons so that when I click on one of them, I know at which array position index it is at?
You kind of don't care, start by adding an ActionListener to the buttons
myButtons[i].addActionListener(this); // Or some other ActionListener
In the actionPeformed method, you can look up which button it is using the ActionEvent#getSource
#Override
public void actionPerformed(ActionEvent evt) {
for (JButton btn : myButtons) {
if (btn.equals(evt.getSource()) {
// Do what ever you need
break;
}
}
}
You can also use the actionCommand property of the JButton
for (int i=0; i<5; i++)
{
myButtons[i] = new JButton(Integer.toString(i));
myButtons[i].setActionCommand("button " + i);
myButtons[i].addActionListener(this);
panel.add(myButtons[i]);
}
And when actionPeformed is called, use ActionEvent#getActionCommand to figure out which button was pressed.
A better idea might be to create a dedicated ActionListener for each button...
public class ButtonActionHandler implements ActionListener {
private final JButton button;
public ButtonActionHandler(JButton button) {
this.button = button;
}
public void actionPerformed(ActionEvent evt) {
// Do what ever you need to do with the button...
}
}
for (int i=0; i<5; i++)
{
myButtons[i] = new JButton(Integer.toString(i));
myButtons[i].addActionListener(new ButtonActionHandler(myButtons[i]));
panel.add(myButtons[i]);
}
Another idea would be to make use of the Action API which would allow you to define a self contained entity which was capable of configuring the button and handling the associated action event by itself. See How to Use Actions for more details
But which you might use will come down to why you need to identify the buttons in the first place.
You can add listener in loop, like below if you implement ActionListener interface with class. For example,
class TestGUI extends JPanel implements ActionListener{
public TestGUI(){
for(int i=0; i< 5; i++){
....
myButtons[i].addActionListener(this);
}
}
or, if you have separate Listener class or method.
myButtons[i].addActionListener(new MyListener());
Than at actionPerformed method you can check with button is clicked,
public void actionPerformed(ActionEvent e){
if("0".equals(e.getActionCommand())){
System.out.println("First button is clicked");
}
... so on
}

How To Create JPanels at runtime and show its name when user click on it

I am creating Chess game , for this i am creating 64 JPanels using Loop. and changing background color, here is the example code that i am using to create panel and changing its background color.
for(int i=0;i<8;i++)
{
for( int j=0;j<8;j++)
{
jp[i][j]=new JPanel();
p.add(jp[i][j]);
this.allSquares.add(jp[i][j]); // adding panel in arraylist of type Jpanel
if(j%2==0&&i%2==0)// code to change background color of panels for chess board
{
jp[i][j].setBackground(Color.DARK_GRAY);
}
if(j%2!=0&&i%2!=0)
{
jp[i][j].setBackground(Color.DARK_GRAY);
}
}
}
i need code to get name of the JPanel when user click on it in chess board
extend JPanel and add a name property that you want to save and read
class MyPanel extends JPanel {
public final int i;
public final int j;
public MyPanel(int i,int j){
super();
this.i = i;
this.j = j;
}
}
and
for(int i=0;i<8;i++)
{
for( int j=0;j<8;j++)
{
jp[i][j]=new MyJPanel(i,j);
p.add(jp[i][j]);
jp[i][j].addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
MyPanel p = (MyPanel)e.getSource();
// p.i p.j
}
});
this.allSquares.add(jp[i][j]); // adding panel in arraylist of type Jpanel
if(j%2==0&&i%2==0)// code to change background color of panels for chess board
{
jp[i][j].setBackground(Color.DARK_GRAY);
}
if(j%2!=0&&i%2!=0)
{
jp[i][j].setBackground(Color.DARK_GRAY);
}
}
}
and on click listener, cast panel to MyPanel
MyPanel p = (MyPanel)object;
String name = p.name;

How do I make an ImageIcon (or any kind of image really) visible without a JButton?

I'm working on a minesweeper game and I want to make the bomb (or in this case a panda image I created) to show up under the game space when it's pressed. At this point I just want to make it show up under every single space, I know how to do the randomizing of where it shows up after that, the problem is making it show up.
Right now the parts of my code that apply to this topic are in 2 different classes:
1st class
public class MSBoard extends JPanel implements ActionListener
{
int x = 8;
int y = 8;
public GridLayout gl = new GridLayout(x,y,0,0);
public MSBoxes boxarray[][] = new MSBoxes[x][y];
MSBoard()
{
super();
setLayout(gl);
for(int i=0;i<x;i++)
for (int j=0;j<y;j++)
{
boxarray[i][j] = new MSBoxes();
add(boxarray[i][j]);
}
}
public void actionPerformed(ActionEvent ae){}
}
2nd one
public class MSBoxes extends JPanel implements ActionListener
{
public JButton b1;
ImageIcon panda;
MSBoxes()
{
super();
panda = new ImageIcon("panda.gif");
b1 = new JButton();
add(b1);
b1.addActionListener(this);
b1.setVisible(true);
}
public void actionPerformed(ActionEvent ae)
{
if(b1 == ae.getSource())
{
b1.setVisible(false);
}
}
}
use JToggleButton for Minesweeper game
use putClientProperty
use ItemListener for JToggleButton

Simple ActionListener within a 2D array of JButtons

Okay so I am making a 2d array of JToggleButtons. I got the action listener up and going, but I have no way to tell which button is which.
If I click one, all it returns is something like
javax.swing.JToggleButton[,59,58,19x14,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.BorderUIResource$CompoundBorderUIResource#53343ed0,flags=296,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14],paintBorder=true,paintFocus=true,pressedIcon=,rolloverEnabled=false,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=]
Is there anyway to stick some sort of item or number in the button object to associate each button?
And then when the button is clicked I can retrieve that item or number that was given to it?
Here is my button generator code. (How could I make "int l" associate (and count) to each button made, when it is called, it will return that number, or something along those lines.
JToggleButton buttons[][] = new JToggleButton[row][col];
int l = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
buttons[i][j] = new JToggleButton("");
buttons[i][j].setSize(15,15);
buttons[i][j].addActionListener(new e());
panel.add(buttons[i][j]);
l++;
}
}
ActionListner
public class e implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
System.out.println(source);
}
}
variable "source" is what I use to get my data, so how can int l, be returned through "source" (as its unique value for the unique button clicked) as a button is clicked?
Thanks,
-Austin
very simple way is add ClientProperty to the JComponent, add to your definition into loop e.g.
buttons[i][j].putClientProperty("column", i);
buttons[i][j].putClientProperty("row", j);
buttons[i][j].addActionListener(new MyActionListener());
rename e to the MyActionListener and change its contents
public class MyActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JToggleButton btn = (JToggleButton) e.getSource();
System.out.println("clicked column " + btn.getClientProperty("column")
+ ", row " + btn.getClientProperty("row"));
}
EDIT:
for MinerCraft clone isn't required to implements ony of Listeners, there is only about Icon, find out that in this code (don't implement any of Listeners anf remove used ItemListener)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonsIcon extends JFrame {
private static final long serialVersionUID = 1L;
private Icon errorIcon = UIManager.getIcon("OptionPane.errorIcon");
private Icon infoIcon = UIManager.getIcon("OptionPane.informationIcon");
private Icon warnIcon = UIManager.getIcon("OptionPane.warningIcon");
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ButtonsIcon t = new ButtonsIcon();
}
});
}
public ButtonsIcon() {
setLayout(new GridLayout(2, 2, 4, 4));
JButton button = new JButton();
button.setBorderPainted(false);
button.setBorder(null);
button.setFocusable(false);
button.setMargin(new Insets(0, 0, 0, 0));
button.setContentAreaFilled(false);
button.setIcon((errorIcon));
button.setRolloverIcon((infoIcon));
button.setPressedIcon(warnIcon);
button.setDisabledIcon(warnIcon);
add(button);
JButton button1 = new JButton();
button1.setBorderPainted(false);
button1.setBorder(null);
button1.setFocusable(false);
button1.setMargin(new Insets(0, 0, 0, 0));
button1.setContentAreaFilled(false);
button1.setIcon((errorIcon));
button1.setRolloverIcon((infoIcon));
button1.setPressedIcon(warnIcon);
button1.setDisabledIcon(warnIcon);
add(button1);
button1.setEnabled(false);
final JToggleButton toggleButton = new JToggleButton();
toggleButton.setIcon((errorIcon));
toggleButton.setRolloverIcon((infoIcon));
toggleButton.setPressedIcon(warnIcon);
toggleButton.setDisabledIcon(warnIcon);
toggleButton.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (toggleButton.isSelected()) {
} else {
}
}
});
add(toggleButton);
final JToggleButton toggleButton1 = new JToggleButton();
toggleButton1.setIcon((errorIcon));
toggleButton1.setRolloverIcon((infoIcon));
toggleButton1.setPressedIcon(warnIcon);
toggleButton1.setDisabledIcon(warnIcon);
toggleButton1.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (toggleButton1.isSelected()) {
} else {
}
}
});
add(toggleButton1);
toggleButton1.setEnabled(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
}
Just add the row and column data to each listener. You could add an explicit constructor, but I suggest adding a little method (which may have more added to it later).
buttons[i][j].addActionListener(e(i, j));
...
private ActionListener e(final int i, final int j) {
return new ActionListener() {
// i and j available here
...
(In JDK8 you should be able to use a lambda to reduce the syntax clutter.)
And then renaming it with a better name.
I made a minesweeper game and ran into a similar problem. One of the only ways you can do it, is to get the absolute location of the clicked button, then divide that by the x and y between buttons, so for me it was
if ((e.getComponent().getX() != (randx) * 25 && e.getComponent().getY() != (randy) * 25) &&bomb[randx][randy] == false) {
This code was to check if the area had bombs. So I had 25 x and y difference between location of bombs. That will just give you a general idea on how to do this.
I believe: (x - x spacing on left side) / buffer - 1 would work.
Instead of 'e.getSource()' you can always call 'e.getActionCommand()'. For each button you can specify this by:
JButton button = new JButton("Specify your parameters here"); /*you get these from getActionCommand*/
button.setText("title here"); /*as far as I remember*/

Categories

Resources