绘图板程序设计及其具体实现 第三篇

工具包详细解析

(二) 输入处理工具类

SafeKeyboardInput类

SafeKeyboardInput类是一个安全的键盘输入处理类,实现了KeyListener接口。当由于种种原因导致帧速率过低时,普通的键盘输入处理可能会漏掉一些事件。本类中使用将所有接受到的键盘事件储存在一个数组中,当需要处理的时候再按照顺序依次处理所有的键盘事件,因此不会漏掉任何键盘事件。但是这样也存在一个问题,如果之前接受到的键盘事件不需要处理,则需要调用flush函数来清空之前接收到的键盘事件。

  • SafeKeyboardInput类字段一览表
修饰符类型名称说明
privateenumEventType表示键盘事件类型的枚举类
privateclassEvent表示键盘事件的类
privateLinkedList< Event>eventThread接收到的键盘事件列表
privateLinkedList< Event>gameThread正在处理的键盘事件列表
privateEventevent当前正在处理的键盘事件
privateint[]polled表示键盘中所有键的数组(共256个)
  • SafeKeyboardInput类方法一览表
修饰符返回值函数名参数说明
publicSafeKeyboardInput()默认构造函数
public synchronizedbooleankeyDown(int keyCode)返回一个键是否被按下
public synchronizedbooleankeyDownOnce(int keyCode)返回一个键是否有且被按下一次
public synchronizedbooleanprocessEvent()处理事件,返回是否还有时间未处理
publicCharactergetKeyTyped()返回单击的字符
public synchronizedvoidpoll()每帧调用,刷新待处理的键盘事件
public synchronizedvoidflush()清除之前未处理的所有事件
public synchronizedvoidkeyPressed(KeyEvent e)键盘按下事件触发
public synchronizedvoidkeyReleased(KeyEvent e)键盘释放事件触发
public synchronizedvoidkeyTyped(KeyEvent e)键盘单击事件触发
  • SafeKeyboardInput类源代码
package Rendering.utils;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.LinkedList;

public class SafeKeyboardInput implements KeyListener {
    private enum EventType {
        PRESSED,
        RELEASED,
        TYPED,
    }

    private class Event {
        KeyEvent event;
        EventType type;

        public Event(KeyEvent event, EventType type) {
            this.event = event;
            this.type = type;
        }
    }

    private LinkedList<Event> eventThread = new LinkedList<Event>();
    private LinkedList<Event> gameThread = new LinkedList<Event>();
    private Event event = null;
    private int[] polled;

    public SafeKeyboardInput() {
        polled = new int[256];
    }

    public synchronized boolean keyDown(int keyCode) {
        return keyCode == event.event.getKeyCode() && polled[keyCode] > 0;
    }

    public synchronized boolean keyDownOnce(int keyCode) {
        return keyCode == event.event.getKeyCode() && polled[keyCode] == 1;
    }

    public synchronized boolean processEvent() {
        event = gameThread.poll();
        if (event != null) {
            int keyCode = event.event.getKeyCode();
            if (keyCode >= 0 && keyCode < polled.length) {
                if (event.type == EventType.PRESSED) {
                    polled[keyCode]++;
                } else if (event.type == EventType.RELEASED) {
                    polled[keyCode] = 0;
                }
            }
        }
        return event != null;
    }

    public Character getKeyTyped() {
        if (event.type != EventType.TYPED) {
            return null;
        } else {
            return event.event.getKeyChar();
        }
    }

    public synchronized void poll() {
        LinkedList<Event> swap = eventThread;
        eventThread = gameThread;
        gameThread = swap;
    }

    public synchronized void flush() {
        eventThread = new LinkedList<Event>();
        gameThread = new LinkedList<Event>();
    }

    public synchronized void keyPressed(KeyEvent e) {
        eventThread.add(new Event(e, EventType.PRESSED));
    }

    public synchronized void keyReleased(KeyEvent e) {
        eventThread.add(new Event(e, EventType.RELEASED));
    }

    public synchronized void keyTyped(KeyEvent e) {
        eventThread.add(new Event(e, EventType.TYPED));
    }
}

RelativeMouseInput类

RelativeMouseInput类是一个既可以处理绝对鼠标事件,还可以处理相对鼠标事件的鼠标事件处理类,实现了MouseListener接口, MouseMotionListener接口和MouseWheelListener接口。当设置relative字段为false时,处理绝对鼠标事件;设置relative字段为true时,处理相对鼠标事件。

  • RelativeMouseInput类字段一览表
修饰符类型名称说明
private static finalintBUTTON_COUNT表示鼠标所有按键的数目(3)
privatePointmousePos鼠标当前帧的位置
privatePointcurrentPos鼠标的实时位置
privateboolean[]mouse存储鼠标的按键是否被按下的数组
privateint[]polled表示鼠标所有键的数组
privateintnotches鼠标滚轮的转动距离
privateintpolledNotches当前帧鼠标滚轮的转动距离
privateintdx鼠标相对上一帧移动的x值
privateintdy鼠标相对上一帧移动的y值
privateRobotrobot自动实现移动鼠标
privateComponentcomponent鼠标所在的组件
privatebooleanrelative处理绝对或相对鼠标事件
  • RelativeMouseInput类方法一览表
