public class myWindow extends JFrame implements ActionListener{
if i have this code my class will be a JFrame where where I can add component and add actionlistener to them in my constructor as followed
public MyWindow()
{
JButton b = new Jbutton("button");
b.addActionListener(this);
}
this keyword will work as an anonymous actionlistener object(which is my class) right ?
later on i will override the actionPerformed method with the heading:-
public void ActionPerformed(ActionEvent ae)
{ :
:
}
I really have a big confusion here .. my book says "the listener object invokes an event handler method with the event as an argument "
listener object : this
event handler method :ActionPerformed(ActionEvent ae)
argument: my event is the JButton b .. how come when it's not of EventAction type ? And if so why we are using :
ae.getActionCommand();
I thought it's a method to tell which component fired the event,why we need it when the component is passed as an argument then?
this keyword will work as an anonymous actionlistener object(which is my class) right ?
No this will be an Object of class which is implementing the actionsListener. In your case it is "MyWindow".
my event is the JButton b .. how come when it's not of EventAction type ? And if so why we are using :
JButton b is a component not an event. Events describes the changed in state of the source. When users interact with GUI, events are generated like clicking of button, moving the mouse.
Reference from Click here
Event Handling is a mechanism that controls the event and decides what should happen if an event occurs.
Steps involved in event handling:-
The User clicks the button and the event is generated.
Now the object of concerned event class is created automatically and information about the source and the event get populated with in same object.
Event object is forwarded to the method of registered listener class.
the method is now get executed and returns.
I thought it's a method to tell which component fired the event,why we need it when the component is passed as an argument then?
Now you would have understood that there could be many buttons registered to the same ActionsListerner. Now to perform different actions for different events,
e.getActionCommand() comes handy, it will tell you which button is the source of firing the event.
Hope this helps.
I have tried to give you can example of a simple JButton program.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ButtonSwing {
private int numClicks = 0;
public Component createComponents() {
//Method for creating the GUI componenets
final JLabel label = new JLabel("Clicks: " + "0"); //final so that i can access inside inner class
JButton button = new JButton("Simple Button");
button.addActionListener(
//inner class for ActionListener. This is how generally it is done.
new ActionListener() {
public void actionPerformed(ActionEvent e) {
numClicks++;
label.setText("Clicks: " + numClicks);
System.out.println(e.getActionCommand());
System.out.println(e.getModifiers());
System.out.println(e.paramString());
}
}
);
JPanel pane = new JPanel(); //using JPanel as conatiner first.
pane.setLayout(new FlowLayout());
pane.add(button); // adding button to the JPanel.
pane.add(label); // adding label to the JPanel.
return pane;
}
public static void main(String[] args) {
JFrame frame = new JFrame("SwingApplication");
ButtonSwing obj = new ButtonSwing();
Component contents = obj.createComponents();
frame.getContentPane().add(contents);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.pack(); //It will cause the window to be sized to fit the preferred size
//and layouts of its subcomponents.
frame.setVisible(true);
}
}
Your JButton is a component not an event. Events are generated by some action on components in this case When you click your button, an ActionEvent will be fired and it will be passed to all the listeners who subscribed to that event in this case it is your MyWindow object which is serving as an ActionListener
Related
help,
my questions are:
why isn't itemStateChanges triggered, I tried to put it in the inner class ButtonHandler and also in RadioButtonHandler Im having trouble with it, what is the right way to do it?
I want to trigger and check the marked JRadioButtons after the user click the "check" button.
What is the right way to check which button was clicked, I feel like comparing the strings is bad programming practise. Maybe using an ID ?
How should I make a "reset" button(start over), I want to uncheck all radio buttons and run the constructor once again.
Thank you for your help !
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class ExamFrame extends JFrame {
static ArrayList<Question> qArrList;
JRadioButton a1,a2,a3,a4;
public ExamFrame() {
super("Quiz");
setLayout(new GridLayout(0, 1));
GridBagConstraints gbc = new GridBagConstraints();
Exam exam = new Exam();
qArrList = exam.getExam();
int count=0;
for(Question q : qArrList){
count++;
JLabel questionLabel = new JLabel(count+". "+q.getQustion()); //swing constant ?
ArrayList<String> ansRand = q.getAllRandomAns();
a1 = new JRadioButton(ansRand.get(0));
a2 = new JRadioButton(ansRand.get(1));
a3 = new JRadioButton(ansRand.get(2));
a4 = new JRadioButton(ansRand.get(3));
add(questionLabel);
add(a1);add(a2,gbc);add(a3);add(a4);
ButtonGroup radioGroup = new ButtonGroup(); //logical relationship
radioGroup.add(a1);radioGroup.add(a2);radioGroup.add(a3);radioGroup.add(a4);
}
//buttons:
JButton checkMe = new JButton("Check Exam");
JButton refresh = new JButton("Start Over");
ButtonHandler handler = new ButtonHandler();
checkMe.addActionListener(handler);
refresh.addActionListener(handler);
add(checkMe);
add(refresh);
}
/** Listens to the radio buttons. */
public class ButtonHandler implements ActionListener
{
public void actionPerformed (ActionEvent e) {
if(e.getActionCommand().equals("Start Over")){ //id?
//how to do this?
}
else{
RadioButtonHandler handler = new RadioButtonHandler();
a1.addItemListener(handler);
System.out.println("success?");
}
JOptionPane.showMessageDialog(ExamFrame.this, String.format("You pressed: %s", e.getActionCommand()));
}
public void itemStateChanged(ItemEvent e) //can i add it here?
{
JOptionPane.showMessageDialog(ExamFrame.this, String.format("yes?"));
System.out.println("success!");
}
}
public class RadioButtonHandler implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{
JOptionPane.showMessageDialog(ExamFrame.this, String.format("radio state changed"));
}
}
}
why "itemStateChanges" isn't triggered, i tried to put it in the inner
class "ButtonHandler" and also in "RadioButtonHandler" Im having
troubles with it, what is the right way to do it? I want to trigger
and check the marked JRadioButtons after the user click the "check"
button.
ButtonHandler is implemented with ActionListener only:
public class ButtonHandler implements ActionListener{}
The itemStateChanged(ItemEvent) function belongs to ItemListener. This function is triggered if state of a source component to which this listener is registered gets changed. So implement the ItemListener. However, one more thing to note, that JButton doesn't respond to ItemListener but JRadioButton will. Because this Item events are fired by components that implement the ItemSelectable interface. Some example of such components are: check boxes, check menu items, toggle buttons and combo boxes including Radio Buttons as mentioned above.
What is the right way to check which button was clicked, i feel like
comparing the strings is wrong programming. Maybe using an ID
Well using the event source function: e.getSource(), check whither the type of the source is your expected type and cast it to appropriate type. And then you can use getName(String) function and check the name you were expecting. Of-course you should assign the name using setName(String) after initialization of component. Or using the component reference directly if it is declared in the Class context and you have direct access to the component.
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getSource() instanceof JCheckBox)
{
JCheckBox checkBox = (JCheckBox)e.getSource();
if(checkBox.getName().equals("expectedName"))
; // do my thing
}
}
How should i make a "reset" button(start over), i want to uncheck all
radio buttons and run the constructor once again.
Well you are working with ButtonGroup. And ButtonGroup has a nice function: clearSelection() to help with whatever(I could not understand the part: run the constructor part) you want.
Edit: As you wanted me to see an ItemListener implemented class, Yes i can see that But:
i can not see that you have actually registered an instance of that class(a1.addItemListener(handler);) to any component before performing any action on the component to which ButtonHandler is registered to: checkMe, refresh
In addition to that, in this action performed function, you are checking with
action command, which you haven't even set with JButton.setActionCommand(String) function. You should not assign a (Item)listener depending on event-occurrence of another (Action)listener.
Tutorial:
How to Write an ItemListener
How to Write an ActionListener
How to Use the ButtonGroup Component
This should be a basic Java program for beginners to be found on
"Head First Java 2nd Edition" on the topic of ActionListener interface.
I didn't understand some of the terminologies used in this program such as
button.addActionListener(this);
when this code executes how is the method actionPerformed is triggered or run or
any terminologies you use??
//Program begins from now!!
import javax.swing.*;
import java.awt.event.*;
public class SimpleGui1B implements ActionListener {
JButton button;
public static void main(String[] args) {
SimpleGui1B gui = new SimpleGui1B();
gui.go();
}
public void go(){ //start go
JFrame frame= new JFrame();
button=new JButton("Click me");
frame.getContentPane().add(button);
button.addActionListener(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300,300);
frame.setVisible(true);
}//close go()
public void actionPerformed(ActionEvent event){
button.setText("I’ve been clicked!");
}
}
Let's break down this statement shall we:
button.addActionListener(this);
Okay, so you're referencing the button object. This is an object of type JButton I presume. The button object has a method called addActionListener. What this does, is add an object that implements the ActionListener interface.
The class that this occurs in is one of those objects. As you can see at the top it says:
public class SimpleGui1B implements ActionListener
So what the program is doing, is saying that the current class (this) will work as a parameter for your method. Then if you look in this class, you have a method actionPerformed.
public void actionPerformed(ActionEvent event){
button.setText("I’ve been clicked!");
}
This means that whenever the button is clicked, the code inside the actionPerformed method is called. Another alternative is to say:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
// Add some code here.
}
This is doing the exact same thing, only it's defining the class inside the brackets.
In the JButton class, the keyboard and mouse events are handled, and once the button detects a click, it iterates to its action listeners and calls them:
ActionEvent event = new ActionEvent(...);
for (ActionListener listener : addedListeners) {
listener.actionPerformed(event);
}
Listeners are just callback objects.
Let's walk through the code:
In javax.swing.AbstractButton there is a method called addActionListener where the code is:
public void addActionListener(ActionListener l) {
listenerList.add(ActionListener.class, l);
}
listenerList is defined in javax.swing.JComponent as:
protected EventListenerList listenerList = new EventListenerList();
When an event occurs fireActionPerformed in javax.swing.AbstractButton is called. The code looks like:
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 = getActionCommand();
}
e = new ActionEvent(AbstractButton.this,
ActionEvent.ACTION_PERFORMED,
actionCommand,
event.getWhen(),
event.getModifiers());
}
((ActionListener)listeners[i+1]).actionPerformed(e);
}
}
}
The most important part is the last line that says:
((ActionListener)listeners[i+1]).actionPerformed(e);
This is the line of code that calls your actionPerformed() method
That means that the class which is invoking this code is a listener of button changes. So that button will invoke "actionPerformed" on this particular class.
button.addActionListener(this); tells button that this wants to know whenever the button is clicked. From then on, whenever the button is clicked it will go through its list of registered ActionListeners and call the actionPerformed method on each one.
What the code
button.addActionListener(this);
does is add your class (using the keyword this) to be the action listener of the button you created.
What this means, is that the button will call your class whenever an action (such as click) happens. This is why you need the method
public void actionPerformed(ActionEvent event){
button.setText("I’ve been clicked!");
}
Because it will be called by the button
Basically you are going thru observer pattern where observers registers themselves with subject.Now whenever this is some event triggers on subject , subject notifies the different observers. Here Button is subject and SimpleGui1B(basically listener) is observer.Now lets come to your code snippet
button.addActionListener(this);
In above line , button is subject and this is listener/observer. JButton has designed in a way, whenever some event(click in this case) happens on button, observers will be notified thru the method actionPerformed
# In the problem which i am posting,in this i am unable to understand the code mentioned on line 1 and line 2, As what i know about them is that they are used to set the action listener for the button but the thing which is most confusing for me is that in the syntax sated on the line 1 and line 2 as, {JB1.addActionListener(this)} in this what is the role of "this".....so please tell the basic behind this.And how this whole syntax works...in detail. #
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class frametest1_1 implements ActionListener
{
JLabel JL;
public frametest1_1()
{
//create a JFrame container
JFrame JF=new JFrame("A BUTTON");
//Frame Layout This is contained in Java .awt.*; "ON USING THIS OPTION OUR BUTTON AND OTHER COMPONENT ARE ADJUSTED IN THE FRAME AUTOMATICALLY"
JF.setLayout(new FlowLayout());
//set the size of the container
JF.setSize(200, 200);
//set visible
JF.setVisible(true);
//make button
JButton JB1=new JButton("FIRST");
JButton JB2=new JButton("SECOND");
//add button to the JFrame container
JF.add(JB1);
JF.add(JB2);
//Create and add Label to the JFrame container
JL=new JLabel("PRESS A BUTTON");
JF.add(JL);
//set action command :now this will help in determining that which button is presses, is it FIRST or SECOND
JB1.setActionCommand("one");
JB2.setActionCommand("two");
//The action responded is added to the actionlistener
JB1.addActionListener((ActionListener) this); // line 1
JB2.addActionListener((ActionListener) this); // line 2
}
public void actionPerformed(ActionEvent ae)
{
if(ae.getActionCommand().equals("one"))
JL.setText("First Button Pressed"); // to set text on the label
else
JL.setText("Second button Pressed"); // to set the text on the label
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new frametest1_1();
}
});
}
}
1. Consider that Listener is someone who reacts to some action.
2.ActionListener is an Interface which has a call back method, named actionPerformed, inside which is the code that will run when certain action is done on the controller.
3. This line JB1.addActionListener((ActionListener) this); means as follows
JB1 - Button
ActionListener - Interface
addActionListener - Registering the Button with the Listener.
4. addActionListener will bind/register the Button with the Listener (here its ActionListener).
5. In an MVC architecture Button is the controller, when certain action is done on it, then who all are to be informed to do certain things is done by registering it to the listener.
6. And this Listener will have the callback method which will be overridden by the class that implements the listener.
7. Moreover in your example, you can also do it like this...
JB1.addActionListener(this);
'this' refers to the current instance of the enclosing class (frametest1_1), the instance constructed in the run() method.
Some further reading on 'this':
Using the this Keyword
Provided code is terribly ugly from object-oriented design point of view - hence your confusion. It's definitely bad idea to have one class responsible for:
containing main method
holding references to JFrame components (i.e. JLabel)
implementation of ActionListener concept
thus violating Single responsibility principle, though such ugly examples can be found even in official tutorials on Swing.
Slightly better implementation of exactly the same functionality would be the following:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class frametest1_1 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
runFrameTest();
}
});
}
public static void runFrameTest() {
//create a JFrame container
JFrame JF=new JFrame("A BUTTON");
//Frame Layout This is contained in Java .awt.*; "ON USING THIS OPTION OUR BUTTON AND OTHER COMPONENT ARE ADJUSTED IN THE FRAME AUTOMATICALLY"
JF.setLayout(new FlowLayout());
//set the size of the container
JF.setSize(200, 200);
//set visible
JF.setVisible(true);
//make button
JButton JB1=new JButton("FIRST");
JButton JB2=new JButton("SECOND");
//add button to the JFrame container
JF.add(JB1);
JF.add(JB2);
//Create and add Label to the JFrame container
final JLabel JL=new JLabel("PRESS A BUTTON");
JF.add(JL);
//set action command :now this will help in determining that which button is presses, is it FIRST or SECOND
JB1.setActionCommand("one");
JB2.setActionCommand("two");
ActionListener labelUpdater = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if(ae.getActionCommand().equals("one"))
JL.setText("First Button Pressed"); // to set text on the label
else
JL.setText("Second button Pressed"); // to set the text on the label
}
};
//The action responded is added to the actionlistener
JB1.addActionListener(labelUpdater); // line 1
JB2.addActionListener(labelUpdater); // line 2
}
}
Hope this helps in understanding ...
In my program I have a main JFrame that holds a button. When this button is clicked a new JFrame appears in which I can change some information. Whenever I finish editing I press a save button on the new JFrame which saves the changes and disposes the JFrame. Now when this is done, I'd like to perform an action in the main JFrame as well, but only if something changed. If I open the new JFrame and just close it again without using the save button, I don't want to do anything in the main frame.
I've tried searching the web for a solution, but just don't seem to be anything useful out there..
An example of the code I've got so far:
Main Frame...
public class MainFrame extends JFrame
{
public MainFrame()
{
super("Main Frame");
JButton details = new JButton("Add Detail");
add(details);
details.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
new DetailFrame().setVisible(true);
}
});
}
}
Detail Frame...
public class DetailFrame extends JFrame
{
public DetailFrame()
{
super("Detail Frame");
JButton save = new JButton("Save");
add(save);
save.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
// Save whatever content
dispose();
}
});
}
}
So when I click the "Save" button on the Detail Frame, I want to do something in the Main Frame, whereas when the "x" is clicked on the Detail Frame, I don't want to do anything..
Hope someone is able to help me, and sorry for my english..
You can pass a MainFrame handle to the DetailFrame constructor. Then, on clicking the Save button, the DetailFrame would call a function in MainFrame and pass the changes to it.
Another way is to create a public boolean variable in DetailFrame and set it to true when the Save button is clicked. This way MainFrame will know whether the DetailFrame was closed or Save'd.
EDIT: Some more ideas:
Use JDialog instead of JFrame. JDialog.setVisible is modal, i.e. it will block the calling function until the dialog is closed; this way you can process the results of the dialog in the same "Details" button listener.
To access the dialog after it is called, store the dialog in a separate variable. First construct the dialog, then show it, and then process the result by analyzing its variables.
Store the results of editing in other public variables of DetailFrame (or let's call it DetailDialog). This should happen only when the "Save" button is clicked. This may even allow to go without the boolean variable (depends on the types of values you are editing).
DetailDialog dlg = new DetailDialog();
dlg.setVisible(true);
if(dlg.approvedResult != null) {
// process the result...
}
EDIT: Sorry, JDialog is not modal by default. Need to call a special super constructor to make it modal.
Also, here you will have to pass the reference to MainFrame to the dialog constructor, but you still can declare it as a simple JFrame and avoid unnecessary dependencies.
To get the reference to the enclosing MainFrame from within the anonymous ActionListener, use MainFrame.this.
To be able to change the button text after it was created, you will have to store the button in a member variable.
Main Frame...
public class MainFrame extends JFrame
{
private JButton details = new JButton("Add Detail");
public MainFrame()
{
super("Main Frame");
getContentPane().add(details);
details.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
DetailDialog dlg = new DetailDialog(MainFrame.this);
dlg.setVisible(true);
if(dlg.approved){
details.setText("Edit Detail");
}
}
});
}
}
Detail Dialog... (not Frame)
public class DetailDialog extends JDialog
{
public boolean approved = false;
public DetailDialog(JFrame parent)
{
super(parent,"Detail Dialog",true); // modal dialog parented to the calling frame
JButton save = new JButton("Save");
getContentPane().add(save);
save.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
// Save whatever content
approved = true;
dispose();
}
});
}
}
Create the detail frame in the main frame, and add a windowlistener to it, using the windowadapter class. Implement the windowclosing event by checking for changes, handle those, and then dispose the detail frame. This is all done in the mainframe.
The detail frame should have do nothing on close set to prevent the detail frame being disposed before you recorded the changes.
You may wish to implement checking for changes in the detailframe as a method returning a class holding the interesting data. That way your windowlistener can be small an to the point.
Forget the 2nd JFrame. use a modal dialog instead. It will block input until dismissed. Once dismissed, the only thing to do is decide whether to update the original data. JOptionPane has some inbuilt functionality that makes that easy. If the user presses Cancel or the esc key, the showInputDialog() method will return null as the result.
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
class EditInfo {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
final JFrame f = new JFrame("Uneditable");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel(new BorderLayout(10,10));
final JTextField tf = new JTextField("Hello World!", 20);
tf.setEnabled(false);
p.add(tf, BorderLayout.CENTER);
JButton edit = new JButton("Edit");
edit.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent ae) {
String result = JOptionPane.showInputDialog(
f,
"Edit text",
tf.getText());
if (result!=null) {
tf.setText(result);
}
}
} );
p.add(edit, BorderLayout.EAST);
p.setBorder(new EmptyBorder(10,10,10,10));
f.setContentPane(p);
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
If it is necessary to edit a number of fields all at once in the JOptionPane, use a JPanel to contain them all, and put them in a showMessageDialog() call. Check the integer based return result to determine if the user OK'd the changes.
I created a component based on a JPanel that contains a textfield and a checkbox. Since I use it as component and put it around in other panels I'd like to be able to set a KeyPressed event for the panel. Obiouvsly this doesn't work as the keyPressed events fire for the inner textfield. Is it there a way to propagate them to the JPanel as it was receiving them instead of the textfield? I tried with handleEvent but it doesn't even compile.
Let's clarify the question. I created this big element containing a textfield. Now a want to use this element in another and I want to set the OTHER ONE as the listener. So there is the JPanel between. That's the problem.
You can use javax.swing.event.EventListenerList in the JPanel containing the JTextField, and create a addKeyListener public method.
import javax.swing.event.EventListenerList;
public static class TestPanel extends JPanel implements KeyListener{
private JTextField text;
private EventListenerList listenerList = new EventListenerList();
TestPanel(){
text = new JTextField();
text.addKeyListener(this);
}
public void keyPressed(KeyEvent e){
//doesn't create a new array, used for performance reasons
Object[] listeners = listenerList.getListenerList();
//Array of pairs listeners[i] is Class, listeners[i + 1] is EventListener
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == KeyListener.class) {
((KeyListener)listeners[i+1]).keyPressed(e);
}
}
}
public void addKeyListener(KeyListener l) {
listenerList.add(KeyListener.class, l);
}
public void keyReleased(KeyEvent e){
//idem as for keyPressed
}
public void keyTyped(KeyEvent e){
//idem as for keyPressed
}
}
Try adding an ActionListener to the JPanel. The actionPerformed() method in the ActionListener will get called when the user presses key in the JTextfield. You can call getSource() on the event object to determine if the event was fired due to action in JTextField and act accordingly.
you could add the JPanel derivative to the JTextField as an event listener.
You will need to do some plumbing to get this to work, for example making your JPanel derivative implement KeyListener and implementing the required methods.