JButton Action Listener not working - java

I'm making a short text adventure game as my first big application, and I've run into a problem. I'm using GUI for my game, and my problem is with the action listener I'm using for the second button, proceed. All of the other code works, except for the method buttonAction. I added an action listener to proceed and whenever I run the code and click proceed, nothing happens and I can't figure out why. I moved the code now found in init2() from actionPerformed(), but it had no effect. I've also tried using #Override on buttonAction, but it gives me the error "The method buttonAction(ActionEvent) of type SimpleGui must override or implement a supertype method". Please keep in mind that my java skills are at best, elementary, so please try to explain as best you can. Any help would be greatly appreciated. The code from my application is below.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import Classes.Rogue;
import Classes.Warrior;
import Classes.Wizard;
public class SimpleGui extends JFrame implements ActionListener {
public JPanel panelControl, panel, panel2, panel3, panel4;
public JButton create, proceed;
public JTextField name;
public final JTextField textField = new JTextField();
public JComboBox playerClass;
public Char player1;
public String[] classOptions = { "Rogue", "Wizard", "Warrior" };
public JLabel textObject;
SimpleGui() {
super("RPG Quest");
name = new JTextField(20);
init();
this.setVisible(true);
this.setSize(455, 250);
this.setResizable(false);
}// end SimpleGui
public void init() {
panel = new JPanel();
panel3 = new JPanel();
panel2 = new JPanel();
playerClass = new JComboBox(classOptions);
create = new JButton("Create Character");
create.addActionListener(this);
textObject = new JLabel("Name");
panel.setBorder(BorderFactory
.createTitledBorder("<html><font color:black>Create Your Character</font></html>"));
panel.add(textObject);
panel.add(name);
panel.add(playerClass);
panel.setBackground(Color.WHITE);
panel3.setBorder(BorderFactory
.createTitledBorder("<html><font color:black>Class Descriptions</font></html>"));
panel3.add(new JLabel(
"<html><font color:black>The Rogue has a 20% chance to land Critical Hits on enemies.</font></html>"));
panel3.add(new JLabel(
"<html><font color:black>The Wizard can only cast spells and has only a 70% chance of landing a hit,</font></html>"));
panel3.add(new JLabel(
"<html><font color:black>but spells do more damage than melee attacks.</font></html>"));
panel3.add(new JLabel(
"<html><font color:black>The Warrior has a 30% chance to block an incoming attack.</font></html>"));
panel3.setBackground(Color.WHITE);
panel2.add(create);
panel2.setBackground(Color.WHITE);
this.add(panel);
this.add(panel3);
this.add(panel2);
this.pack();
this.setResizable(true);
this.setLayout(new BorderLayout());
this.add(panel, BorderLayout.NORTH);
this.add(panel3);
this.add(panel2, BorderLayout.SOUTH);
}// end void
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource() == create) {
String type = classOptions[playerClass.getSelectedIndex()];
if (type == "Rogue") {
player1 = new Rogue();
}
if (type == "Wizard") {
player1 = new Wizard();
}
if (type == "Warrior") {
player1 = new Warrior();
}
player1.name = name.getText();
JOptionPane.showMessageDialog(this, "You are a " + type
+ ". Your name is " + player1.name + ".");
init2();
}
}
public void init2() {
this.remove(panel);
this.remove(panel2);
this.remove(panel3);
panel.remove(textObject);
panel.remove(name);
panel.remove(playerClass);
panel.setBorder(BorderFactory
.createTitledBorder("<html><font color:black>Info</font></html>"));
panel.setBackground(Color.WHITE);
proceed = new JButton("Proceed");
proceed.addActionListener(this);
panel.add(proceed);
textField.setText("Hello There");
textField.setEditable(false);
panelControl = new JPanel();
panelControl.setBackground(Color.WHITE);
panelControl.setBorder(BorderFactory.createBevelBorder(NORMAL));
panelControl.add(textField);
this.add(panelControl, BorderLayout.NORTH);
this.add(panel, BorderLayout.SOUTH);
this.pack();
}
public void buttonAction(ActionEvent event) {
proceed.addActionListener(this);
if (event.getSource() == proceed) {
JOptionPane.showMessageDialog(this, "It Works!");
System.out.println("hi");
}
}
}
// end class

