自从开始接触Symbian,就觉得Symbian的UI编程非常困难。难在哪呢?因为不知道Symbian控件的运行机制,所以在编程过程中常会出现一些莫名其妙的错误,让人摸不着头脑。
也许有人会说,SDK提供了一些UI的例子,可以进行参考。这话倒是不错,但问题是例子中对相应控件的语句的注释不够充分,最后还是被控件的语句弄得云里雾里的,也许写例子的作者自己觉得,在代码之中的逻辑是非常简单的,所以注释就大大的省略了。但对于像小弟这种缺少对Symbian平台内核机制认识的人来说,只能通过Debug一步一步跟了。
今天正好碰到个需求,需要做个类似控制台的控件,将程序的运行状态通过文本的方式显示在手机屏幕上,因为其显示的字符只局限于英文和数字,所以就想到自定义一个继承于CEikEdwin的文本框控件(CEikEdwin是Symbian中所有文本框类的基类),应该能满足需求。于是通过对控件从创建到使用再到析构的过程,进行了一些分析。现将得到的结果记录在下面,与大家分享。
首先,因为CStatusMonitor是继承于CEikEdwin, 而CEikEdwin是个控件类,所以,CStatusMonitor也是个控件。既然是控件,按照Symbian程序的架构,控件就得放在容器里,所以CStatusMonitor的实例化过程就放在容器的ConstructL中了。
这里需要注意,对于容器来说,每个容器都必须有个窗口,要么是通过CreateWindowL()自己建一个,要么就是通过SetContainerWindowL()用别人已经建好的。这一步,必须放在所有容器ConstructL()函数中的第一步。
然后接着讲CStatusMonitor的创建过程:既然是Symbian自定义控件,那就用Symbian的传统构造方法——二阶段构造:先通过:
CStatusMonitor *self = new (ELeave) CStatusMonitor;
创建一个CStatusMonitor的实例,然后通过调用CStatusMonitor的ConstructL()方法,进行真是构造。这里着重讲一下ConstructL()方法中需要做的事和顺序:
首先,因为Symbian文本框控件的特殊性,上一步骤中的实例是一个还没有初始化完的实例,因此需要调用CEikEdwin::ConstructL()方法,完成该实例的构造,这也就是CStatusMonitor的ConstructL()中的第一步。CEikEdwin::ConstructL()的说明和参数的解释在SDK的文档中有,在此就不作解释了。
接着,为了能使CStatusMonitor能够接受用户通过按下方向键进行光标移动的响应,需要通过SetFocus()将程序的焦点给CStatusMonitor。
然后,因为CStatusMonitor是放在容器中的控件,因此需要使用容器的窗口作为自己的窗口,所以需要把容器的引用传给CStatusMonitor,好让CStatusMonitor在ConstructL中通过调用SetContainerWindowL()方法设置控件的父窗口。
此时,如果需要给文本框加上滑动块,则可以通过调用CreateScrollBarFrameL()->SetScrollBarVisibilityL方法进行设置,设置完后别忘了通过调用UpdateScrollBarsL对滑动块进行更新。至此,CStatusMonitor的ConstructL完成。
接着回到容器的ConstructL()中,继续执行ActivateL()和SetRect()函数,函数的作用请参见SDK,在此不详细说明。
值得注意的是,在执行了ActivateL()后,程序会调用容器的CountComponentControls()函数,获取当前容器中的控件数,别忘了更新这个数目哦;还需要注意的是容器的ComponentControl函数,该函数在CountComponentControls函数调用完后被调用,别忘了在相应的case中加上相应的控件指针,不然会报KERN-EXEC 3空指针错误。
最后在SetRect()被调用后,容器的SizeChanged()函数会被调用,在这里,需要调用控件的SetExtent()函数,设置控件出现的位置和尺寸大小,如果有滑块,别忘了设置滑块大小,设置完后再次调用UpdateScrollBarsL对控件进行更新。
之后就是Symbian程序框架的事情了,编译、运行,文本框就可以显示在手机屏幕上了。