用户窗体和范围
UserForm and Range
我有一个 Excel sheet,其中 D 列(第 4 列)是每一行的下拉列表,有 2 个选项:
- 是
- 没有
当我单击“否”时,会弹出一个用户表单,其中包含一个简单的 "text zone" 要求输入一个值和一个 "Submit button" 进行验证。
单击 "Submit button" 时,我希望将 "text zone" 中的值应用到右侧的单元格中:offset(0,1).
示例:D5:"No" -> "Enters 5 in Userform" -> E5:“5”
到目前为止,这是我的代码:
工作sheet:
Private Sub Worksheet_Change(ByVal Target As Range)
If ActiveCell.Column = 4 Then
If ActiveCell.Value = "no" Then
UserForm1.Show
End If
End If
End Sub
用户表单:
Private Sub CommandButton1_Click()
ActiveCell.Offset(0, 1).Value = TextBox1.Value
UserForm1.Hide
End Sub
如果我将 UserForm1.Hide 放在 ActiveCell 之前,它会执行我想要的操作,但用户窗体不会关闭。
如果我取出 ActiveCell,用户窗体将关闭,但我似乎无法同时使两者工作。
您正在更改 Worksheet_Change 处理程序 中的单元格 ,这意味着如果您没有阻止 UI 的表单,您d 快速将调用堆栈和 运行 炸成 "Out of stack space" 错误,也称为... 堆栈溢出.
您需要防止 Worksheet_Change
处理程序递归调用自身。
这可以通过在进行更改之前关闭 Application.EnableEvents
并在之后重新打开来完成:
Application.EnableEvents = False
ActiveCell.Offset(0, 1).Value = TextBox1.Value
Application.EnableEvents = True
现在,看看这有什么问题?表单如何知道它是从 Worksheet_Change
处理程序调用的,因此它需要切换 Application.EnableEvents
?它不知道 - 现在,它假设它。
这是个问题,只是因为表单运行正在显示。翻转过来,让表单尽可能愚蠢,并让 Worksheet_Change
处理程序负责进行 sheet 更改 和 切换 Application.EnableEvents
状态:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 4 And Not IsError(Target.Value) Then
If Target.Value = "no" Then
With New UserForm1
.Show
If .Proceed Then
Application.EnableEvents = False
Target.Offset(0, 1).Value = .Contents
Application.EnableEvents = True
End If
End With
End If
End If
End Sub
几件事:
- 触发事件的单元格是
Target
- 在 ActiveCell
. 上使用 that
- 如果该单元格的值为
#N/A
或任何其他单元格错误值,您的代码就会出错。使用 IsError
验证首先将单元格的值与任何内容进行比较是否安全。
- 表单现在需要
Proceed
和 Contents
属性,不能自毁。
- 调用代码不关心任何文本框:它不知道
Contents
是如何填充的 - 这是表单的关注点。
那么现在表单的代码隐藏是什么样子的?
Option Explicit
Private mProceed As Boolean
Private mContents As String
Public Property Get Proceed() As Boolean
Proceed = mProceed
End Property
Public Property Get Contents() As String
Contents = mContents
End Property
Private Sub TextBox1_Change()
mContents = TextBox1.value
End Sub
Private Sub CommandButton1_Click()
mProceed = True
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
Me.Hide
End If
End Sub
现在所有表单所做的就是收集数据,并将其公开以供调用代码查看:它不知道或不关心任何 ActiveCell
或工作 sheet - 它收集数据,并将其公开以供调用代码查看。 不多也不少.
我有一个 Excel sheet,其中 D 列(第 4 列)是每一行的下拉列表,有 2 个选项:
- 是
- 没有
当我单击“否”时,会弹出一个用户表单,其中包含一个简单的 "text zone" 要求输入一个值和一个 "Submit button" 进行验证。
单击 "Submit button" 时,我希望将 "text zone" 中的值应用到右侧的单元格中:offset(0,1).
示例:D5:"No" -> "Enters 5 in Userform" -> E5:“5”
到目前为止,这是我的代码:
工作sheet:
Private Sub Worksheet_Change(ByVal Target As Range)
If ActiveCell.Column = 4 Then
If ActiveCell.Value = "no" Then
UserForm1.Show
End If
End If
End Sub
用户表单:
Private Sub CommandButton1_Click()
ActiveCell.Offset(0, 1).Value = TextBox1.Value
UserForm1.Hide
End Sub
如果我将 UserForm1.Hide 放在 ActiveCell 之前,它会执行我想要的操作,但用户窗体不会关闭。 如果我取出 ActiveCell,用户窗体将关闭,但我似乎无法同时使两者工作。
您正在更改 Worksheet_Change 处理程序 中的单元格 ,这意味着如果您没有阻止 UI 的表单,您d 快速将调用堆栈和 运行 炸成 "Out of stack space" 错误,也称为... 堆栈溢出.
您需要防止 Worksheet_Change
处理程序递归调用自身。
这可以通过在进行更改之前关闭 Application.EnableEvents
并在之后重新打开来完成:
Application.EnableEvents = False
ActiveCell.Offset(0, 1).Value = TextBox1.Value
Application.EnableEvents = True
现在,看看这有什么问题?表单如何知道它是从 Worksheet_Change
处理程序调用的,因此它需要切换 Application.EnableEvents
?它不知道 - 现在,它假设它。
这是个问题,只是因为表单运行正在显示。翻转过来,让表单尽可能愚蠢,并让 Worksheet_Change
处理程序负责进行 sheet 更改 和 切换 Application.EnableEvents
状态:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 4 And Not IsError(Target.Value) Then
If Target.Value = "no" Then
With New UserForm1
.Show
If .Proceed Then
Application.EnableEvents = False
Target.Offset(0, 1).Value = .Contents
Application.EnableEvents = True
End If
End With
End If
End If
End Sub
几件事:
- 触发事件的单元格是
Target
- 在ActiveCell
. 上使用 that
- 如果该单元格的值为
#N/A
或任何其他单元格错误值,您的代码就会出错。使用IsError
验证首先将单元格的值与任何内容进行比较是否安全。 - 表单现在需要
Proceed
和Contents
属性,不能自毁。 - 调用代码不关心任何文本框:它不知道
Contents
是如何填充的 - 这是表单的关注点。
那么现在表单的代码隐藏是什么样子的?
Option Explicit
Private mProceed As Boolean
Private mContents As String
Public Property Get Proceed() As Boolean
Proceed = mProceed
End Property
Public Property Get Contents() As String
Contents = mContents
End Property
Private Sub TextBox1_Change()
mContents = TextBox1.value
End Sub
Private Sub CommandButton1_Click()
mProceed = True
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
Me.Hide
End If
End Sub
现在所有表单所做的就是收集数据,并将其公开以供调用代码查看:它不知道或不关心任何 ActiveCell
或工作 sheet - 它收集数据,并将其公开以供调用代码查看。 不多也不少.