一、动作
对于多个事件需连接到一个监听器上的情况,可以使用Action接口。
Action接口中包含下列方法:
void actionPerformed(ActionEvent e);
void setEnabled(boolean b);
boolean isEnabled();
void putValue(String key,Object value);
Object getValue(String key);
void addPropertyChangeListener(propertyChangeListener listener);
void removePropertyChangeListener(propertyChangeListener listener);
键值对中有两个重要的预定义字符串,Action.NAME和Action.SMALL_ICON,分别用于存储动作的名称和动作的图标
还有一个常用预定义字符串Action.SHORT_DESCRIPTION,用于存储图标的简要说明,显示在工具提示中。
action.putValue(Action.NAME,"blue");
action.putValue(Action.SMALL_ICON,new ImageIcon("2b.jpg"));
action.putValue(Action.SHORT_DESCRIPTION,"change blue");
其它一些预定义字符串见API文档。
Action接口的最后两个方法能够让其它对象在动作对象的属性发生变化时得到通告,尤其是菜单或工具栏触发的动作。
Action是接口,所以每次使用都必须实现这七个方法,比较麻烦,对应的AbstractAction是实现了Action接口除actionPerformed以外的方法,因此使用时只要实现actionPerformed方法即可。
class ColorAction extends AbstractAction
{
public ColorAction(String name,ImageIcon img,Color c)
{
putValue(Action.NAME,name);
putValue(Action.SMALL_ICON,img);
putValue("color",c);
putValue(Action.SHORT_DESCRIPTION,"set color"+name.toLowerCase());
}
public void actionPerformed(ActionEvent e)
{
Color c = (Color)getValue("color");
setBackground(c);
}
}
动作与按钮关联
Action blueColorAct = new ColorAction("blue",new ImageIcon("2b.jpg"),Color.BLUE);
JButton blueButton = new JButton(blueColorAct);
按键与动作关联:
上面实现了按钮与动作的关联,现在需要实现按键与动作的关联,此时需要生成KeyStroke对象,其封装了对键的说明。
KeyStroke的构造方法是private的,获得对象需要调用getKeyStroke方法
KeyStroke blueKey = KeyStroke.getKeyStroke(KeyEvent.VK_B,InputEvent.CTRL_DOWN_MASK);
每个JComponent有三个输入映射,WHEN_FOCUSED(当该组件拥有键盘焦点时),WHEN_ANCESTOR_OF_FOCUSED_COMPONENT(当该组件包含了拥有键盘焦点的组件时),WHEN_IN_FOCUSED_WINDOW(当该组件包含在一个拥有键盘焦点组件的窗口中时)。一个击键将按照WHEN_FOCUSED,WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,WHEN_IN_FOCUSED_WINDOW的顺序检查这些映射,找到符合的映射就执行。可以使用getInputMap方法从组件获得输入映射
InputMap imap = panel.getInputMap(JComponent.WHEN_FOCUSED);
InputMap不能直接将KeyStroke与Action映射,需要两层映射,首先通过InputMap将KeyStroke映射到任意对象a,然后通过ActionMap将a映射到需要的Action。这样就相当于对象KeyStroke与动作Action的映射。
InputMap imap = panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
imap.putValue(KeyStroke.getKeyStroke("ctrl b"),"panelblue");
ActionMap amp = panel.getActionMap();
amp.put("panelblue",blueAct);
例程
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.util.ArrayList;
public class ActionFrameTest01
{
public static void main(String[] args)
{
ActionFrame sp = new ActionFrame();
sp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //关闭窗口是操作
sp.setVisible(true); //显示组件
sp.setTitle("ActionWindow"); //标题栏
}
}
class ActionFrame extends JFrame
{
public ActionFrame()
{
ActionPanel mp = new ActionPanel();
setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT); //设置组件宽度和高度
//setResizable(false); //设置组件大小是否可调节
add(mp);
}
public static final int DEFAULT_WIDTH = 650;
public static final int DEFAULT_HEIGHT = 350;
}
class ActionPanel extends JPanel
{
public ActionPanel()
{
Toolkit kit = Toolkit.getDefaultToolkit();
Image img = kit.getImage("2b.jpg").getScaledInstance(15,15,5);
ImageIcon imgIcon = new ImageIcon(img);
rect2D = new ArrayList<Rectangle2D>();
MouseListener mousL = new MouseLis();
MouseMotionListener mouseMl = new MouseMLis();
addMouseListener(mousL);
addMouseMotionListener(mouseMl);
JButton clearB = new JButton("清除");
add(clearB);
ActionListener act = new ClActionListener();
clearB.addActionListener(act);
//动作与按钮关联
Action blueAct = new ColorAction("blue",imgIcon,Color.BLUE);
JButton blueButton = new JButton(blueAct);
Action yellowAct = new ColorAction("yellow",imgIcon,Color.YELLOW);
JButton yellowButton = new JButton(yellowAct);
Action greenAct = new ColorAction("green",imgIcon,Color.GREEN);
JButton greenButton = new JButton(greenAct);
add(blueButton);
add(yellowButton);
add(greenButton);
backColor=getBackground();
//动作与按键关联
InputMap imap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
imap.put(KeyStroke.getKeyStroke("ctrl B"),"panelblue");
imap.put(KeyStroke.getKeyStroke("ctrl Y"),"panelyellow");
imap.put(KeyStroke.getKeyStroke("ctrl G"),"panelgreen");
ActionMap amp = getActionMap();
amp.put("panelblue",blueAct);
amp.put("panelyellow",yellowAct);
amp.put("panelgreen",greenAct);
JMenu blueM = new JMenu(blueAct);
JMenu yellowM = new JMenu(yellowAct);
JMenu greenM = new JMenu(greenAct);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D gps2D = (Graphics2D)g ;
//图形颜色
gps2D.setPaint(Color.RED);
for(Rectangle2D r2d:rect2D)
{
gps2D.draw(r2d);
}
}
public void add(Point2D e)
{
double x = e.getX();
double y = e.getY();
Rectangle2D temp2d = new Rectangle2D.Double(x-side/2,y-side/2,side,side);
rect2D.add(temp2d);
repaint();
}
public void remove(Rectangle2D e)
{
if(e==null)
return;
else
{
rect2D.remove(e);
currentR2D=null;
}
repaint();
}
public Rectangle2D findR2D(Point2D e)
{
for(Rectangle2D r:rect2D)
{
if(r.contains(e.getX(),e.getY()))
return r;
}
return null;
}
class MouseLis extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
currentR2D = findR2D(e.getPoint());
if(currentR2D == null)
{
add(e.getPoint());
}
}
public void mouseClicked(MouseEvent e)
{
if((currentR2D != null)&&(e.getClickCount()>=2))
{
remove(currentR2D);
}
}
}
class MouseMLis extends MouseMotionAdapter
{
public void mouseDragged(MouseEvent e)
{
double x = e.getX();
double y = e.getY();
if(currentR2D != null)
{
currentR2D.setFrame(x-side/2,y-side/2,side,side);
repaint();
}
}
public void mouseMoved(MouseEvent e)
{
currentR2D = findR2D(e.getPoint());
if(currentR2D != null)
{
//newCursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
Toolkit tk = Toolkit.getDefaultToolkit();
Image img = tk.getImage("2b.jpg");
newCursor = tk.createCustomCursor(img,new Point(5,5),"new Cursor");
}
else
{
newCursor = Cursor.getDefaultCursor();
}
setCursor(newCursor);
}
}
class ClActionListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
rect2D.clear();
setBackground(backColor);
repaint();
}
}
class ColorAction extends AbstractAction
{
public ColorAction(String name,ImageIcon img,Color c)
{
putValue(Action.NAME,name);
putValue(Action.SMALL_ICON,img);
putValue("color",c);
putValue(Action.SHORT_DESCRIPTION,"set background "+name.toLowerCase());
}
public void actionPerformed(ActionEvent e)
{
Color c = (Color)getValue("color");
setBackground(c);
}
}
private Color backColor;
private Cursor newCursor;
private ArrayList<Rectangle2D> rect2D;
private Rectangle2D currentR2D;
private static final int side =10;
}
二、多点传送
多点传送就是一个事件传给多个事件监听器处理。将多个监听器添加到一个事件源就可以使得所有注册的监听器都能对该事件进行处理。
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.util.ArrayList;
public class MultiFrameTest01
{
public static void main(String[] args)
{
MultiFrame sp = new MultiFrame();
sp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //关闭窗口是操作
sp.setVisible(true); //显示组件
sp.setTitle("MouseWindow"); //标题栏
}
}
class MultiFrame extends JFrame
{
public MultiFrame()
{
MousePanel mp = new MousePanel();
setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT); //设置组件宽度和高度
//setResizable(false); //设置组件大小是否可调节
add(mp);
}
public static final int DEFAULT_WIDTH = 650;
public static final int DEFAULT_HEIGHT = 350;
}
class MousePanel extends JPanel
{
public MousePanel()
{
JButton newFrame = new JButton("新建");
final JButton closeAllFrame = new JButton("全部关闭");
add(newFrame);
add(closeAllFrame);
ActionListener newActListener = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ExtraFrame extFrame = new ExtraFrame(closeAllFrame);
extFrame.setVisible(true);
}
};
newFrame.addActionListener(newActListener);
}
}
class ExtraFrame extends JFrame
{
public ExtraFrame(final JButton closeAllFrame)
{
counter++;
setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);
setTitle("MultiWindow"+counter);
setLocation(startXY*counter,startXY*counter);
setVisible(true);
actL=new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
closeAllFrame.removeActionListener(actL);
dispose();
}
};
closeAllFrame.addActionListener(actL);
}
private ActionListener actL;
private static int counter=0;
private static final int DEFAULT_WIDTH = 400;
private static final int DEFAULT_HEIGHT = 200;
private static final int startXY=20;
}
执行结果:
三、实现事件源
实现自定义的事件三要素:
1、事件类型(Event Type)。
2、事件监听接口(Event Listener Interface)。
3、增加和删除监听器方法
addXXXXListener(Event Listener e);
removeXXXXListener(Event Listener e);
事件源需要在事件发生的时候,构造一个事件对象,并传递给注册的事件监听器。
EventListenerList类可以管理事件监听器,使用它可以实现增加、删除事件监听器和激活事件。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.*;
public class EventSourceFrameTest01
{
public static void main(String[] args)
{
EventSourceFrame sp = new EventSourceFrame();
sp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sp.setVisible(true);
}
}
class EventSourceFrame extends JFrame
{
public EventSourceFrame()
{
setTitle("EventSourceFrame");
final PainCountPanel mp = new PainCountPanel();
setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);
add(mp);
mp.addPropertyChangeListener(new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent e)
{
setTitle("EventSourceFrame-"+e.getNewValue());
}
}
);
}
public static final int DEFAULT_WIDTH = 650;
public static final int DEFAULT_HEIGHT = 350;
}
class PainCountPanel extends JPanel
{
public void paintComponent(Graphics g)
{
int oldPaintCount = paintCount;
paintCount++;
firePropertyChangeEvent(new PropertyChangeEvent(this,"paintCount",oldPaintCount,paintCount));
super.paintComponent(g);
}
public void addPropertyChangeListener(PropertyChangeListener e)
{
listenerList.add(PropertyChangeListener.class,e);
}
public void removePropertyChangeListener(PropertyChangeListener e)
{
listenerList.remove(PropertyChangeListener.class,e);
}
public void firePropertyChangeEvent(PropertyChangeEvent e)
{
EventListener[] listeners = listenerList.getListeners(PropertyChangeListener.class);
for(EventListener el:listeners)
((PropertyChangeListener)el).propertyChange(e);
}
private int paintCount;
}