Since your class implements ActionListener, it must define an implementation for actionPerformed, which you have correctly done. Now when you say
proceed.addActionListener(this);
you are essentially connecting the button to the actionPerformed defined in your class, and not to the buttonAction() method you seem to wish to connect to. This is the same listener that create is connected to. You should be able to fix this by using
public void actionPerformed(ActionEvent event) {
if (event.getSource() == create) {
String type = classOptions[playerClass.getSelectedIndex()];
if (type == "Rogue") {
player1 = new Rogue();
}
if (type == "Wizard") {
player1 = new Wizard();
}
if (type == "Warrior") {
player1 = new Warrior();
}
player1.name = name.getText();
JOptionPane.showMessageDialog(this, "You are a " + type
+ ". Your name is " + player1.name + ".");
init2();
} else if (event.getSource() == proceed)
{
JOptionPane.showMessageDialog(this, "It Works!");
System.out.println("hi");
{
}
This would make buttonAction() unnecessary. I will add that instead of implementing ActionListener, you could define listeners as inner classes, and connect buttons to them individually, making the code cleaner. Something for you to research :)

You have written
proceed.addActionListener(this);
So whenever you are clicking on the JButton proceed you are basically calling actionPerformed(ActionEvent event) of the class SimpleGui. Now the actionPerformed method does not have any code for proceed. So, it does nothing.
I would here suggest that you add the code for proceed variable in the actionPerformed method of the class SimpleGui. You could add the following after the existing code of you actionPerformed as illustrated below:
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource() == create) {
//Your existing code;
} else if (event.getSource() == proceed){
//put the code for proceed action here.
}
}
I hope that this will solve your problem.

You made the event handler be 'this', means when the button clicked, the
#Override public void actionPerformed(ActionEvent event)
will be triggered.
public void buttonAction(ActionEvent event)
is useless in your code. And you cannot use #Override on it because none of the interface have this method signature.
if (event.getSource() == create)
will only allow the create button to pass.
So, the solution can be add another condition and add your code for proceed button, in the actionPerformed method.
if (event.getSource() == create){...}
else if (event.getSource() == proceed){...}

Related

How do I call a GUI form from another Java class

