ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: prome3

[分享] UI设计自制日历窗体(无需注册MSCOMCTL.OCX)

  [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-9 20:43 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
micch 发表于 2024-1-8 23:34
太难了,不容易。

还是图省事,用窗体糊弄做一个吧

省事是一方面,稳定性是另一方面。就我有限的经验来说,直接用VBA的内置窗体比起自己用API做一个窗体然后在上面做控件更稳定,因为自己做窗体的话,有太多消息要处理,做不好的话容易导致Office软件崩溃。

当然,做得好、做得对的话还是有巨大的好处的,毕竟所有的东西都建立在API之上,用API可以做到VBA以及Office默认提供的东西所做不到的。只是,需要的代码量会很多很多。一分钱一分货吧。

网上其实还有收费的日历控件。刚刚我看了一下,有一款(EXCalendar)做成了COM/ActiveX控件,支持很多函数,支持事件,价格1000+人民币,背后的源码据官网称是(去掉注释和空行后)72289行。

2楼还嫌代码量太大了,殊不知高效和安全的组件往往意味着更多行的代码。就好像开车需要系安全带一样,虽然麻烦些,但保证了安全,可以在道路车速限制内把车开得快一些。如果要在不系安全带的情况下保证安全,就只能开得慢一些。对应到程序上也一样,运行速度快且安全的代码往往也要求更大的代码量。嫌麻烦或者“省去”麻烦,必然要付出代价。

兴许是在EH论坛内待久了,看多了那些就只有一个Sub的 code snippets,就觉得我这日历背后的代码太多了。说实话我自己也很喜欢那种一个Sub解决问题的代码片段,但是在生产环境中,要稳定、高效且安全地完成一个功能,需要的代码真的太多太多了。

TA的精华主题

TA的得分主题

发表于 2024-1-15 10:31 | 显示全部楼层
本帖最后由 szdcp 于 2024-1-15 10:32 编辑
prome3 发表于 2024-1-2 23:58
各位,新版来了。

版本号1.0.4

大神您好!

             本人VBA菜鸟,套用您的日历控件,运行就崩溃(Office2019标准版),请帮忙看看是啥原因,谢谢!

PZHZ1.7z

56.1 KB, 下载次数: 17

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-15 23:15 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
szdcp 发表于 2024-1-15 10:31
大神您好!

             本人VBA菜鸟,套用您的日历控件,运行就崩溃(Office2019标准版),请帮忙看 ...

已做修正,请见附件。

PZHZ1.zip

65.27 KB, 下载次数: 49

TA的精华主题

TA的得分主题

发表于 2024-1-15 23:41 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2024-1-16 09:01 | 显示全部楼层
本帖最后由 szdcp 于 2024-1-16 09:04 编辑
prome3 发表于 2024-1-15 23:15
已做修正,请见附件。

非常感谢您的帮忙,但是点击文本框旁边的日历控件就一直转圈,没反映,不知道是啥原因,可不可以不要控件,点击文本框即弹出日历窗直接选择?请帮忙看看。谢谢您!

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-16 20:24 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
szdcp 发表于 2024-1-16 09:01
非常感谢您的帮忙,但是点击文本框旁边的日历控件就一直转圈,没反映,不知道是啥原因,可不可以不要控件 ...

现在应该可以了,请见附件。

原先加一个日历的小图标,是因为 UserForm2 在显示时会自动把焦点给到第一个文本框里面,这会立即自动触发日历的显示。从用户体验的角度,这个现象会很奇怪,所以用了一个日历小图标来手动点击显示。现在去掉小图标,在 UserForm2 初始化事件里面先把焦点给到确认按钮,解决了这个问题。

然后,借此楼层说一下1.0.4及1.0.6版本中导致Excel崩溃的那个bug:
有一个名称为 InitCommonControlsEx 的枚举类型,该名称和对应的API名称冲突了。需要做如下修改:
  1. Private Type InitCommonControlsEx
  2.     dwSize As Long
  3.     dwICC As Long
  4. End Type
复制代码
改为
  1. Private Type LPINITCOMMONCONTROLSEX
  2.     dwSize As Long
  3.     dwICC As Long
  4. End Type
复制代码
,VBA7 API声明改为
  1. Private Declare PtrSafe Function InitCommonControlsEx Lib "Comctl32" (ByRef picce As LPINITCOMMONCONTROLSEX) As Boolean
复制代码
VBA6-中的API做对应更改就行。最后是变量声明部分,
  1. Private Function CreateCalendar(ByVal WindowCaption As String) As Boolean

  2.     Dim picce As InitCommonControlsEx
  3.     Dim rc As RECT
复制代码
改为
  1. Private Function CreateCalendar(ByVal WindowCaption As String) As Boolean

  2.     Dim icce As LPINITCOMMONCONTROLSEX
  3.     Dim rc As RECT
复制代码
感谢楼上 @duhong2024 的肯定和支持!


以上。

PZHZ1.zip

65.23 KB, 下载次数: 50

TA的精华主题

TA的得分主题

发表于 2024-1-17 09:32 | 显示全部楼层
prome3 发表于 2024-1-16 20:24
现在应该可以了,请见附件。

原先加一个日历的小图标,是因为 UserForm2 在显示时会自动把焦点给到第 ...

大神您好!不知啥原因,您修改后的程序我还是无法使用,点击文本框就无响应然后EXCEL崩溃重启,算了我放弃了,感谢您的支持与帮助,谢谢您!

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-1-17 19:03 | 显示全部楼层
szdcp 发表于 2024-1-17 09:32
大神您好!不知啥原因,您修改后的程序我还是无法使用,点击文本框就无响应然后EXCEL崩溃重启,算了我放 ...

我这边运行起来没有任何问题,也是 Microsoft Office 2019(64位):
运行效果.gif

网上有很多很多不基于 WINDOWS API 的日历控件,可以真真正正彻彻底底保证稳定运行。论坛内有很多,国外的也有。

至于国外的我比较喜欢的一款是 Trevor Eyre 做的,它的最新版已放到附件里面方便下载(注:控件代码和说明、示例文档都是英文的)。


感谢以往的肯定!

CalendarForm v1.5.2.zip

229.13 KB, 下载次数: 59

TA的精华主题

TA的得分主题

发表于 2024-1-23 23:18 | 显示全部楼层
看插入里---最后-日期

samradapps_datepicker.zip

123.91 KB, 下载次数: 39

TA的精华主题

TA的得分主题

 楼主| 发表于 2024-2-14 16:00 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
揭秘本贴主题的时刻到了。


本贴的主题是用户界面设计,以日历窗体作为示例,主要为了解决以下两个问题:
  • 用户界面的一致性问题。在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 列表样式下的组合框

图1 列表样式下的组合框

注意此时该组合框的Style属性已经设置为fmStyleDropDownList,但是其中的编辑按钮还有光标,并且不可输入文字。从用户体验的角度来看,这个是很反直觉的。



解决上述问题最直接的方法就是使用Windows系统自带的comctl32.dll里面的控件。先看和上面图1对比的效果图:

图2 系统自带组合框静止状态

图2 系统自带组合框静止状态

图3 系统自带组合框展开状态

图3 系统自带组合框展开状态

其背后的代码(主要部分)如下:

图4 组合框相关代码

图4 组合框相关代码

一般来说,创建系统自带控件需要如下三个步骤:

  • 获取父窗口句柄。一般是取用户窗体第一个子窗体的句柄。具体就是先用FindWindow函数来获取用户窗体的句柄,然后以该句柄传入FindWindowEx函数获取子窗体的句柄。
  • 初始化控件类。调用InitCommonControlsEx函数来初始化所要创建的系统控件类。函数用法详见官网。
  • 创建控件。调用CreateWindowEx函数来创建指定的控件窗口。支持的控件类型大致如下列表所示:

图5 系统自带控件类

图5 系统自带控件类

剩下的,就是设置控件的文本、样式、颜色、字体这些了。


使用系统自带的控件比起VBA自带的控件有如下优点:

  • 更好看。
  • Windows系统自带,无需第三方UI库。
  • 可选的控件类型更多。从上图可以看到,可创建的控件类型有20余种,而VBA自带的控件只有16种。
  • 控件可自定义的属性更多。比如系统的文本框控件可以设置一个浅灰色提示文本,提示用户要输入的信息,当用户点击文本框时,提示文本会自动消失(有点像旧版QQ登录窗口的账号密码输入框)。


最后是,系统提供的控件类可以进一步地用VBA的类模块包装起来。如下方图片所示,用户窗体上共有7个控件,都是用系统的控件画的:

图6-1 初始界面,共7个控件

图6-1 初始界面,共7个控件

图6-2 点选日期界面

图6-2 点选日期界面

图6-3 点击确定按钮后,获取选中的日期

图6-3 点击确定按钮后,获取选中的日期

而这7个控件其实只有3类,分别是标签、日期时间选择和按钮,对应的VBA类模块分别是clsStatic、clsDateTimePicker和clsButton,其在用户窗体模块中的创建如下:

图7 VBA对系统控件的包装

图7 VBA对系统控件的包装


以上就是本帖所要分享的东西——对UI有所追求的一个理念和实现方式。


您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-19 07:39 , Processed in 0.049415 second(s), 7 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表