I am writing a GUI program in Java. The GUI consists of 9 buttons titled H. In run mode, when the mouse clicks on any button, that button should change the heading to T. I have a MouseListener code watching out for the clicks. But I have no way of finding out based on the mouse clicks that I need to change that particular button. Any help is appreciated.
Below is my code.
package flippingcoins;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class FlippingCoins extends JFrame
{
public FlippingCoins()
{
JPanel p = new JPanel();
p.setLayout(new GridLayout(3,3,1,1));
JButton jbt1=new JButton("H");
p.add(jbt1);
JButton jbt2=new JButton("H");
p.add(jbt2);
JButton jbt3=new JButton("H");
p.add(jbt3);
JButton jbt4=new JButton("H");
p.add(jbt4);
JButton jbt5=new JButton("H");
p.add(jbt5);
JButton jbt6=new JButton("H");
p.add(jbt6);
JButton jbt7=new JButton("H");
p.add(jbt7);
JButton jbt8=new JButton("H");
p.add(jbt8);
JButton jbt9=new JButton("H");
p.add(jbt9);
add(p);
}
public static void main(String[] args) //Main program begins here.
{
FlippingCoins frame = new FlippingCoins();//Instantiating an object.
frame.setTitle("Head or Tails");//Setting the frame title.
frame.setSize(300,300);//Setting the size.
frame.setLocationRelativeTo(null);//Setting the location.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// Default closing options.
frame.setVisible(true);//Setting visibility to true.
}//End of main program.
static class ChangeTiles extends JPanel
{
public ChangeTiles()
{
addMouseListener(new MouseAdapter()//Creating a listener
{
public void mouseClicked(MouseEvent e)//When the mouse is clicked.
{
int x=e.getX();
int y=e.getY();
System.out.println("x= "+ x + "y= "+y);
}
}
);
}
}
That's not the good strategy. Instead, add an ActionListener to every button. Not only will it be much easier, but users will then also be able to use their keyboard to click the buttons.
Also, consider using an array or list of buttons. That will allow using loops instead of copying and pasting the same code 9 times.
public FlippingCoins() {
final JPanel p = new JPanel();
p.setLayout(new GridLayout(3, 3, 1, 1));
for (int i = 0; i < 9; i++) {
final JButton jbt = new JButton("H");
jbt.setName("" + i);
jbt.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
jbt.setText("T");
System.out.println(jbt.getName());
}
});
p.add(jbt);
}
setContentPane(p);
}
Some notes:
use loops for repetitive tasks
listeners have to be added to the widget they should listen to
do not use MouseListeners for JButton, there is ActionListener
Alternative for JLabel:
public FlippingCoins2() {
final JPanel p = new JPanel();
p.setLayout(new GridLayout(3, 3, 1, 1));
for (int i = 0; i < 9; i++) {
final JLabel jlb = new JLabel("H", SwingConstants.CENTER);
jlb.setBorder(BorderFactory.createLineBorder(Color.blue));
jlb.setName("" + i);
jlb.addMouseListener(new MouseAdapter() {
public void mouseClicked(final MouseEvent e) {
jlb.setText("T");
System.out.println(jlb.getName());
}
});
p.add(jlb);
}
setContentPane(p);
}
This is how you should do it:
JButton jbt1=new JButton("H");
jbt1.addActionListener(new ButtonListener());
//add ButtonListener to all of the other buttons
//Somewhere in your code:
public class ButtonListener extends ActionListener {
public void actionPerformed(ActionEvent e) {
JButton source = (JButton) e.getSource();
source.setText("T");
}
}
This will be easy if you add an ActionListener. Inside the actionPerformed code you can make it print out which button was clicked.
getSource()
Returns: The object on which the Event initially occurred.
you can call getSource() on the ActionEvent generated by the ActionPerformed method. I haven't tried this but sounds like you can easily find out which button was clicked.
Related
I have a ArrayList of JPanel. And each items of this list has a JButton.
Now, when JButton is clicked I want to remove its' parent JPanel from the ArrayList. So how can I make the JButton remove its' parent from the ArrayList?
Thanks in advance.
public class TestingArrayList extends JFrame {
JPanel grandPanel; // a JPanel for all the panels
ArrayList<JPanel> panelParent = new ArrayList<>(); // JPanel ArrayList
public TestingArrayList() {
super("Test");
setLayout(new FlowLayout());
grandPanel = new JPanel();
add(grandPanel);
for (int i = 0; i < 10; i++) { // adding 10 JPanel into grandPanel
panelParent.add(new JPanel());
grandPanel.add(panelParent.get(i));
// adding JButton in all panels
JButton btnParent = new JButton("X");
panelParent.get(i).add(btnParent);
// add new task button action
btnParent.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println(getParent());
//What to do!!!
}
});
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1000, 100);
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new TestingArrayList();
}
}
You have all you need right in your code. You just need a final reference to the JPanel of interest as this will allow you to use it within the anonymous inner ActionListener class:
for (int i = 0; i < 10; i++) {
// make it final so that it is accessible from inner anon class
final JPanel myPanel = new JPanel();
panelParent.add(myPanel);
grandPanel.add(myPanel);
JButton btnParent = new JButton("X");
myPanel.add(btnParent);
btnParent.addActionListener(event -> panelParent.remove(myPanel));
}
If you also want to remove it from the grandPanel, then you'll need more...
btnParent.addActionListener(event -> {
panelParent.remove(myPanel);
grandPanel.remove(myPanel);
grandPanel.revalidate();
grandPanel.repaint();
});
Note, that if you wanted to use Seymore's method of removing the JPanel, you first need to understand that the source object obtained by calling getSource() on the ActionEvent parameter is the object that the listener was added to -- here a JButton not a JPanel, and also the type of object returned is Object, and so no Swing component methods can be called on it without casting. And so you would need to wrap all in parenthesis in order to allow you to call methods of that type. For example:
parentPanel.remove((JPanel) ((JButton) event.getSource()).getParent());
or
parentPanel.remove((JPanel) ((JComponent) event.getSource()).getParent());
I find it easier to separate lines when code gets this convoluted:
// since a JButton extends from JComponent
JComponent source = (JComponent) event.getSource();
JPanel parent = (JPanel) source.getParent();
parentPanel.remove(parent);
btnParent.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println(getParent());
panelParent.remove((JPanel)(event.getSource().getParent()));
}
});
I'm looking to recall a JButton's value when clicked i.e. when the user clicks a JButton, the value of that JButton (which is a single letter) will be written to a JLabel. The user will click multiple buttons and as such, multiple values will need to be stored and printed. Finally the user will click a button and the JLabel holding all recieved JButton values will be stored (Obviously using an array).
Here is what my JButton's look like in code:
theModel.randomLetters();
for(int i=0;i<16;i++){
JButton dice = new JButton(theModel.letters.get(i));
dice.addActionListener(disableButtonListener);
boggleGrid.add(dice);
}
theModel.randomLetters(); is a reference to another class with "letters" being an array holding 16 values. Will I need to add each JButton individually to the boggleGrid so their individual names can be recalled to achieve the goal stated above, or do they have individual names and I don't know it? (I've used a for loop someone gave me so I'm not sure if there are individual names for each JButton)
Thanks, and sorry if this is elementary
Read the following code, you'll get some ideas...
I used a StringBuilder to store the values of the Button's each time they were clicked by using StringBuilder.append(JButton.getText().toString()). That was done in the actionPerformed methods of the JButtons.
Then finally in the Done buttons actionPerformed method I had stored the text the string builder held in an array.
P.S. I know you're using 16 JButton's I just used 3 for simplicity...
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.ArrayList;
public class GUI extends JFrame{
ArrayList<String> numbers = new ArrayList<>();
StringBuilder sb = new StringBuilder();
JButton button1;
JButton button2;
JButton button3;
JButton doneButton;
JPanel row1 = new JPanel();
JPanel textLabelRow = new JPanel();
JLabel label = new JLabel();
JPanel row3 = new JPanel();
public void create(){
setTitle("S-O");
setSize(500,200);
setLayout(new GridLayout(3,1,10,10));
button1 = new JButton("1");
button2 = new JButton("2");
button3 = new JButton("3");
doneButton = new JButton("Done");
row1.add(button1);
row1.add(button2);
row1.add(button3);
button1.addActionListener(new Button1Listener());
button2.addActionListener(new Button2Listener());
button3.addActionListener(new Button3Listener());
doneButton.addActionListener(new doneButtonListener());
textLabelRow.add(label);
row3.add(doneButton);
add(row1);
add(textLabelRow);
add(row3);
setVisible(true);
}
private class Button1Listener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
sb.append(button1.getText().toString());
}
}
private class Button2Listener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
sb.append(button2.getText().toString());
}
}
private class Button3Listener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
sb.append(button3.getText().toString());
}
}
private class doneButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
label.setText(sb.toString());
numbers.add(sb.toString());
sb = new StringBuilder();
}
}
public static void main(String[] args){
GUI start = new GUI();
start.create();
}
}
EDIT:
You could just use one class which implements ActionListener opposed to having one for each JButton.
With in the actionPerformed method "public void actionPerformed(ActionEvent ev)"
You would have to ev.getActionCommand(), that would return the text value of the JButton which caused the event. Then you could append that to the StringBuilder.
So something along the lines of this:
private ArrayList listForEdit = new ArrayList<>();
StringBuilder sbEdit = new StringBuilder();
class actionHandler implements ActionListener{
public void actionPerformed(ActionEvent ev){
if(ev.getActionCommand.equals("Done"))
listForEdit.add(sbEdit);
sbEdit = new StringBuilder();
}
else{
sbEdit.append(ev.getActionCommand());
}
}
For example, I am trying to call the setEnable method on a JButton that I constructed within the parameter parenthesis of an add method:
add(new JButton());
I know I could just do something like:
JButton button = new JButton();
button.setEnable(false);
but is there I way I can call setEnable on a JButton that I didn't assign a reference name to?
The reason why I am not assigning the JButton a reference name is because I am supposed to add an unknown number of JButtons to a JPanel. How I am doing this, is by using this for loop.
for (int i = 0; i < numberOfButtonsToAdd; i++)
{
JPanelName.add(new JButton());
}
and I want all the JButtons to be disabled.
You state in comment:
The reason why I am not assigning the JButton a reference name is because I am supposed to add an unknown number of JButtons to a JPanel. How I am doing this, is by using a for loop: for (int i = 0; i < numberOfButtonsToAdd; i++) { JPanelName.add(new JButton()); }
Then just use either an array or ArrayList of JButton.
// in your field declarations
List<JButton> buttonList = new ArrayList<JButton>();
// elsewhere in your program
for (int i = 0; i < numberOfButtonsToAdd; i++) {
JButton button = new JButton();
buttonList.add(button);
somePanel.add(button);
}
Now you have a reference to any button in the list via buttonList.get(someIndex)
Note also, that most buttons are given ActionListeners that are activated whenever the button is pressed. Without such listeners, the buttons are pretty much useless. You can also get a reference to the pressed JButton from the ActionListener via the ActionEvent object passed into its actionPerformed method:
public void actionPerformed(ActionEvent e) {
AbstractButton myButton = (AbstractButton) e.getSource();
// now you can use myButton
}
Note that this is key information that you should have shared with us up front in your original question.
Edit
You state now:
and I want all the JButtons to be disabled.
Then just make them disabled from the get-go:
for (int i = 0; i < numberOfButtonsToAdd; i++) {
JButton button = new JButton();
button.setEnabled(false);
buttonList.add(button);
somePanel.add(button);
}
Although I am curious -- why all disabled? Why no ActionListener? No text?
Edit 2
You state:
Would I still be able to access those individual buttons later on, since they are all assigned "button"?
Please understand that the variable name is of little importance, and in fact, in my example above, the variable named button does not exist outside of the for loop within which it was declared. Instead what matters is the reference to the JButton object. As has been much discussed in the other answers and as you are aware, this can be obtained by using a variable, but it doesn't have to be a variable directly to the JButton, it could, as is in this case, be the variable to the ArrayList<JButton>. That's why I suggest that you create this entity.
Edit 3
for example:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class ButtonLists extends JPanel {
private static final int ROWS = 6;
private static final int COLS = 6;
private List<JButton> allButtons = new ArrayList<JButton>();
private List<JButton> evenButtons = new ArrayList<JButton>();
public ButtonLists() {
JPanel gridPanel = new JPanel(new GridLayout(ROWS, COLS));
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
int buttonInt = i * COLS + j;
String buttonString = String.valueOf(buttonInt);
JButton button = new JButton(buttonString);
button.setEnabled(false);
gridPanel.add(button);
allButtons.add(button);
if (buttonInt % 2 == 0) {
evenButtons.add(button);
}
}
}
JPanel bottomPanel = new JPanel();
bottomPanel.add(new JButton(new AbstractAction("Activate All") {
#Override
public void actionPerformed(ActionEvent e) {
for (JButton btn : allButtons) {
btn.setEnabled(true);
}
}
}));
bottomPanel.add(new JButton(new AbstractAction("Activate Even") {
#Override
public void actionPerformed(ActionEvent e) {
for (JButton btn : allButtons) {
btn.setEnabled(false);
}
for (JButton btn : evenButtons) {
btn.setEnabled(true);
}
}
}));
bottomPanel.add(new JButton(new AbstractAction("Activate Odd") {
#Override
public void actionPerformed(ActionEvent e) {
for (JButton btn : allButtons) {
btn.setEnabled(true);
}
for (JButton btn : evenButtons) {
btn.setEnabled(false);
}
}
}));
setLayout(new BorderLayout());
add(gridPanel, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("ButtonLists");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ButtonLists());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
If you added it to a panel you can get the components of that panel and looping through those components if one is a button you could call setEnabled(), but if there were more than one button you would have to determine if it was the correct one.
Edit:
Since you added that you want all the buttons disabled then this method should work nicely. Examples:
All:
for(Component c : panel.getComponents()){
c.setEnabled(false);
}
Just JButtons:
for(Component c : panel.getComponents()){
if(c instanceof JButton){
((JButton)c).setEnabled(false);
}
}
No, you can't. If setEnabled() returned the object it's enabling, you could enable-and-add the object in a single line. But as it is, setEnabled() returns void, so you have no choice but to use a local variable.
However, a JButton is enabled by default, so there's no need to explicitly call setEnabled() on it, it's already enabled!
You can call a method in a new instance like
new JButton().setEnabled(true);
But this won't allow you to access the JButton instance you create here anymore and thus you cannot call add().
This can only be possible if the method call returns the instance object on which it was called. So if for example setEnabled would return the same instance on which it was called (that is, this in setEnabled context) , you could do add(new JButton().setEnabled(true)).
Anyway in your case don't be afraid of using references:
final JButton button = new JButton();
button.setEnabled(true);
add(button);
Note that in this case 2 last methods can be called in any order, the result will be the same.
The only way this can work is if what ever you are adding it to has a get method. other than that you don't have any other options. Best way is what you showed.
JButton button = new JButton();
button.setEnable(true);
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Concentration extends JFrame implements ActionListener {
private JButton buttons[][]=new JButton[4][4];
int i,j,n;
public Concentration() {
super ("Concentration");
JFrame frame=new JFrame();
setSize(1000,1000);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel=new JPanel(new GridLayout(4,4));
panel.setSize(400, 400);
for( i=0; i<buttons.length; i++){
for (j=0; j<buttons[i].length;j++){
n=i*buttons.length+buttons[i].length;
buttons[i][j]=new JButton();
panel.add(buttons[i][j]);
buttons[i][j].addActionListener(this);
}
}
add(panel);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
buttons[i][j].setIcon(new ImageIcon(
getClass().getResource("/images/2.jpg")));
}
public static void main(String args[]){
new Concentration();
}
}
This is my code. I am making memory game. I want to make that, each time clicked a button, that button shows image but
buttons[i][j].addActionListener(this);
in that, methot can not take i and j and doesnot show any image.
But for example when i do
buttons[2][2].addActionListener(this);
it shows only in 2x2 . image. What can i do to solve that?
Possible solutions:
Inside the ActionListener, iterate through the button array to see which JButton in the array matches the button that was pressed, obtained by calling e.getSource()
Give your JButtons actionCommand Strings that correspond to i and j
Create a separate ActionListener implementing class that has i and j fields that can be set via a constructor, and give each button a unique ActionListener with i and j set.
Try this code:
public void actionPerformed(ActionEvent e) {
if(e.getSource() instanceof JButton){
JButton pressedButton = (JButton) e.getSource();
if(pressedButton.getIcon() == null){
pressedButton.setIcon(new ImageIcon(getClass().getResource("/images/2.jpg")));
} else {
pressedButton.setIcon(null);
}
}
}
Direct form EventObject javadoc:
public Object getSource()
The object on which the Event initially occurred.
Returns:
The object on which the Event initially occurred.
This means there's no need to know the array indexes of pressed button as it could be known through getSource() method.
I have created a frame in Java which has some textfields and buttons in it. Assuming that user wants more textfields (for example to add more data), I want to put a button and when a user clicks the button, then a new textfield should appear. then user can fill data in it and again by clicking that button another textfield should appear.
How can I do this ? What code I need to write for the button to show more and more text fields by clicking button?
Thank you !
It would be wise that instead of adding components to your JFrame directly, you add them to a JPanel. Though related to your problem, have a look at this small example, hopefully might be able to give you some hint, else ask me what is out of bounds.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JFrameExample
{
private JFrame frame;
private JButton button;
private JTextField tfield;
private String nameTField;
private int count;
public JFrameExample()
{
nameTField = "tField";
count = 0;
}
private void displayGUI()
{
frame = new JFrame("JFrame Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(0, 1, 2, 2));
button = new JButton("Add JTextField");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
tfield = new JTextField();
tfield.setName(nameTField + count);
count++;
frame.add(tfield);
frame.revalidate(); // For JDK 1.7 or above.
//frame.getContentPane().revalidate(); // For JDK 1.6 or below.
frame.repaint();
}
});
frame.add(button);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new JFrameExample().displayGUI();
}
});
}
}
Supposing that you have a main container called panel and a button variable button which is already added to panel, you can do:
// handle the button action event
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// create the new text field
JTextField newTextField = new JTextField();
// add it to the container
panel.add(newTextField);
panel.validate();
panel.repaint();
}
});
When adding the new text field, you may need to mention some layout related characteristics, depending on the layout manager you are using (for instance if you use GridBagLayout, you will need to specify the constraints).