So I have been figuring out how to make this work but I can't find , so I decided to look for help, the below is how my code look like,What I'm trying to do is display the Main Menu after the user refuse to proceed the tutorial and I tried to
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Login {
public Login() {
String userName;
int option;
//This will ask user to input the username
userName = JOptionPane.showInputDialog(null,"Please enter your name","Welcome", JOptionPane.INFORMATION_MESSAGE);
//Display option
option =JOptionPane.showOptionDialog(null, "Welcome " + userName + "\n\nWould you like to have a tutorial about this game?",
"Welcome", JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE, null, null, null);
//Ok to continue to the tutorial
if(option == JOptionPane.OK_OPTION)
{
//Call the tutorial class
}
This is where the code gone wrong and I tried to resolve with different ways
else //If select cancel will proceed to the Main menu
{
//This is the part I can't figure it out, it display different errors when I try different ways
that I searched from website
MainMenu MainMenuGUI = new MainMenu();
}
}
}
And here's my Main Menu code
import javax.swing.*;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.*;
import javax.swing.*;
public class MainMenu {
private JButton exitButton;
private JPanel MainMenu;
private JButton startButton;
private JButton historyButton;
public MainMenu() {
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int exitButton = JOptionPane.YES_NO_OPTION;
exitButton = JOptionPane.showConfirmDialog(null, "Are you sure you want to exit?", "Warning", JOptionPane.YES_NO_OPTION);
if (exitButton == JOptionPane.YES_OPTION)
{
System.exit(0);
}
}
});
}
//Main Menu GUI setup
public static void main(String[] args) {
JFrame frame = new JFrame("Main Menu");
frame.setContentPane(new MainMenu().MainMenu);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setMinimumSize(new Dimension(500, 500));
frame.pack();
frame.setVisible(true);
}
}
Your current code has a couple of problems.
By creating the JFrame container in your main method, you're preventing the UI from ever showing up when instantiating MainMenu - that is, the UI will only show anything when the main method is invoked by the JVM. To fix this, I've moved your JFrame instantiation/setup into MainMenu's constructor.
In the MainMenu class, the mainMenu JPanel is never instantiated. This means your current code doesn't actually paint anything on the JFrame - you need to instantiate mainMenu and add your GUI controls to mainMenu.
The code below fixes both problems.
public class MainMenu
{
private JButton exitButton;
private JPanel mainMenu;
private JButton startButton;
private JButton historyButton;
public MainMenu()
{
JFrame frame = new JFrame("Main Menu");
///// mainMenu IS ALWAYS NULL WITHOUT THE NEXT LINE!!!!
this.mainMenu = new JPanel();
frame.setContentPane(this.mainMenu);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setMinimumSize(new Dimension(500, 500));
frame.pack();
frame.setVisible(true);
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
int exitButton = JOptionPane.YES_NO_OPTION;
exitButton = JOptionPane.showConfirmDialog(null, "Are you sure you want to exit?", "Warning", JOptionPane.YES_NO_OPTION);
if (exitButton == JOptionPane.YES_OPTION)
{
System.exit(0);
}
}
});
}
//Main Menu GUI setup
public static void main(String[] args)
{
new MainMenu();
}
Get rid of the public static void main(String args[]) method in your MainMenu class. You only use the main method once in a java program. Instead, create a method like public void initUI() and place all the code you have inside the main() method in it.
And in your Login class, right after you call MainMenu MainMenuGUI = new MainMenu();
you can call MainMenuGUI.initUI().
One small thing, MainMenuGUI should probably be mainMenuGUI to properly follow camel case formatting and to avoid confusion later on.

Enter Key work as Tab Key for every component except JButton

