vba - Excel 用户表单输入失控
问题描述
我有一个名为SlideSorterStart的用户表单的以下代码:
Private Sub Okay1_Click()
Dim startOn As Integer
startOn = SlideSorterStart.Input1
Unload SlideSorterStart
End Sub
Okay1是下面的确定按钮,而Input1是文本框的名称。
我在模块中使用变量startOn
如下:
Sub SlideSorter(ByVal control As IRibbonControl)
Dim first As Long: first = ActiveWindow.Selection.SlideRange.SlideIndex
Dim last As Long: last = ActivePresentation.Slides.Count
SlideSorterStart.Show
For i = first To last
With ActivePresentation.Slides(i)
On Error Resume Next
.Shapes("Squort").Delete
Dim square As Shape
Set square = .Shapes.AddShape(msoShapeRectangle, 400, 360, 150, 150)
With square
.Name = "Squort"
With .TextFrame.TextRange
.Text = startOn
End With ' TextFrame
End With ' Square itself
End With
startOn = startOn + 1
Next i
End Sub
出于某种原因,它没有给出等于填充到用户窗体中的数字的输出,而是始终从 0 开始第一个输出,然后在下次运行该函数时,以幻灯片的数量递增。
例如,如果有 5 张幻灯片要放置此框,那么第一次,幻灯片 1 将有一个 0。下一次在 5。然后是 10,依此类推。
这是什么原因造成的?
解决方案
UserForm1.Show再次来袭!
您正在显示表单的默认实例,并且在该表单的代码中,您指的是该表单的默认实例:
Dim startOn As Integer
startOn = SlideSorterStart.Input1
Unload SlideSorterStart
标识符在SlideSorterStart
这里有双重用途:它是一个UserForm
类的数据类型名称,它是一个以该表单类命名的项目范围的全局对象变量。
您永远不应该在该表单的代码隐藏中引用该表单的默认实例。使用Me
保留的标识符来引用当前实例(可以是默认的,也可以是其他的)。
startOn = Me.Input1
无论您做什么,都不要Unload
在显示该表单时使用该表单,并且您需要稍后访问其实例状态(例如,用户提供的控件内容)。
更改表单的代码,如下所示:
Option Explicit
Private StartAtSlideIndex As Long
Private HasCancelled As Boolean
Public Property Get StartSlideIndex() As Long
StartSlideIndex = StartAtSlideIndex
End Property
Public Property Get IsCancelled() As Boolean
IsCancelled = HasCancelled
End Property
Private Sub Input1_Change()
On Error Resume Next 'index will be 0 if can't convert text value
StartAtSlideIndex = CLng(Input1.Text)
On Error GoTo 0
End Sub
Private Sub Okay1_Click()
Me.Hide
End Sub
Private Sub OnCancel()
HasCancelled = True
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
OnCancel
End If
End Sub
请注意,在表单的代码隐藏中,表单不会被销毁,或者有任何机会被销毁:这就是为什么我们需要处理QueryClose
, 以防止在用户通过单击红色“X”取消对话框时表单实例被销毁" 按钮 - 因为用户总是可以通过这样做来取消任何对话框,所以显示表单的代码需要知道对话框是否被取消。如果您决定添加一个Cancel按钮,您只需使其Click
句柄调用该OnCancel
方法。
所以,不管表单是如何关闭的,我们只需要Hide
它,然后让调用代码销毁它。
SlideSorterStart.Show
这显示了表单的默认实例。避免这样做。
With New SlideSorterStart '<~ form instance gets created here
.Show
If .IsCancelled Then Exit Sub
Dim startOn As Long
startOn = .StartSlideIndex
End With '<~ form instance gets destroyed here
表单的Initialize
处理程序(如果存在)将被调用New SlideSorterStart
(在对象引用被产生到With
块之前);如果存在,Terminate
表单的处理程序将在 处调用End With
。
当您使用表单的默认实例时,这两个关键对象生命周期事件何时被触发是不确定的:这就是为什么您需要不惜一切代价避免它,并完全控制您正在使用的对象,以及何时以及如何使用你正在摧毁他们。
你得到的原因0
是因为表单正在系统地卸载自己;默认实例与其状态一起被销毁,然后在下次引用它时再次重新创建,但随后使用默认初始状态重新创建,...这意味着您实际上丢失了用户的输入。
推荐阅读
- android - Android 约束布局:如何将视图与另一个视图垂直对齐
- arrays - 使用 Google Apps 脚本比较两个整数数组
- excel - 试图提高我的 VBA 代码的质量和效率
- javascript - 如何使我的 if 语句正确评估?
- javascript - 如何对特定数字中的数字进行分类?
- javascript - 查找字符串中重复次数最多的第一个字母
- android - echo $ANDROID_HOME 在 Mac 中返回空白
- ionic4 - Ionic 4:如何为选定的 ion-tab-button 设置边框?
- node.js - Sequelize query where or is failed with empty error
- cakephp - 在 cakephp 的同一查询中使用多个数据库