揭秘本贴主题的时刻到了。
本贴的主题是用户界面设计,以日历窗体作为示例,主要为了解决以下两个问题:
- 用户界面的一致性问题。在Excel程序界面上弹出一个用户窗体,上面的控件样式都是那种90年代的控件模样,和其背后的Excel界面作为一个整体不够和谐。
- 第三方UI库依赖的问题。默认的用户界面控件是由FM20.DLL提供的,其它常见的像TreeView 6.0和ListView 6.0这些则是由MSCOMCTL.OCX提供的。前者Office软件自带,后者可能需要一番配置,并且分发XLSM文件给别人时,不能保证对方电脑上已经配置好了MSCOMCTL.OCX,尤其是在32位环境下开发,然后到64位环境使用的情况下(一开始MSCOMCTL.OCX是没有64位版本的,后来微软官方才发布了一个)。
上述问题其实也不算问题,真正触发本贴的是组合框控件ComboBox Control。组合框控件有一种模式就是只能从下拉列表选择,而不能在编辑框里输入。FM20.DLL所画的这种模式的组合框看起来很有问题:
图1 列表样式下的组合框
注意此时该组合框的Style属性已经设置为fmStyleDropDownList,但是其中的编辑按钮还有光标,并且不可输入文字。从用户体验的角度来看,这个是很反直觉的。
解决上述问题最直接的方法就是使用Windows系统自带的comctl32.dll里面的控件。先看和上面图1对比的效果图:
图2 系统自带组合框静止状态
图3 系统自带组合框展开状态
其背后的代码(主要部分)如下:
图4 组合框相关代码
一般来说,创建系统自带控件需要如下三个步骤:
- 获取父窗口句柄。一般是取用户窗体第一个子窗体的句柄。具体就是先用FindWindow函数来获取用户窗体的句柄,然后以该句柄传入FindWindowEx函数获取子窗体的句柄。
- 初始化控件类。调用InitCommonControlsEx函数来初始化所要创建的系统控件类。函数用法详见官网。
- 创建控件。调用CreateWindowEx函数来创建指定的控件窗口。支持的控件类型大致如下列表所示:
图5 系统自带控件类
剩下的,就是设置控件的文本、样式、颜色、字体这些了。
使用系统自带的控件比起VBA自带的控件有如下优点:
- 更好看。
- Windows系统自带,无需第三方UI库。
- 可选的控件类型更多。从上图可以看到,可创建的控件类型有20余种,而VBA自带的控件只有16种。
- 控件可自定义的属性更多。比如系统的文本框控件可以设置一个浅灰色提示文本,提示用户要输入的信息,当用户点击文本框时,提示文本会自动消失(有点像旧版QQ登录窗口的账号密码输入框)。
最后是,系统提供的控件类可以进一步地用VBA的类模块包装起来。如下方图片所示,用户窗体上共有7个控件,都是用系统的控件画的:
图6-1 初始界面,共7个控件
图6-2 点选日期界面
图6-3 点击确定按钮后,获取选中的日期
而这7个控件其实只有3类,分别是标签、日期时间选择和按钮,对应的VBA类模块分别是clsStatic、clsDateTimePicker和clsButton,其在用户窗体模块中的创建如下:
图7 VBA对系统控件的包装
以上就是本帖所要分享的东西——对UI有所追求的一个理念和实现方式。
|