I am developing a Swing application, in which I want enter key work as tab key for all component of JFrame except JButton components and dialog boxes. For that I have set ENTER and TAB as default focus traversal keys.
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
Set<KeyStroke> keys = new HashSet<>();
keys.add(enter);
keys.add(tab);
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys);
This is working well,but I want that ENTER Key work as Action on JButton and Dialog Boxes.
It's possible, but using another way: global event listener. To register a global event listener you should use the Toolkit class:
Toolkit.getDefaultToolkit().addAWTEventListener(listener, mask);
Here is an example for your case:
import java.awt.AWTEvent;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class FocusTransferTest {
public static void main(String[] args) {
JFrame frm = new JFrame("Test focus transfer");
JPanel panel = new JPanel();
panel.add(new JTextField(10));
panel.add(new JTextField(10));
panel.add(new JTextField(10));
JButton btn = new JButton("Press me");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frm, "It's a message", "Info",
JOptionPane.INFORMATION_MESSAGE);
}
});
panel.add(btn);
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEnterKeyListener(),
AWTEvent.KEY_EVENT_MASK);
frm.add(panel);
frm.pack();
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
private static class AWTEnterKeyListener implements AWTEventListener {
#Override
public void eventDispatched(AWTEvent event) {
if (event instanceof KeyEvent) {
KeyEvent key = (KeyEvent) event;
if (key.getKeyCode() == KeyEvent.VK_ENTER && key.getModifiersEx() == 0
&& key.getID() == KeyEvent.KEY_PRESSED) {
if (key.getComponent() instanceof AbstractButton) {
((AbstractButton) key.getComponent()).doClick();
} else {
key.getComponent().transferFocus();
}
}
}
}
}
}
I think even the solution using AWTEventListener would work, I would suggest avoid using AWTEventListener if another solution is available. It is because it's so powerful that it intercepts all kinds of events globally before they reach their real targets, so if anything went wrong (such as a NullPointerException) in the middle, the whole application would stop working.
My proposed solution makes use of input map & action map which adds handling of Enter key to any focused component in a particular container.
The advantage:
Safer because it affects only components in a container instead of all components.
The disadvantage:
The same handling code has to apply to all containers that need this behavior, but this could be easily accomplished by a static utility method.
Here is the sample program:
public MainFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500, 500);
setLayout(new GridLayout(2, 2));
addAllComponents();
addEnterKeyAsFocusTraversal();
}
private void addAllComponents() {
add(new JTextField());
add(new JTextField());
add(new JButton("OK"));
add(new JButton("Cancel"));
}
private void addEnterKeyAsFocusTraversal() {
final String ENTER_KEY_ACTION = "EnterKeyAction";
// Here uses the content pane of type Container so a cast is required,
// in other case it could be the root container which may already be an instance of JComponent.
JComponent contentPane = (JComponent) getContentPane();
contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ENTER_KEY_ACTION);
contentPane.getActionMap().put(ENTER_KEY_ACTION, createEnterKeyAction());
}
private AbstractAction createEnterKeyAction() {
return new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if (focusOwner != null) {
if (focusOwner instanceof AbstractButton) {
((AbstractButton) focusOwner).doClick();
} else {
focusOwner.transferFocus();
}
}
}
};
}
The approved answer is actually bit wrong.
It add Enter as focus travel key, however it DOES NOT modify the basic button behavior of .doClick();
So this code spams .doClick(); second time. I came across this issue when on button action I was writing data from bunch of text Fields to table, and it added the same record two times. solution for this is pretty simple, on instanceof JButton just make return;
repaired code upgraded to java 14 instanceof
private static class AWTListener implements AWTEventListener{
#Override
public void eventDispatched(AWTEvent event) {
if (event instanceof KeyEvent key && key.getKeyCode() == KeyEvent.VK_ENTER && key.getModifiersEx() == 0 && key.getID() == KeyEvent.KEY_PRESSED) {
if (key.getComponent() instanceof JButton) {
return;
}
key.getComponent().transferFocus();
}
}
}

I'm trying to make a text based GUI game in Java. How do I make the message boxes update to show the next outcomes?

I added more prompts now and the message boxes should say different things but they are stuck at "You go forward and hit a wall" and "You are now facing the opposite direction" They don't change when they should and the third option that I added isn't showing up. Again, here's my code:
package game;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class game extends JFrame implements ActionListener {
JLabel prompt;
JTextField name;
JTextField name1;
JButton click;
JButton click1;
String storeName;
String storeName1;
JButton click2;
public game(){
setLayout(null);
setSize(300,250);
setTitle("Text Adventure");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
prompt = new JLabel("You find yourself in a tunnel.");
click = new JButton("Go forward!");
click1 = new JButton("Turn around!");
click2 = new JButton();
name = new JTextField();
name1 = new JTextField();
prompt.setBounds(60,30,1300,30);
click.setBounds(50,130,100,30);
click.addActionListener(this);
click1.setBounds(150,130,125,30);
click1.addActionListener(this);
click2.setBounds(125,160,125,30);
click2.addActionListener(this);
add(click);
add(click1);
add(name);
add(name1);
add(prompt);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == click) {
JOptionPane.showMessageDialog(null, "You go forward and hit a wall.");
}
{
if(e.getSource() == click1) {
JOptionPane.showMessageDialog(null, "You are now facing the opposite direction.");
prompt.setText("What would you like to do now?");
click.setText("Go forward!");
click1.setText("Turn on light.");
}
}
}
public void actionPerformed1(ActionEvent e) {
if(e.getSource() == click) {
JOptionPane.showMessageDialog(null, "You walk down the tunnel until you hit an intersection.");
prompt.setText("Which way would you like to go?");
click.setText("Left!");
click1.setText("Right!");
add(click2);
click2.setText("Keep going!");
}
if(e.getSource() == click1) {
}
}
public static void main(String args[]){
game s = new game();
s.setVisible(true);
}
}
In your actionPerformed function, use
prompt.setText(" new prompt");
to set the prompt to another prompt.
You might also change the options with:
click.setText(" new click command");
click1.setText(" new click1 command");

