Aexi(5)-Glyph的事件处理

         这次的博客主要实现这样一个功能,当点击文档中的某个点时,调整光标Caret的位置.

         那么到底如何实现这样的功能呢?刚开始的时候我们肯定先考虑比较直接一点的方法.先使用一个controller类来接收鼠标点击事件.在相应的处理方法中可以拿到鼠标点击的坐标.然后遍历所有的page,row,basicGlyph来获得鼠标点击的具体图元,然后再去做具体的处理.

         但是我写了一会之后,马上就否决了这个方案,因为这个方案需要在同一个事件处理函数处理的代码实在太多了,比如我们需要给caret设置frame.最直接的方法就是挨个遍历Glyph比较点击点和Glyph的frame,还要根据是偏左偏右来决定caret是放在左边还是右边.

         这是点击到了Glyph的情况,如果点击到了某一行的空白区域,就要把caret设置到最右边.如果点击了空行,则更加复杂,因为仅仅设置frame是不可以的,还是更改caret的文档索引,以便于用户在caret所在的位置插入文字.

         最最关键的是如果后期我们要对鼠标的点击事件做进一步扩充的话,那么这个函数就会无休止的变得臃肿,因此肯定要进行封装.把和每个图元相关的方法封装到图元自己的身上去.

         具体的设计是怎样的呢?首先我们给GlyphImpl类增加的一个函数public Boolean hitRect(x,y),传入一个坐标值,返回该坐标点是否落在本对象内.

具体函数实现代码如下:

public boolean hitRect(int x, int y) {
    Frame frame = getFrame();
    if (x > (frame.getX() + frame.getWidth()) || x < frame.getX())
        return false;
    return !(y > (frame.getY() + frame.getHeight()) || y < frame.getY());
}

整个文档结构是分层级的,每个层级的对象都应该有机会处理到点击事件,并且上层决定事件时候分发给下层,下层接受到事件之后,还要告诉上层是否已经处理完了,如果没有处理完应该由上层继续协助处理.

写到这里大家应该就非常清楚了,这样的设计就是借鉴了Android系统的事件处理机制.

         我们给Glyph添加如下的的几个方法:

@Override
public boolean dispatchClickEvent(MouseEvent e) {
    if (interceptClickEvent(e))
        return true;
    return onClickEvent(e);
}

@Override
public boolean onClickEvent(MouseEvent e) {
    return false;
}

@Override
public boolean interceptClickEvent(MouseEvent e) {
    return false;
}

这是GlyphImpl的默认实现,主要针对的是基本图元.从dispatchClickEvent()可以看出,首先询问了本类的interceptClickEvent函数是否截断该事件的传递,如果不截断,就发送给本类的onclickEvent()函数进行处理.

下面是GlyphImplGroup的默认实现,主要区别在于dispatchClickEvent()方法.

@Override
public boolean dispatchClickEvent(MouseEvent e) {
    if (interceptClickEvent(e))
        return true;
    List<GlyphImpl> children = getChildren();
    Glyph toBeHandledGlyph = null;
    for (GlyphImpl glyph : children) {
        if (glyph.hitRect(e.getX(), e.getY())) {
            toBeHandledGlyph = glyph;
            break;
        }
    }
    //toBeHandledGlyph可能为空
    if (toBeHandledGlyph == null)
        //进入这里就表示,点到空白位置了,这里需要区别对待,如果是row就要把caret放到row的最右边,如果是page就要把caret放到最后一行.
        //应该直接分发给本类对象的onClickEvent()方法
        return onClickEvent(e);
    if (!toBeHandledGlyph.dispatchClickEvent(e))
        return onClickEvent(e);
    return true;
}

从函数的具体实现可以看出,首先询问本类的interceptEvent()方法是否截断,如果不截断,就遍历子图元调用hitrect()方法找到具体击中的子图元.如果没有找到子图元就发送给本类的onclickEvent()方法.如果找到了就根据子图元的dispatch方法的返回值决定是否还要继续分发给本类onclickEvent();

这样就可以实现上层的对象通过intercept()函数进行控制是否发送事件给下层,下层通过onclickEvent()决定事件是否要抛给上层.

经过这样的设计,就使得复杂的点击事件处理变得简单了,当需要扩充时,可以根据具体的业务逻辑,找到对应的对象并在其onclickEvent()中进行处理了.





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值