i am making a memory game using java swing. so far i have made a class that returns custom JButtons with an image already in them (unfliped). in the main class i am creating objects of that class and add them to the panel. everything works but when i am adding the action listeners the getSource method returns a JButton and as a result i cant use the methods from inside the custom buttons class. How can i use getSource and create a button from the custom buttons class?
i have tried casting the button returned from the getSource method to Buttons(custom buttons class) but it didnt work.
public class Buttons extends JButton{
int id;
JButton butt;
private static int x=0;
public Buttons() throws IOException{
butt=this.retButton();
}
public JButton retButton() throws IOException{
BufferedImage img =
ImageIO.read(getClass().getResourceAsStream("/folder/flipped.png"));
ImageIcon image = new ImageIcon(img);
JButton button = new JButton();
button.setName(Integer.toString(x));
button.setIcon(image);
button.setBackground(Color.white);
x+=1;
return button;
}
public JButton getButton(){
return this.butt;
}
public int getId() {
return id;
}
}
in the main class i am using:
for (int i=0; i<12; i++){
jb[i] = new Buttons();
jb[i].getButton().addActionListener(this);
jb[i].setId(cardNums.get(i));
panel.add(jb[i].getButton());
}
frame.add(panel, BorderLayout.CENTER);
frame.pack();
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof JButton) {
JButton btn = (JButton)source;
System.out.println("hey");}
action listener works but since btn is a JButton it wont let me use the getId method of the Buttons class.
Why do you want your Buttons instance to have a separate button as an attribute? You already ARE a button. This seems like a poor design choice.
That said, since you set the button name to be the creation index,you could just use source.getName() and convert it back to an int, then use that int as an index for the jb array.
Related
This program is just for the sake of teaching myself Java.
While coding around i ran into the following problem:
I'm getting errors (red underlining) when using a listener for a button which I implement in my Main class.
Since I'm new in learning Java please excuse if the solution is obvious.I already tried making both the main and the actionPerfomed method abstract but that lead to further issues. I also tried #Override before the actionPerformed method.
Here is the code:
// Java program to create a blank text
// field of definite number of columns.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Main extends JFrame implements ActionListener {
// JTextField
static JTextField t;
// JFrame
static JFrame f;
// JButton
static JButton b;
// label to diaplay text
static JLabel l;
// default constructor
Main()
{
}
// main class
public static void main(String[] args)
{
// create a new frame to stor text field and button
f = new JFrame("textfield");
// create a label to display text
l = new JLabel("nothing entered");
// create a new button
b = new JButton("submit");
// create a object of the text class
Main te = new Main();
// addActionListener to button
b.addActionListener(te);
// create a object of JTextField with 16 columns
t = new JTextField(16);
// create a panel to add buttons and textfield
JPanel p = new JPanel();
// add buttons and textfield to panel
p.add(t);
p.add(b);
p.add(l);
l.setOpaque(true);
// add panel to frame
f.add(p);
// set the size of frame
f.setSize(300, 300);
p.setBackground(Color.cyan);
f.show();
}
// if the button is pressed
public void actionPerformed(java.awt.event.ActionEvent e, JPanel p)
{
String s = e.getActionCommand();
if (s.equals("submit")) {
// set the text of the label to the text of the field
if(t.getText().equals("hue")) {
p.setBackground(changeColor());
}
l.setText(t.getText());
// set the text of field to blank
t.setText(" ");
}
}
public Color changeColor() {
int r = (int)(Math.random())*256;
int g = (int)(Math.random())*256;
int b = (int)(Math.random())*256;
Color color = new Color(r,g,b);
return color;
}
}
Here:
public void actionPerformed(java.awt.event.ActionEvent e, JPanel p)
Should be
public void actionPerformed(java.awt.event.ActionEvent e)
You have to match the expected signature exactly! You can't just add more parameters to a method you are supposed to override!
You see, in the end, it is not your code that will invoke that method when a button is clicked. It is the Swing framework that will do it. You tell it: when an action happens on this thing, then call back my code. How do you expect that this framework could know that you want an additional parameter to be passed?!
Beyond that: make it your practice to put #Override in front of any method that you expect to override a method (like in this case, where you are implementing a method of that interface). Because then the compiler can tell you when you make such mistakes!
But of course, you added that parameter so that the listener can use it. So: make it known to the listener, for example by adding a field to your Main class that you initialize in the constructor! So instead of passing the panel to that one method (where it can't go) pass it when doing new for your Main instance.
When a class implements an interface, then it has to implement the required functions with the same arguments as given in the Interface.
ActionListener implements only only one function as you can see at https://docs.oracle.com/javase/7/docs/api/java/awt/event/ActionListener.html
void actionPerformed(ActionEvent e);
So you have to implement that function in your class. But you implemented a different function which has the same name but not the same arguments:
void actionPerformed(java.awt.event.ActionEvent e, JPanel p)
Im looking to change an Icon when I click a Jbutton. I have button1 rigged up to an action command that prints "On" or "Off". I would like to have the button change icons from an image of an circle meaning off, to an image of a power button meaning on. I've tried many things but haven't been able to find a solution so Im wondering if there is an easy way to do this or if there isn't an easy way, and ill have to make a more complex way for each button. Any advice is greatly appreciated because Im at a dead end. Fell free to edit large blocks or add things because Im open to all ideas. The code is included below
import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.awt.event.*;
public class OnandOff{
public static void main(String[] a){
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new ButtonDemo());
f.setSize(600,500);
f.setVisible(true);
}
}
class ButtonDemo extends JPanel implements ActionListener {
JTextField jtf;
public ButtonDemo() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
makeGUI();
}
});
} catch (Exception exc) {
System.out.println("Can't create because of " + exc);
}
}
private void makeGUI() {
setLayout(new FlowLayout());
//sets up icons
ImageIcon OnIcon = new ImageIcon(" On.jpg");
Icon OffIcon = new ImageIcon("Off.jpg");
ImageIcon BlankIcon = new ImageIcon("Blank.jpg");
//creates jbuttons with Action command
ImageIcon button1 = new ImageIcon("Off.jpg");
JButton jb = new JButton(button1);
jb.setActionCommand("On");
jb.addActionListener(this);
add(jb);
ImageIcon button2 = new ImageIcon("Off.jpg");
jb = new JButton(button2);
add(jb);
ImageIcon button3 = new ImageIcon("Off.jpg");
jb = new JButton(button3);
add(jb);
ImageIcon button4 = new ImageIcon("Off.jpg");
jb = new JButton(button4);
add(jb);
}
#Override
//prints on and off when detecting action comand from a jbutton
public void actionPerformed(ActionEvent ae) {
String action = ae.getActionCommand();
if (action.equals("On")) {
System.out.println("Yes Button pressed!");
ImageIcon button1 = new ImageIcon("On.jpg");
TicTacToe.a = 1;
}
else if (action.equals("Off")) {
System.out.println("No Button pressed!");
}
}
You're forgetting to call setIcon(...) on any button. As the AbstractButton API will tell you (this is the parent class of JButton), it is easy to change the icon of any button by simply calling its setIcon(Icon icon) method and pass in the new Icon. In the future, first go to the API as you'll learn much there, including methods that do exactly what you need.
Other suggestions: don't give your variables names that don't match what they are. For instance you're calling an ImageIcon variable "button1" as if it were a JButton, and that will confuse other coders and your future self. Instead why not call it `onIcon" or "offIcon", a name that makes the code self-commenting.
A major problem with your code, and one reason why as written, you can't make it work -- your JButton objects are assigned to local variables, variables that are only visible within the method that they were declared. If you want your JButton objects to be able to have there icons changed in different methods of the class, they must be declared at the class level, not at the method or constructor or deeper level.
I'm programming Java with NetBeans. I have a strange problem. In a class Mouse Listener, I do getComponents of a panel, and it returns a array of components that I put(?) in one array JButton (whit cast) so..
JButton[] b= (JButton[])Main.p1.getComponents();
IDE doesn't show an error.
I do, for example:
b[0].setBackground(Color.yellow);
and in output I see an error.
But if I do
JButton b= (JButton) Main.p1.getComponents()[0];
b.setBackground(...);
And all works but I don't understand why. Can somebody explain please?
2015-01-18
Thank to all for the answer.
I want take Components of a Panel, not only for change background's color, but also for the Ordinates; I need all Buttons in a array to compare all at the same time .. Why I cant convert 'Components' in 'Buttons'? Panel has a pointer to Buttons in Ram Memory..
Patryk Dobrowolski thank's you, i try this: (i use class Button extends JButton)
Button[] button = new Button[Main.p1.getComponents().length];
for (int i = 0; i < Main.p1.getComponents().length; i++) {
button[i] = (Button) Main.p1.getComponents()[i];
}
but in output I see this error:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.JLabel cannot be cast to Button
why JLabel?
Hovercraft Full Of Eels, thank's you for your answer, I could create an array and insert the pointer of all Button into it. But I said: JPannel has a Array where insert pointer.. I can use it. Why not?
Thank's you very much!
Alessandro Amedei
In the first case, you are lying to the compiler. By stating
JButton[] b= (JButton[])Main.p1.getComponents();
you are telling the compiler that you know that this is an array of JButtons, when in fact it really is an array of Components. Therefore you get no compile-time errors, but you do get one at runtime.
In the other case it works, since then you are telling the compiler that the Component you want to work with is a JButton, which is true.
It's because array of JComponent is not the same as array of JButton. You need to cast one by one in the loop if you want to finally get array of buttons:
JButton[] buttons = new JButton[components.length];
for (int i = 0; i < components.length; i++) {
buttons[i] = (JButton) components[i];
}
I am concerned that you are trying to extract your selected JButton by iterating through an array of components and thereby basing your program logic on the GUI component structure, which is a very fragile way to do things. If you change components around, or later decide to nest a container that holds your JButtons into another container (i.e., into another JPanel), you would have to take care to update this listener and all similar listeners, again making your code quite fragile.
Rather than do this, a better solution might be to add a listener to the individual components that need them. For instance, if you want to change the background of a JButton to yellow if a mouse is hovering over it, consider adding a ChangeListener to each JButton, extracting the involved button via the ChangeEvent's getSource() method and then testing the button's model to see if it is in a roll-over state. For example:
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
#SuppressWarnings("serial")
public class SetButtonBackground extends JPanel {
public static final Color ROLLOVER_COLOR = Color.yellow;
public SetButtonBackground() {
int rows = 5;
int cols = rows;
setLayout(new GridLayout(rows, cols, 5, 5));
ButtonChangeListener btnChngListener = new ButtonChangeListener();
for (int i = 0; i < rows * cols; i++) {
String text = "Button " + (i + 1);
JButton button = new JButton(text);
button.addChangeListener(btnChngListener);
add(button);
}
}
private class ButtonChangeListener implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
JButton btn = (JButton) e.getSource();
ButtonModel model = btn.getModel();
if (model.isRollover()) {
if (!btn.getBackground().equals(ROLLOVER_COLOR)) {
btn.setBackground(ROLLOVER_COLOR);
}
} else if (btn.getBackground().equals(ROLLOVER_COLOR)) {
btn.setBackground(null); // change back to default state
}
}
}
private static void createAndShowGui() {
SetButtonBackground mainPanel = new SetButtonBackground();
JFrame frame = new JFrame("Set Button Background");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Similar questions to my own have been asked, but I'm at a bit of a loss as to how to proceed. I really have a poor grasp of some of the more subtle nuances of java, so I apologize if anything isn't clear.
Say for example I wanted to compare one JButton within a 2D array with another. To be more specific, all of these JButton's would be stores within a 2D array and displayed in grid format. All of the buttons would have the same action listener that, upon the button being pressed, calls the setselected() method.
How would I go about comparing one of these selected JButton's with another selected JButton within the same array? And upon doing so, how could I swap the positions or more specifically, the icons of said buttons.
Below, I've included some example code and my own attempt on the subject. I understand that I can use .getSource() to grab a JButton object itself, but would this not only allow me to capture 1 selected button at a time. This is all considering the use of the same actionlistner code for each button, but a secular listener for each button.
The code below sets every icon to 1 of 7 randomly generated image icons. A frame is generated within secular main class. Upon being pressed or "selected" the image icons change to a selected iteration of the same image.
EDIT: Based on Ameer's suggestion, I've run into several nullpointer exceptions that are caused by my actionPerformed method. Is this as a result to my button array not being filled with button objects at this point, or am I simply presuming something within my code?
public class SButtonGame extends JFrame implements ActionListener {
public static ImageIcon[] icons={
new ImageIcon("img1.png"),
new ImageIcon("img2.png"),
new ImageIcon("img3.png"),
new ImageIcon("img4.png"),
new ImageIcon("img5.png"),
new ImageIcon("img6.png"),
new ImageIcon("img7.png"),
};
public static ImageIcon[] selectedIcons={
new ImageIcon("simg1.png"),
new ImageIcon("simg2.png"),
new ImageIcon("simg3.png"),
new ImageIcon("simg4.png"),
new ImageIcon("simg5.png"),
new ImageIcon("simg6.png"),
new ImageIcon("simg7.png"),
};
int rowNum=0;
int colNum=0;
JButton[][] Buttons;
boolean swaptf=false;
JButton CButton; // Selected button "holder". Doesn't accomplish anything I think it should
public SButtonGame(String title) {
//Constructs frame
super(title);
getContentPane().setLayout(null)
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(578,634);
int colLoc=10;
int rowLoc=10;
this.colNum=0;
this.rowNum=0;
for(int r=0; r<8; r++)
{
this.Buttons= new JButton[9][9];
this.rowNum++;
for(int c=0; c<8; c++)
{
ActionListener listner = new ActionListener(){
public void actionPerformed(ActionEvent e)
{
if(e.getSource() instanceof JButton)
{
((JButton) e.getSource()).setSelected(true);
CButton=(JButton)e.getSource();
}
}
};
int ranImg;
ranImg=0+(int)(Math.random()*7);
int sranImg=ranImg;
this.Buttons[this.colNum][this.rowNum]= new JButton(icons[ranImg]);
this.Buttons[this.colNum][this.rowNum].setSelectedIcon(selectedIcons[sranImg]);
this.Buttons[this.colNum][this.rowNum].addActionListener(listner);
this.Buttons[this.colNum][this.rowNum].setSize(59,59);
this.Buttons[this.colNum][this.rowNum].setLocation(rowLoc,colLoc);
rowLoc=rowLoc+69;
this.Buttons[this.colNum][this.rowNum].setVisible(true);
this.Buttons[this.colNum] [this.rowNum].setBorder(BorderFactory.createLineBorder(Color.black));
add(this.Buttons[this.colNum][this.rowNum]);
}
this.colNum++;
colLoc=colLoc+69;
rowLoc=10;
}
JButton Newgame;
Newgame= new JButton("NewGame");
Newgame.setSize(100, 30);
Newgame.setLocation(350, 560);
Newgame.setVisible(true);
add(Newgame);
JButton Quit;
Quit= new JButton("Quit");
Quit.setSize(60, 30);
Quit.setLocation(480, 560);
Quit.setVisible(true);
add(Quit);
New.addActionListener(new ActionListener()
{
//dispose of current frame and generates a new one;
public void actionPerformed(ActionEvent e)
{
dispose();
SButtonGame Frame;
Frame = new SButtonGame("ShinyButtons");
Frame.setVisible(true);
}
});
Quit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
dispose();
}
});
}
#Override
public void actionPerformed(ActionEvent ae){
if(ae.getSource() instanceof JButton){
JButton sButton;
int rindex=0;
int cindex=0;
((JButton) ae.getSource()).setSelected(true);
sButton=(JButton)ae.getSource();
if(SButtonGame.this.Buttons[(int)sButton.getClientProperty("rownum")][(int)sButton.getClientProperty("colnum")].isEnabled()==true){
}
}
}
public static void main(String[] args)
{
SButtonGame Frame;
Frame = new SButtonGame("ButtonsGame");
Frame.setVisible(true);
}
}
Inside actionPerformed(ActionEvent e) method, you can access the 2D array of buttons by using SButtonGame.this.Buttons (ideally variable name should be buttons starting with small b).
You can then compare the clicked button with the buttons from array and do rest of your stuff.
I have a various panels with various buttons. Some buttons should call a method initiating a search through an array list, other buttons should call methods that send information to different JTextArea boxes.
After adding an event listener for each button, how do I create specific actions depending on the button clicked in my actionPerformed method? Below is my code for various gui properties, as you can see there are 3 different JPanels, the buttons of each needing to perform different functions. I just need to know how to determine which button was clicked so I can link it to the appropriate method (already written in another class). Does this require an if statement? Can my other class access the buttons on the GUI if I make them public, or is there a more efficient way to do this.
JPanel foodOptions;
JButton[] button= new JButton[4]; //buttons to send selected object to info panel
static JComboBox[] box= new JComboBox[4];
JPanel search;
JLabel searchL ;
JTextField foodSearch;
JButton startSearch; //button to initialize search for typed food name
JTextArea searchInfo;
JPanel foodProfile;
JLabel foodLabel;
JTextArea foodInfo;
JButton addFood; //but to add food to consumed calories list
JPanel currentStatus;
JLabel foodsEaten;
JComboBox foodsToday;
JLabel calories;
JTextArea totalKCal;
JButton clearInfo; //button to clear food history
As per people's comments, you need to use listeners of some sort, here is a real basic example to get you started, however I would define your listeners elsewhere in most cases, rather than on the fly:
JButton startSearch = new JButton("startSearch");
JButton addFood = new JButton("addFood");
startSearch.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
//DO SEARCH RELATED THINGS
}
});
addFood.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//DO FOOD ADD RELATED THINGS
}
});
Something like this:
JButton searchButton = new JButton("Start search");
searchButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do some search here
}
});
JButton addFoodButton= new JButton("Add food");
addFoodButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// add your food
}
});
and so on. If you need to reuse an behaviour through multiple buttons, create a ActionListener instance instead of using anonymous classes and assign it multiple times to your buttons.
Well there any many ways to do that I guess. I suppose you can do the following:
public class Myclass implements ActionListener
{
private JButton b1,b2;
private MyClassWithMethods m = new MyClassWithMethods();
// now for example b1
b1 = new JButton("some action");
b1.setActionCommand("action1");
b1.addActionListener(this);
public void actionPerformed(ActionEvent e) {
if ("action1".equals(e.getActionCommand()))
{
m.callMethod1();
} else {
// handle other actions here
}
}
}
And you can do the same for more buttons and test which action triggered the event and then call the appropriate methods from you class.