Every time i click a button it exits? (action listener)

here is my code
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.applet.Applet;
class Panell implements ActionListener {
JButton button;
JButton buttonTwo;
JButton buttonThree;
JButton buttonFour;
JButton buttonFive;
JTextArea textArea;
public static void main(String[] args) {
Panell gui = new Panell ();
gui.go();
}
void go() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBackground(Color.darkGray);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
button = new JButton("Monday");
buttonTwo = new JButton("Tuesday");
buttonThree = new JButton("Wednesday");
buttonFour = new JButton("Thursday");
buttonFive = new JButton("Friday");
textArea = new JTextArea();
button.addActionListener(this);
buttonTwo.addActionListener(this);
buttonThree.addActionListener(this);
buttonFour.addActionListener(this);
buttonFive.addActionListener(this);
panel.add(button);
panel.add(buttonTwo);
panel.add(buttonThree);
panel.add(buttonFour);
panel.add(buttonFive);
frame.add(BorderLayout.CENTER, textArea);
frame.getContentPane().add(BorderLayout.WEST, panel);
frame.setSize(300,300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
if(event.getSource() == button) {
textArea.setText("I've been clicked!");
} else {
System.exit(1);
}
{
if(event.getSource() == buttonTwo) {
textArea.setText("herro");
} else {
System.exit(1);
}
}
}
}
It keeps on exiting when i press a button? any ideas?
and also how can i add more action listeners?
You should exit (should you?) only if all of the conditions (buttons pressed) failed. Not one of them.
You can use something like:
if(event.getSource() == button) {
textArea.setText("I've been clicked!");
} else if(event.getSource() == buttonTwo) {
textArea.setText("herro");
} else if(...
...//any other check
} else {
System.exit(1); //button not found :(
}
Your application closes due to your "System.exit(1)".
The comparison "==" is ok in this case, since you compare object-references. But you have always to be sure if you compare references or objects. So it is more safe for you to change your code:
event.getSource() == button
to this
event.getSource().equals(button)
In addition you should check your if's: if the event source is not "button" (Monday), your "else" quits your application. The next comparison (to buttonTwo) will never be reached.
If the first comparison fits, the next comparison will fail and again the next "else" (of the second comparison) quits your application.
Change your code to something like this:
public void actionPerformed(ActionEvent event) {
if (event.getSource().equals(button)) {
textArea.setText("I've been clicked!");
} else if (event.getSource().equals(buttonTwo)) {
textArea.setText("herro");
} else {
System.exit(1);
}
}

Java Swing add/remove jButtons on runtime

