随着社会的发展,各行各业都出现了很多的行业软件,这些软件由于长时间的酝酿,在业务上基本上都能够满足用户的使用要求,这样如何在激烈的行业竞争中获得头筹,就要求我们的软件既能够从业务上真正的解决用户面临的实际问题,还能够让用户用最简单易用的方式来完成,本文主要针对如何实现良好的用户体验来讨论。首先我们谈论一下用户最常用的输入法问题。
不管是Web应用,还是桌面应用,我们都会频繁的涉及到用户焦点切换的问题,比如常见一个用户信息输入窗体,用户可能会不断在姓名、住址、电话号码输入信息,而这些信息有很明显的特征:姓名一般为中文,电话号码为数字,这样用户需要不断的切换输入法,对于一次应用来说,你可能会觉得这个没什么,但是如果频繁的操作呢?比如她是一个人力部门的文员(她的职责就是录人员)?
因此我们迫切需要给用户提供最便利的切换方式,记住用户上次使用的输入法成为首选。
如何记住用户上次输入的输入法?
很多人第一个感觉就是使用持久化,没错!持久化是我们解决这个问题的根本方法,整体思路上大同小异:记录上次输入的输入法,保存到磁盘文件,下次装载窗体时初始化原有的输入法。
这样如何持久化?如何解决控件与输入法的对应关系就成了整个事情的核心。
一种笨方法:搞定每个界面上的控件,比如说Edit的 OnEnter、OnExit方法,在OnExit时记录其正在使用的输入法(GetKeyBoardLayout(0)),在OnEnter后激发原有的输入法(ActiveKeyBoardLayout)。没错这种方法可以解决问题,而且一般很多人上来就是这么想的,我也是这样,但是再仔细想想,有没有其他更优雅的方式来解决呢?很显然这种方法不是一个OCP的案例,而且一旦后面有新的功能的加入,也需要再搞一遍,代码多不是错,长的差不多就是你的错了!
也许看到这里有些人说,我做个公共函数或者类来负责处理这件事情不就OK了?确实,这是一种思路,可以减少重复的代码,如果我们采用这个笨方法,可以这样来优化一下。
再来看看这个问题,我们需要做的仅仅是在控件离开焦点时,记录其输入法,重新回来时,恢复输入法,这是一个典型的AOP的例子,我们需要一个切面来处理。说到这里,大家可能就明白我后面的思路了。对,我们可以采用Hook,Hook控件的这两个事件,一劳永逸的解决这个问题。
提供另外一种思路:不采用Hook,我们实现一个处理器,专门负责界面控件输入法的管理,当窗体创建时,我将窗体传递给这个“输入法管理的单件实例”,这个对象就通过算法枚举所有界面的控件,当然我们只找到所有最叶子的控件,也就是说子控件=0的控件。对于其,我们采用AOP的思想,偷换其OnEnter、OnExit事件。说白了,我们换的过程如下:
原始控件:edtName: TEdit; 事件:OnEnter = DoMyEnter;
我们将其事件换掉,挂上我们自己的事件: OnEnter = DoXXXEnter;
实际上 DoXXXEnter执行时的流程时先调用了 DoMyEnter,在触发我们的保存输入法操作,这是一个典型的三明治做法,其实也是AOP的一种。
好,这样做,唯一缺少一个就是如何记录控件的输入法了?这需要一个对应关系,如何定义控件唯一?
很多方法:自己定义格式,比如 模块名称-子模块名称-功能名称-控件名称, 能解决问题,但是唯一比较遗憾的是不利于未来的扩展,你需要不断的调整你的这个名称,加入新的名称。烦哪!
我想到了一个很好的方法:采用控件所在的层次来定义,将控件的名称和其所有父控件形成一个URL,这样就很好的解决了,而且可以写的很通用,太爽了。
举个例子: 窗体上一个edtName,它的URL为:
edtName.TPanel.TForm.基窗体Caption
好吧,有了这些基础,我们就可以很容易的在内存中使用一个单件实例管理所有控件URL对应的输入法了,至于持久化也就是你自己随便处理的问题了。
好的软件,不仅仅是完成功能,只有用的贴心才能让用户成为你的忠实客户!不断的购买你的产品!