Excel 用户表单输入失控
Excel Userform Input going haywire
我有以下代码用于名为 SlideSorterStart 的用户表单:
Private Sub Okay1_Click()
Dim startOn As Integer
startOn = SlideSorterStart.Input1
Unload SlideSorterStart
End Sub
Okay1是下面的确定按钮,而Input1是文本框的名称。
我在模块中使用变量startOn
如下:
Sub SlideSorter(ByVal 控件作为 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,依此类推。
这是什么原因造成的?
您的 startOn
变量必须在模块级别声明为 Public。
它仅采用您为 Okay1_Click()
事件设置的值。
您还应该使用 Option Explicit' in the module where
Sub SlideSorter' 运行。这样,将引发有关 startOn
变量未声明的错误。
UserForm1.Show再出击!
您正在显示表单的 默认实例 ,并且在该表单的代码中,您指的是该表单的默认实例:
Dim startOn As Integer
startOn = SlideSorterStart.Input1
Unload SlideSorterStart
SlideSorterStart
标识符在这里有双重用途:它是UserForm
的数据类型名称class,和它是一个项目-scoped global object variable named after that form class.
您永远不应在表单的代码隐藏中引用表单的默认实例。使用 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
块之前);如果存在,将在 End With
.
处调用表单的 Terminate
处理程序
当您使用表单的默认实例时,这两个关键对象生命周期事件的确切时间是不确定的:这就是为什么您需要不惜一切代价避免它,并完全控制您正在使用的对象,以及何时以及如何销毁它们。
您得到 0
的原因是表单正在系统地自行卸载;默认实例与其状态一起被销毁,然后在下次引用它时再次重新创建它,但随后它以默认初始状态重新创建,...这意味着您实际上失去了用户的输入。
我有以下代码用于名为 SlideSorterStart 的用户表单:
Private Sub Okay1_Click()
Dim startOn As Integer
startOn = SlideSorterStart.Input1
Unload SlideSorterStart
End Sub
Okay1是下面的确定按钮,而Input1是文本框的名称。
我在模块中使用变量startOn
如下:
Sub SlideSorter(ByVal 控件作为 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,依此类推。
这是什么原因造成的?
您的 startOn
变量必须在模块级别声明为 Public。
它仅采用您为 Okay1_Click()
事件设置的值。
您还应该使用 Option Explicit' in the module where
Sub SlideSorter' 运行。这样,将引发有关 startOn
变量未声明的错误。
UserForm1.Show再出击!
您正在显示表单的 默认实例 ,并且在该表单的代码中,您指的是该表单的默认实例:
Dim startOn As Integer
startOn = SlideSorterStart.Input1
Unload SlideSorterStart
SlideSorterStart
标识符在这里有双重用途:它是UserForm
的数据类型名称class,和它是一个项目-scoped global object variable named after that form class.
您永远不应在表单的代码隐藏中引用表单的默认实例。使用 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
块之前);如果存在,将在 End With
.
Terminate
处理程序
当您使用表单的默认实例时,这两个关键对象生命周期事件的确切时间是不确定的:这就是为什么您需要不惜一切代价避免它,并完全控制您正在使用的对象,以及何时以及如何销毁它们。
您得到 0
的原因是表单正在系统地自行卸载;默认实例与其状态一起被销毁,然后在下次引用它时再次重新创建它,但随后它以默认初始状态重新创建,...这意味着您实际上失去了用户的输入。