My application has a module which allows the user to add jButtons on the jLayeredpane during runtime. I want to add action listeners to this dynamically added contents and also i have to provide access to delete the dynamically added buttons during runtime. Is there any way to do this ?
private Map<String, JButton> dynamicButtons;
public void addButton(String name) {
JButton b = new JButton(name);
b.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jLayeredPane2.add(b);
dynamicButtons.put(name, b);
jLayeredPane2.invalidate();
}
public void removeButton(String name) {
JButton b = dynamicButtons.remove(name);
jLayeredPane2.remove(b);
jLayeredPane2.invalidate();
}
Original Answer Good in general, but done differently in this case
In order to keep track of an arbitrary number of added JButtons, you will need to keep them in a list.
So, after you create a new button, add the listeners to it, and add it to the pane, you then need to save that new button in a list.
That way you can keep track of all of the buttons you have added.
You could also use a Map<String, JButton> that maps a button name to the button.
Example:
private Map<String, JButton> dynamicButtons;
public void addButton(String name) {
JButton b = new JButton(name);
b.addActionListener(someAction);
yourPanel.add(b);
dynamicButtons.put(name, b);
yourPanel.invalidate();
}
public void removeButton(String name) {
Button b = dynamicButtons.remove(name);
yourPanel.remove(b);
yourPanel.invalidate();
}
The following is a full class that lets you add and remove buttons dynamically. It's not exactly what you want, but it should get you really close.
Code for your specific case:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class ExampleFrame extends JFrame {
private JButton add, remove;
private JPanel dynamicButtonPane, addRemovePane;
private boolean waitingForLocationClick;
public ExampleFrame() {
super("Dynamic button example");
waitingForLocationClick = false;
add = new JButton("Add Button");
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
addButton(JOptionPane
.showInputDialog("Name of the new button:"));
}
});
remove = new JButton("Remove Button");
remove.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
lookingToRemove = true;
}
});
JPanel mainPane = new JPanel(new BorderLayout());
dynamicButtonPane = new JPanel();
dynamicButtonPane.setLayout(null);
dynamicButtonPane.setPreferredSize(new Dimension(300, 300));
addRemovePane = new JPanel();
addRemovePane.add(add);
addRemovePane.add(remove);
mainPane.add(dynamicButtonPane, BorderLayout.NORTH);
mainPane.add(addRemovePane, BorderLayout.SOUTH);
add(mainPane);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
dynamicButtonPane.addMouseListener(pointSelectorListener);
}
private JButton buttonToPlace;
public void addButton(String name) {
JButton b = new JButton(name);
b.setActionCommand(name);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (lookingToRemove) {
if (e.getSource() instanceof JButton) {
dynamicButtonPane.remove((Component) e.getSource());
dynamicButtonPane.validate();
dynamicButtonPane.repaint();
}
} else
JOptionPane.showMessageDialog(ExampleFrame.this, "This is " + e.getActionCommand());
}
});
waitingForLocationClick = true;
lookingToRemove = false;
buttonToPlace = b;
}
public void putButtonAtPoint(Point p) {
System.out.println("Placing a button at: " + p.toString());
dynamicButtonPane.add(buttonToPlace);
buttonToPlace.setBounds(new Rectangle(p, buttonToPlace
.getPreferredSize()));
dynamicButtonPane.validate();
buttonToPlace = null;
waitingForLocationClick = false;
}
private boolean lookingToRemove = false;
private final MouseListener pointSelectorListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (waitingForLocationClick) {
putButtonAtPoint(e.getPoint());
} else {
System.out.println("Not in waiting state");
}
}
};
public static void main(String[] args) {
new ExampleFrame();
}
}
Absolutely. All of this stuff can be done programatically at any time. Here are a couple of hints to avoid problems and pitfalls:
When you add components to any panel, make sure this is done on the Event Dispatch Thread through SwingUtilities.invokeLater(Runnable). Inside the Runnable, you want to add the component to the panel, hook up the listeners, and re-layout the panel.
Use SwingUtilities.isEventDispatchThread() to check to see if you are already on the event dispatch thread. If you are, then you can just run the Runnable immediately instead of calling invokeLater.
Once you've modified the layout of a panel, be sure to call Component.invalidate() on the panel to make sure it gets laid out again.
Maintain your own list of listeners. Overwrite the add and remove methods on the panel to add or remove them from your list and also from all existing buttons. When you add new buttons, add all listeners on the list.
This is a very common task, and it is fully supported by Java. You should be able to get it done without too much trouble.

Categories

Resources