本文主要是介绍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()中进行处理了.
这篇关于Aexi(5)-Glyph的事件处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!