How to propogate Swing events from a inner component to a container? - java

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.

Related

ActionListener interface

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

How to make key events work on a JDialog while there is a JTextArea on it?

What I have basicly created is a JDialog which has a key event on the form. So when for example space is pressed it does something. This worked fine until I created a JTextArea on the same dialog, which is editable. When I did this I can't remove the focus from the JTextArea and make the hot keys work. How do I allow both the key events and the JTextArea to function on the same JDialog?
What you need to do is add the KeyListener from the JDialog to the JTextArea.
Below is a SSCCE of this.
import java.awt.event.*;
import javax.swing.*;
public class DialogListener {
public static void main(String[] args) {
JDialog dialog = new JDialog();
dialog.setSize(300, 400);
dialog.setVisible(true);
KeyListener listener = getKeyListener();
dialog.addKeyListener(listener);
JTextArea area = new JTextArea();
area.addKeyListener(listener);
dialog.add(area);
}
public static KeyListener getKeyListener(){
return new KeyAdapter() {
public void keyTyped(KeyEvent e) {
System.out.println(e.getKeyChar());
}
};
}
}
Let's assume you already have defined your KeyListener for your JDialog object.
This is how you can get the components of a component:
dialog.getContentPane().getComponents();
This is how you can get the array of KeyListeners of your dialog:
KeyListener[] keyListeners = dialog.getKeyListeners();
Now, let's iterate the Components and add the KeyListeners:
Component[] components = dialog.getContentPane().getComponents();
KeyListener[] keyListeners = dialog.getKeyListeners();
for (int componentIndex = 0; componentIndex < components.length; componentIndex++) {
for (int keyListenerIndex = 0; keyListenerIndex < keyListeners.length; keyListenerIndex++) {
components[componentindex].addKeyListener(keyListeners[keyListenerIndex]);
}
}
Code is untested, if there are any typos, please, let me know. Also, this is not transitive, that is, it does not dwelve into the listeners of the Components of Components, it defines the key events for the child Components solely.

How to add actions to a button in java

I have been working with java buttons, and I have created a button ,but when i click the button, I want the shape of the object to change. This is the code I've worked on
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class shapes {
public static void main(String[] a) {
JFrame f = new JFrame("Change shapes");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton b = new JButton("Shapes Change");
f.getContentPane().add(b);
f.pack();
f.setVisible(true);
}
Public void paint (Graphics g)
{
//no clue what to do here
}
private static abstract class MyButton extends JButton implements ActionListener {
MyButton()
{
addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == b)
{
//no clue what to do here
}
}
}
}
At first, There is a shape created, once the button is clicked it I want to change it to another shape.
There really should be any need to subclass JButton. If you want to customise the button, you could use the Action API instead, see How to Use Actions.
To perform custom painting your should extend a Swing component like JComponent or JPanel and override the paintComponent method...
See Performing Custom Painting for more details.
You would then need to provide some method which you could call to tell the component that the shape should change to how the shape should be changed.
You would then provide a means for your buttons ActionListener to reference the instance of the paint panel and call these methods...
You simply add an ActionListener to the button:
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// do some action
}
});
A couple other things to note:
You should not run Swing methods outside the Event Dispatch Thread (EDT) or you may run into unpredictable errors.
Java naming conventions specify that class names should be capitalized. In your code, you named the class "shapes" but it is more proper to name it "Shapes".
First declare and define methods for drawing objects. For example drawSquare (), drawCircle () which draws required shapes. Define radio button or something similar to that to get the users choice (to know which object has to be drawn) . In actionPerformed () check which radiobutton is selected and call the appropriate method for drawing objects and call the repaint () for updating in user interface

Handle RadioButton events after button clicked

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

Events and Listeners in Java

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

Categories

Resources