How to check from a class ModalDialog extends JDialog implements ActionListener if actionPerformed(ActionEvent e) method ocurred in another class (Connect extends JFrame implements ActionListener)? And one step further, how to check which of two buttons that I have in ModalDialog fired ActionPerformed method? (I know about event.getSource, but I need to check it from another class).
public ModalDialog()
{
btn8 = new Button("human");
btn8.setMaximumSize(new Dimension(60,40));
btn8.addActionListener(this);
btn9 = new Button("robot");
btn9.setMaximumSize(new Dimension(60,40));
btn9.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
}
class Connect extends JFrame implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
ModalDialog md = new ModalDialog();
if(md.ActionPerformed(e)....)...something like that...
}
}
How to check from a class ModalDialog extends JDialog implements ActionListener if actionPerformed(ActionEvent e)
This is a basic problem of how to return information from one class to another. The simple answer is to provide a getter method, which returns the selected value.
Start by defining the value to be returned, here I used a enum, as it clearly defines what could be returned
public enum Option {
HUMAN, ROBOT;
}
Update your ModalDialog to provide a getter to return the selected value
public class ModalDialog extends JDialog implements ActionListener {
private Option selection;
public ModalDialog() {
setModal(true);
Button btn8 = new Button("human");
btn8.addActionListener(this);
Button btn9 = new Button("robot");
btn9.addActionListener(this);
setLayout(new GridBagLayout());
add(btn8);
add(btn9);
pack();
}
public Option getSelection() {
return selection;
}
public void actionPerformed(ActionEvent e) {
//...
}
}
When the dialog is closed, the caller can now call getSelection to get the selected value (or null if the user closed the dialog via the [X] button
And one step further, how to check which of two buttons that I have in ModalDialog fired ActionPerformed method?
This is not an uncommon problem, and there a number of ways you might implement it. Since you've already implemented ActionListener at the class level, you could just make use of the actionCommand support available in buttons, which defaults to the text of the button
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
switch (cmd) {
case "human":
selection = Option.HUMAN;
break;
case "robot":
selection = Option.ROBOT;
break;
}
setVisible(false);
}
So now, when the dialog is closed, you can just request the selected value...
ModalDialog dialog = new ModalDialog();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
Option selection = dialog.getSelection();
System.out.println("You choose " + selection);
Related
How to place Action Listener directly in definition of class that extends Button ?
If object of class Button is created then we could simply use anonumous inner class :
b = new Button("Click me");
b.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("stringToPrint");
}
}
);
how to do the same in below :
class CustomizedButton extends Button{
String customClass;
Button(String stringToPrint){
super(customClass); //customClass is also button name
this customString = stringToPrint;
}
/*this.addActionListener( //don't work this way
new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println(customClass);//use outer(?) field
}
}
);*/
}
I need to create 20 almost identical but slightly different buttons, so anonymous inner is too long
You could declare a private nested class, like so:
public class CustomizedButton extends Button{
String customClass;
CustomizedButton(String stringToPrint){
super(customClass); //customClass is also button name
this.customString = stringToPrint;
addActionListener(new MyListener());
}
private class MyListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO: listener code here
}
}
}
But it's not much different from using an anonymous inner class or lambda:
public class CustomizedButton extends Button{
String customClass;
CustomizedButton(String stringToPrint){
super(customClass); //customClass is also button name
this.customString = stringToPrint;
addActionListener(e -> myListenerCode(e));
}
private void myListenerCode(ActionEvent e) {
// TODO: listener code here
}
}
Having said this, other issues come to mind:
Usually it's best to favor composition over inheritance. I would bet that what you really want is some sort of factory method that creates your button complete with listener
Why use AWT components such as the java.awt.Button class when it is 20+ yrs out of date? Why not Swing JButtons instead?
If you were using Swing JButtons, best would be to create a custom Action rather than extend JButton. Actions can hold and change many button properties, including a listener, the displayed text, icons, the tool tip text (displayed on hover)....
For that matter, you should favor JavaFX if this is a new project, since this is the current best-supported Java GUI library.
For example an AbstractAction class could look something like:
public class CustomizedAction extends AbstractAction{
String text;
CustomizedAction(String text, int mnemonic){
super(text); //text is also button name
this.text = text;
putValue(MNEMONIC_KEY, mnemonic); // for alt-key short cut if desired
}
#Override
public void actionPerformed(ActionEvent e) {
String currentName = getValue(NAME); // same value as the text field
System.out.println(currentName);
// TODO: more listener code here
}
}
and could be used like so:
JButton button = new JButton(new CustomizedAction("Foo", KeyEvent.VK_F));
I have a JPanel with a bunch of different check boxes and text fields, I have a button that's disabled, and needs to be enabled when specific configurations are setup.
What I need is a listener on the the whole JPanel looking for events, whenever anything changes.
I believe I need an action listener but I can't find anything to bridge the action Listener with the JPanel
JPanel Window = new JPanel();
Window.addActionListener(new ActionListener(){
//Check if configurations is good
}
I figure I can copy and paste my code a bunch of times into every listener in the panel, but that seems like bad coding practice to me.
First off as #Sage mention in his comment a JPanel is rather a container than a component which do action. So you can't attach an ActionListener to a JPanel.
I figure I can copy and paste my code a bunch of times into every
listener in the panel, but that seems like bad coding practice to me.
You're totally right about that, it's not a good practice at all (see DRY principle). Instead of that you can define just a single ActionListener and attach it to your JCheckBoxes like this:
final JCheckBox check1 = new JCheckBox("Check1");
final JCheckBox check2 = new JCheckBox("Check2");
final JCheckBox check3 = new JCheckBox("Check3");
final JButton buttonToBeEnabled = new JButton("Submit");
buttonToBeEnabled.setEnabled(false);
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean enable = check1.isSelected() && check3.isSelected();
buttonToBeEnabled.setEnabled(enable);
}
};
check1.addActionListener(actionListener);
check2.addActionListener(actionListener);
check3.addActionListener(actionListener);
This means: if check1 and check3 are both selected, then the button must be enabled, otherwise must be disabled. Of course only you know what combination of check boxes should be selected in order to set the button enabled.
Take a look to How to Use Buttons, Check Boxes, and Radio Buttons tutorial.
A suggestion could be to derive a class from each of the components you're using and add an ActionListener that bubbles up the Container tree and looks for the first Container that implements a custom interface like this:
public interface MyCommandProcessor {
void execute(String actionCommand);
}
public class MyButton extends JButton {
public MyButton(string actionCommand) {
setActionCommand(actionCommand);
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
Container traverser = MyButton.this;
while (traverser != null && !(traverser instanceof MyCommandProcessor))
traverser = traverser.getParent();
if (traverser != null)
((CommandListener)traverser).execute(ae.getActionCommand());
}
});
}
}
public class MyApp extends JFrame implements MyCommandListener {
public MyApp() {
JPanel panel = new Panel();
panel.add(new MyButton("MyButton got pressed"));
}
public void execute(String actionCommand) {
System.out.println(actionCommand);
}
}
You need to create custom component listener. Look here:
Create a custom event in Java
Creating Custom Listeners In Java
http://www.javaworld.com/article/2077333/core-java/mr-happy-object-teaches-custom-events.html
I do it throw the standard ActionListener
Example
public class MyPanel extends JPanel {
private final JComboBox<String> combo1;
private final JButton btn2;
.......
//catch the actions of inside components
btn2.addActionListener(new MyPanelComponentsActionListener());
........
//assign actionlistener to panel class
public void addActionListener(ActionListener l) {
listenerList.add(ActionListener.class, l);
}
public void removeActionListener(ActionListener l) {
listenerList.remove(ActionListener.class, l);
}
//handle registered listeners from components used MyPanel class
protected void fireActionPerformed(ActionEvent event) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
ActionEvent e = null;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ActionListener.class) {
// Lazily create the event:
if (e == null) {
String actionCommand = event.getActionCommand();
if(actionCommand == null) {
actionCommand = "FontChanged";
}
e = new ActionEvent(FontChooserPanel.this,
ActionEvent.ACTION_PERFORMED,
actionCommand,
event.getWhen(),
event.getModifiers());
}
// here registered listener executing
((ActionListener)listeners[i+1]).actionPerformed(e);
}
}
}
//!!! here your event generator
class MyPanelComponentsActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//do something usefull
//.....
fireActionPerformed(e);
}
}
....
}
I'm writing a pretty big class and don't want to post it here. The question is the following, how do I refer to the button that was pressed in the constructor of a different class? Let's say, I want to disable it after some actions in the listener. If the listener were anonymus or were an inner class of the SomeClass, I would just use the name of the variable like this:
button.setEnabled(false);
But how can I do it when my listener is a separate class? Tried using e.getModifiers().setEnabled(false) and e.getSource().setEnabled(false), didn't work.
public class SomeClass extends JPanel {
private JButton button = new JButton("Button");
public SomeClass() {
button.setActionCommand("button");
button.addActionListener(new ButtonListener());
}
public static void main(String[] args) {
// TODO code application logic here
}
}
class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String src = e.getActionCommand();
if (src.equals("button")) {
//some actions here
//then
}
}
}
Try this ((JButton)e.getSource()).setEnabled(false)
It must work)
e.getSource() return component to which this event refers( docs)
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
Im new to java and im trying to build a simple GUI with several buttons and drop down menus. Ive managed to get a working GUI but the real question is about the proper use of the actionListener method. In order to assign an action to a button i inserted each actionListener in its own class, this is the code:
public class GUI implements something
{
public static ClientGUI App;
private JFrame chatWin;
private JMenuBar menubar;
private JMenu x;
private JMenu y;
private JMenuItem exit;
private JMenuItem about;
public GUI()
{
/*
* some code and parameters
*/
//creating the menu bar
JMenuBar menubar = new JMenuBar();
chatWin.setJMenuBar(menubar);
JMenu x= new JMenu("menu1");
menubar.add(x);
JMenuItem exit = new JMenuItem("menu2");
x.add(exit);
JMenu y= new JMenu("Help");
menubar.add(help);
JMenuItem about = new JMenuItem("inner menu1");
y.add(about);
//action listener for the exit button
class exitaction implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
}
exit.addActionListener(new exitaction());
//action listener for the about button
class aboutaction implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
//some code
}
}
}
public static void main (String args[])
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
App = new GUI();
}
});
}
}
Is that code is considered to be neat and correct? is there anything i could improve or need to change?
I follow the rule:
If the action implementation is great, I put in a inner class.
public MyFrame extends JFrame {
// componentes creating, etc
private static class MyShortAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e){
// some big implementation
}
}
}
When short, i put in a anonymous class.
myButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e){
// some small code
}
});
If it is used by other components, I extract to a top level class.
public class MyAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e){
// some small code
}
}
Simple direct way to add an action listener to a button:
//Create the button
JButton button_save = new JButton("Save");
add(button_save);
// Create the listener
button_save.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//do your stuff when button clicked
//ex: disable the button
button_save.setEnabled(false);
}
});
It will work, but you can implement that in a separated class or even in the main class instead of creating a nested class for every button...
public class GUI implements something,ActionListener
{
//...
public GUI()
{
//...
exit.setActionListener(this);
about.setActionListener(this);
//...
}
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
if(source == exit)
{
System.exit(0);
} else if(source == about)
{
//action
}
}
}
You could also set an action command to the items and compare the string instead of the object.
public class GUI implements something,ActionListener
{
//...
public GUI()
{
//...
exit.setActionCommand("exit");
exit.addActionListener(this);
about.setActionCommand("about");
about.addActionListener(this);
//...
}
public void actionPerformed(ActionEvent e)
{
String action = e.getActionCommand();
if("exit".equals(action))
{
System.exit(0);
} else if("about".equals(action))
{
//action
}
}
}
IMHO your code is already correct (I mean it's working, isn't it).
The rest is mostly a matter of taste (and usability of your code). For example you may want to reuse your code later or add functionality and other buttons to your program you hadn't considered yet. Therefore try the following rules of thumb:
avoid inner classes – you never know when you want to instantiate an object of that class somewhere else. So, use one file for each class (and btw classes should begin with a capital letter)
put each implementation of the ActionListener in its own class. I know this will blow up your project but all your code will be clearly arranged and you can even reuse the functionality. For example your exit button. Maybe you decide to have a second exit button somewhere else in the program, then you could give those two buttons the same ActionListener and thereby the same functionality.
For the compiler it wont make any difference, but for you when your project starts growing and getting more and more complex.
So, I have a JTextArea. I have added keyboard action to it's input/action maps.
On enter press, JDialog is supposed to be created, along with it's contents. And I need to add keyListener to a button it will contain, which i can't, because that button doesn't ahve final modifier. If I set it to final, I can't edit it's properties.
Here's a snippet of the code:
class blabla extends JTextArea
{
getInputMap.put(KeyStroke.getKeyStroke("ENTER"), "pressedEnter");
getActionMap.put("pressedEnter", new AbstractAction()
{
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e)
{
JDialog dialog;
JButton confirm;;
//JDialog
dialog = new JDialog(Main.masterWindow, "newTitle", true);
dialog.getContentPane().setLayout(new BoxLayout(dialog.getContentPane(), BoxLayout.Y_AXIS));
dialog.addWindowListener(new WindowAdapter()
{
public void windowActivated(WindowEvent e)
{
//this doen't work, it asks me to declare confirm as final
//and I have to request focuse here due to Java bug
confirm.requestFocus();
}
});
//JButton for confirming
confirm = new JButton(lang.getString("ok"));
confirm.setAlignmentX(Component.CENTER_ALIGNMENT);
confirm.addKeyListener(new KeyAdapter()
{
#Override
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
//this doen't work, it asks me to declare confirm as final
confirm.doClick();
}
}
});
dialog.add(confirm);
dialog.pack();
dialog.setLocationRelativeTo(Main.masterWindow);
dialog.setVisible(true);
}
How can I make this work?
Option 1: make confirm a class field.
Option 2: You could create a dummy final JButton variable, final JButton finalConfirm = confirm; and pass in the confirm reference, and then work on this variable inside of the inner class.
Option 3: don't use an anonymous inner class for your Key Binding's AbstractAction, but rather a private inner class with a constructor that takes the JButton instance.