修饰符返回值函数名参数说明
publicRelativeMouseInput(Component component)构造函数
public synchronizedvoidpoll()每帧调用,刷新当前帧的鼠标位置和滚轮位置
public synchronizedbooleanisRelative()返回是否为相对鼠标事件
public synchronizedvoidsetRelative(boolean relative)更改绝对/相对鼠标事件
public synchronizedPointgetPosition()返回鼠标当前帧的绝对位置/相对上一帧的位置
public synchronizedintgetNotches()返回当前帧鼠标滚轮的转动距离
public synchronizedbooleanbuttonDown(int button)返回一个键是否被按下
public synchronizedbooleanbuttonDownOnce(int button)返回一个键是否有且被按下一次
public synchronizedvoidmousePressed(MouseEvent e)鼠标按下事件触发
public synchronizedvoidmouseReleased(MouseEvent e)鼠标释放事件触发
publicvoidmouseClicked(MouseEvent e)鼠标单击事件触发
public synchronizedvoidmouseEntered(MouseEvent e)鼠标进入事件触发
public synchronizedvoidmouseExited(MouseEvent e)鼠标移出事件触发
public synchronizedvoidmouseDragged(MouseEvent e)鼠标拖动事件触发
public synchronizedvoidmouseMoved(MouseEvent e)鼠标移动事件触发
public synchronizedvoidmouseWheelMoved(MouseWheelEvent e)
privatePointgetComponentCenter()返回鼠标所在的组件
privatevoidcenterMouse()移动鼠标到所在组件的中央
publicvoidmoveMouse(Vector2f mousePos)移动鼠标到组件的指定位置
  • RelativeMouseInput类源代码
package Rendering.utils;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class RelativeMouseInput
        implements MouseListener, MouseMotionListener, MouseWheelListener {
    private static final int BUTTON_COUNT=3;
    private Point mousePos;
    private Point currentPos;
    private boolean[] mouse;
    private int[] polled;
    private int notches;
    private int polledNotches;
    private int dx, dy;
    private Robot robot;
    private Component component;
    private boolean relative;

    public RelativeMouseInput(Component component) {
        this.component = component;
        try {
            robot = new Robot();
        } catch (Exception e) {
            e.printStackTrace();
        }
        mousePos = new Point(0, 0);
        currentPos = new Point(0, 0);
        mouse = new boolean[BUTTON_COUNT];
        polled = new int[BUTTON_COUNT];
    }

    public synchronized void poll(){
        if (isRelative()) {
            mousePos = new Point(dx, dy);
        } else {
            mousePos = new Point(currentPos);
        }
        dx = dy = 0;
        polledNotches = notches;
        notches = 0;
        for (int i = 0; i < mouse.length; i++) {
            if (mouse[i]) {
                polled[i]++;
            } else {
                polled[i] = 0;
            }
        }
    }

    public synchronized boolean isRelative() {
        return relative;
    }

    public synchronized void setRelative(boolean relative) {
        this.relative = relative;
        if (relative) {
            centerMouse();
        }
    }

    public synchronized Point getPosition() {
        return mousePos;
    }

    public synchronized int getNotches() {
        return polledNotches;
    }

    public synchronized boolean buttonDown(int button) {
        return polled[button-1]>0;
    }

    public synchronized boolean buttonDownOnce(int button) {
        return polled[button-1]==1;
    }

    public synchronized void mousePressed(MouseEvent e) {
        int button=e.getButton()-1;
        if (button >= 0 && button < mouse.length) {
            mouse[button] = true;
        }
    }

    public synchronized void mouseReleased(MouseEvent e) {
        int button=e.getButton()-1;
        if (button >= 0 && button < mouse.length) {
            mouse[button] = false;
        }
    }

    public void mouseClicked(MouseEvent e) {
        //Not needed
    }

    public synchronized void mouseEntered(MouseEvent e) {
        mouseMoved(e);
    }

    public synchronized void mouseExited(MouseEvent e) {
        mouseMoved(e);
    }

    public synchronized void mouseDragged(MouseEvent e) {
        mouseMoved(e);
    }

    public synchronized void mouseMoved(MouseEvent e) {
        if (isRelative()) {
            Point p = e.getPoint();
            Point center = getComponentCenter();
            dx += p.x - center.x;
            dy += p.y - center.y;
            centerMouse();
        } else {
            currentPos = e.getPoint();
        }
    }

    public synchronized void mouseWheelMoved(MouseWheelEvent e) {
        notches += e.getWheelRotation();
    }

    private Point getComponentCenter() {
        int w = component.getWidth();
        int h = component.getHeight();
        return new Point(w / 2, h / 2);
    }

    private void centerMouse() {
        if (robot != null && component.isShowing()) {
            Point center = getComponentCenter();
            SwingUtilities.convertPointToScreen(center, component);
            robot.mouseMove(center.x, center.y);
        }
    }

    public void moveMouse(Vector2f mousePos) {
        if (robot != null && component.isShowing()) {
            Point tmp = new Point((int) mousePos.x, (int) mousePos.y);
            SwingUtilities.convertPointToScreen(tmp, component);
            robot.mouseMove(tmp.x, tmp.y);
        } else {
            JOptionPane.showMessageDialog(
                    component, "Can not support similar!!!",
                    "Warning", JOptionPane.INFORMATION_MESSAGE
            );
        }
    }
}

更多:

第一篇
第二篇
第三篇
第四篇
第五篇
第六篇
第七篇
最终篇
源代码

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值