Link to home
Start Free TrialLog in
Avatar of moonlight
moonlight

asked on

use action-listeners on userdefined objects in a canvas

I have a canvas containing objects ( which are ludo game
pieces here). For drawing these objects on the screen, they
contain x and y coordinates relative to the convas. What I need is actionListeners on every object, so that its not needed to verify the position of a mouse click, but directly  
jump to the actionPerformed method.

This easily done for buttons, menuItems and such but how do I make one for a component?
Avatar of evijay
evijay

are these objects extend from Component ?

If so, you can make these objects implement MouseListener and then in the mouseClicked method of it, fire a actionEvent.
You need to add the methods addActionListener and removeActionListener to these objects and maintain listeners in a vector. In the mouse click event, you need to invoke a fireActionEvent method (which you implement). In the fireActionEvent method, you create a ActionEvent, traverse thru the listener vector and invoke the actionPerformed method for each element in vector.

vijay

ASKER CERTIFIED SOLUTION
Avatar of mjenkins
mjenkins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Here is a complete example just to make it easier to understand:

import java.awt.*;
import java.awt.event.*;
 
public class Act
        extends Canvas
{
    private ActionListener actionListener;
 
        public static void main( String args[] )
        {
                Frame f = new Frame( "Act" );
                f.setSize( 400,400 );
                Act a = new Act( );
                f.add( a );
                a.addActionListener( new ActionListener()
                        {
                                public void actionPerformed( ActionEvent e )
                                {
                                        System.out.println( "DONE" );
                                }
                        }
                );
                f.setVisible(true);
        }
 
        public Act()
        {
                setSize( 100,100 );
                enableEvents( AWTEvent.MOUSE_EVENT_MASK | AWTEvent.ACTION_EVENT_MASK );
        }
 
    public synchronized void addActionListener(ActionListener l)
        {
                actionListener = AWTEventMulticaster.add(actionListener, l);
    }
 
    public synchronized void removeActionListener(ActionListener l)
        {
                actionListener = AWTEventMulticaster.remove(actionListener, l);
    }
 
    protected void processEvent(AWTEvent e)
        {
        if (e instanceof MouseEvent)
                {
                        if( e.getID() == MouseEvent.MOUSE_RELEASED )
                processActionEvent( new ActionEvent(e.getSource(),ActionEvent.ACTION_PERFORMED, "ACTION!") );    
        }
                super.processEvent(e);
    }
 
    protected void processActionEvent(ActionEvent e)
        {
        if (actionListener != null)
                {
            actionListener.actionPerformed(e);
        }
    }
}

Notice that it is our responsibilty to convert the MouseEvent into an ActionEvent. I hope this puts the matter in perspective.
Avatar of moonlight

ASKER

Hi,
I've tested your sample code, but it doesnt respond the way I want it to. It doesnt matter where you click and I want it to. Isn't it what you should achieve with setSize(100,100) in Act () ?

How do I make an invisible area on the screen which will generate the object's actionPerformed() and send the object to it, when clicked on? as opposed to what I see now when it runs actionPerformed() on all clicks everywhere?
The reason that it responds no matter where you click, is that the layout manager is resizing the component (even though I set it to 100,100). The default layout for Frame is BorderLayout. BorderLayout expands the "Center" component to the size of the container. If you insert:

f.setLayout( null );

right after

f.setSize(400,400);

You will see the behavior you are expecting. The app will print "DONE" only while clicking in the area bounded by 0,0,100,100.

You need to manage the size of your components in your actual application.
Well, did it work? Are you satisfied with your answer?
thank you for the help. sorry for dealy.