如何将VBA日历窗体选择的日期传递回Excel工作表指定单元格
问题:Excel VBA日历窗体选择日期后传递值到指定单元格
我参考了一篇关于Excel VBA添加日历的问答,运行后基本满足需求,现在想修改代码实现:选择日期后将其传递到指定单元格并关闭日历窗体。我对VBA了解有限,不清楚#if和if的区别,上一次接受正式编程培训还是1992年的Turbo Pascal,仅了解全局变量和局部变量的概念。
现有代码实现
Sheet2「Forecast」代码
Private Sub StartDatePicker_Click() Dim StartDate As Date CalendarModule.Launch (StartDate) Me.Cells(5, 2) = StartDate End Sub Private Sub EndDatePicker_Click() Dim EndDate As Date CalendarModule.Launch (EndDate) Me.Cells(6, 2) = EndDate End Sub
CalendarModule代码
Sub Launch(dDate As Date) Set f = frmCalendar With f .Caltheme = ArcticBlue .LongDateFormat = "dddd dd. mmmm yyyy" '"dddd mmmm dd, yyyy" etc .ShortDateFormat = "yyyy/mm/dd" '"mm/dd/yyyy" or "d/m/y" etc .Show End With End Sub
frmCalendar代码
'~~> Insert Selected date Private Sub DTINSERT_Click() Dim PickedDate as Date If Len(Trim(Label6.Caption)) = 0 Then MsgBox "Please select a date first", vbCritical, "No date selected" Exit Sub End If '~~> Change the code here to insert date where ever you want 'PickedDate = Cdate(Label6.Caption) MsgBox Label6.Caption, vbInformation, "Date selected" End Sub
我的问题
我完全不熟悉窗体操作,如何将PickedDate传递回CalendarModule.Launch,再传递到Sheet2.StartDatePicker_Click,并且能重复传递到Sheet2.EndDatePicker_Click中?
更新(24/09/29 11:20)
我在frmCalendar代码中添加了:
Public PickedDate as Date
CalendarModule代码修改为:
Sub Launch(dDate As Date) Set f = frmCalendar With f .Caltheme = ArcticBlue .LongDateFormat = "dddd dd. mmmm yyyy" '"dddd mmmm dd, yyyy" etc .ShortDateFormat = "yyyy/mm/dd" '"mm/dd/yyyy" or "d/m/y" etc .Show dDate = .PickedDate End With End Sub
现在dDate能获取到选择的日期值,但回到Sheet2代码时,StartDate的值变为0。我感觉Sub Launch (dDate as Date)的声明部分缺少了一些设置。
解决方案
问题核心是参数传递方式:VBA默认按ByVal(传值)传递参数,这意味着Launch过程里修改的dDate只是原变量的副本,不会影响Sheet2里的StartDate/EndDate。改成ByRef(传引用)就能让修改直接作用于原变量。
步骤1:修改CalendarModule的Launch过程
把参数声明改为ByRef dDate As Date,同时添加窗体资源释放逻辑:
Sub Launch(ByRef dDate As Date) Set f = frmCalendar With f .Caltheme = ArcticBlue .LongDateFormat = "dddd dd. mmmm yyyy" .ShortDateFormat = "yyyy/mm/dd" .Show dDate = .PickedDate End With ' 释放窗体资源 Unload f Set f = Nothing End Sub
步骤2:完善frmCalendar的DTINSERT_Click事件
将选中日期赋值给公共变量,并关闭窗体:
' 窗体模块顶部声明公共变量 Public PickedDate As Date '~~> 确认选择日期 Private Sub DTINSERT_Click() If Len(Trim(Label6.Caption)) = 0 Then MsgBox "请先选择日期", vbCritical, "未选择日期" Exit Sub End If ' 将选中日期存入公共变量 PickedDate = CDate(Label6.Caption) ' 隐藏窗体(保持对象状态以便读取变量) Me.Hide End Sub
步骤3:调整Sheet2的调用方式
调用时去掉括号(或用Call语句),避免隐式传值:
Private Sub StartDatePicker_Click() Dim StartDate As Date CalendarModule.Launch StartDate ' 去掉括号,或写成 Call CalendarModule.Launch(StartDate) Me.Cells(5, 2) = StartDate End Sub Private Sub EndDatePicker_Click() Dim EndDate As Date CalendarModule.Launch EndDate Me.Cells(6, 2) = EndDate End Sub
补充说明
ByValvsByRef:ByVal传递变量副本,修改副本不影响原变量;ByRef传递变量内存地址,修改参数会直接改变原变量的值,这正是你需要的场景。- 窗体关闭逻辑:用
Me.Hide而非Unload Me,确保Launch过程能读取到窗体的公共变量,读完后再手动Unload释放资源更稳妥。
内容的提问来源于stack exchange,提问作者Forward Ed
相关产品推荐
相关产品推荐

