鼠标事件
如果只希望用户能够点击按钮或菜单,那么就不需要显式地处理鼠标事件,鼠标操作将由用户界面中的各种组件内部处理,不过,如果希望用户能使用鼠标画图,就需要捕获鼠标移动,点击和拖动事件。
本节,我们将展示一个简单的图形编辑器应用,它允许用户在画布上放置、移动和擦除方块。
用户点击鼠标按钮时,将会调用三个监听器方法:鼠标第一次被按下时调用mousePressed,鼠标被释放时调用mouseReleased,最后调用mouseClicked,如果只对最终的点击事件感兴趣,就可以忽略前两个方法,以MouseEvent类对象作为参数,调用getX和getY方法可以获得鼠标被按下时鼠标指针所在的x和y坐标,想要区分单击,双击和三击,需要使用getClickCount方法。
鼠标在窗口移动时,窗口会收到一连串的鼠标移动事件,有两个独立的接口MouseListener和MouseMotionListener,这样做有利于提高效率,当用户移动鼠标时,会有大量鼠标事件,只关心鼠标点击(click)的监听器就不会被多余的鼠标移动事件所干扰。
这里给出测试程序将捕获鼠标动作事件,光标位于一个小方块之上时变成另一种形状(十字),这是使用Cursor类中的getPredefinedCursor方法完成的,以下列出了在Windows环境下这个方法使用常量以及相应的光标形状。
常量为:
常量 | |
DEFAULT_CURSOR | NE_RESIZE_CURSOR |
CROSSHAIR_CURSOR | E_RESIZE_CURSOR |
HAND_CURSOR | SE_RESIZE_CURSOR |
MOVE_CURSOR | S_RESIZE_CURSOR |
TEXT_CURSOR | SW_RESIZE_CURSOR |
WAIT_CURSOR | W_RESIZE_CURSOR |
N_RESIZE_CURSOR | NW_RESIZE_CURSOR |
MouseMotionListener类的mouseMoved方法:
public void mouseMoved(MouseEvent event){
if(find(event.getPoint())==null){
setCursor(Cursor.getDefaultCursor());
}else{
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
}
如果用户在移动鼠标的同时按下鼠标,就会生成mouseDragged调用而不是mouseMoved调用。在测试 应用中,用户可以拖动光标下的小方块,我们只是更新当前拖动的方块,让它在鼠标位置居中,然后,重新绘制画布,以显示新的鼠标位置。
还有另外两个鼠标事件方法:mouseEnterd和mouseExited,这两个方法会在鼠标进入或移除组件时被调用,监听鼠标点击事件,mouseClicked。
案例:点击鼠标新建小方块,可拖动方块,双击删除方块
package mouse;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class MouseComponent extends JComponent {
public static void main(String[] args) {
EventQueue.invokeLater(()->{
var frame = new JFrame();
frame.add(new MouseComponent());
frame.pack();
frame.setTitle("鼠标事件");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 200;
private static final int SIDELENGTH = 10;//边长10
private ArrayList<Rectangle2D> squares;
private Rectangle2D current;//这个正方形包含了鼠标的指针
public MouseComponent() {
squares = new ArrayList<>();
current = null;
addMouseListener(new MouseHandler());
addMouseMotionListener(new MouseMotionHandler());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
}
@Override
protected void paintComponent(Graphics g) {
var g2 = (Graphics2D)g;
//画所有的正方形
for (Rectangle2D r : squares) {
g2.draw(r);
}
}
public Rectangle2D find(Point2D p) {
for (Rectangle2D r : squares) {
if (r.contains(p)) return r;
}
return null;
}
public void add(Point2D p) {
double x = p.getX();
double y = p.getY();
current = new Rectangle2D.Double(x-SIDELENGTH/2,y-SIDELENGTH/2,SIDELENGTH,SIDELENGTH);
squares.add(current);
repaint();
}
public void remove(Rectangle2D s) {
if(s == null) return;
if(s == current) current = null;
squares.remove(s);
repaint();
}
private class MouseHandler extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
current = find(e.getPoint());
if(current==null) add(e.getPoint());
}
@Override
public void mouseClicked(MouseEvent e) {
current = find(e.getPoint());
if(current!=null&&e.getClickCount()>=2) remove(current);
}
}
private class MouseMotionHandler implements MouseMotionListener {
@Override
public void mouseMoved(MouseEvent e) {
if(find(e.getPoint())==null) setCursor(Cursor.getDefaultCursor());
else setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
@Override
public void mouseDragged(MouseEvent e) {
if(current!=null) {
int x = e.getX();
int y = e.getY();
current.setFrame(x-SIDELENGTH/2,y-SIDELENGTH/2,SIDELENGTH,SIDELENGTH);
repaint();
}
}
}
}
java.awt.event.MouseEvent 1.1
- int getX()
- int getY()
- Point getPoint(),返回事件发生时点(鼠标点击位置)相对于事件源组件的左上角x和y坐标。
- int getClickCount(),返回与事件相关的鼠标连击次数(连击时间与系统有关)。
java.awt.Component 1.0
- public void setCursor(Cursor cursor),为指定光标设置光标图像。