我对VB的了解很少,但希望能在没有任何帮助的情况下解决这个问题,但是 alas!
我有一张电子表格,显示了机箱内HP刀片的布局。目前,我已经设置了一个宏(我在工作表上右键单击查看代码),通过该宏单击特定的“刀片”(实际上是几个合并的单元格),然后出现一个输入框,询问用户他们想要的IP-然后,它会寻找完全匹配的内容(例如O-OAM,I-iLO),并根据选择的选项-在case语句中分配一个值。例如:O-OAM IP将分配数字2-执行VLOOKUP并查看第2列,以将IP地址返回给用户剪贴板。
我正在尝试将输入框更改为用户窗体。我已经创建了一个,并且有一个带有可用选项的简单下拉列表。
我正在努力将用户选择导出到一个变量中,以供日后使用。
到目前为止,我所有的努力都导致在完成“用户窗体”并按“确定”按钮后分配一个变量。但是,该变量然后未分配在工作表的代码区域中。我认为这与范围和分配有关。
工作表代码
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Intersect(Target, Range("D57:H80")) Is Nothing Then
Dim HostName As String
Dim ColIndex As Integer
Dim NodeIP As String
HostName = ActiveCell.Value
ufrmIPSelection.Show
'uOption = InputBox("Option Required" & vbCrLf & "o = OAM IP" & vbCrLf & "i = iLO IP", "User selection required")
'uOption
MsgBox "Option captured is " & uOption
Select Case uOption
Case "OAM IP"
ColIndex = 2
Case "iLO IP"
ColIndex = 3
End Select
MsgBox "Column referenced is " & ColIndex
NodeIP = Application.VLookup(HostName, Sheet7.Range("A1:C503"), ColIndex, False)
MsgBox "Hostname is " & HostName
MsgBox "Node IP is " & NodeIP
End If
End Sub
和用户表单“确定”按钮的代码
Public Sub cmdOK_Click()
uOption = cboIP.Value
MsgBox "Combo Box Value " & uOption
'Above line used to see if variable has been assigned
Unload Me
End Sub
谢谢
答案 0 :(得分:1)
您需要在表单中添加一个public property ...
Private m_OptionChoice as String
Property Let OptionChoice(value As String)
m_OptionChoice = value
End Property
Property Get OptionChoice() As String
OptionChoice = m_OptionChoice
End Property
然后将“确定”按钮代码更改为...
Public Sub cmdOK_Click()
OptionChoice = cboIP.Value
MsgBox "Combo Box Value " & uOption
'Above line used to see if variable has been assigned
Unload Me
End Sub
现在,当窗体关闭时,您可以通过ufrmIPSelection.OptionChoice
访问OptionChoice。例如更改...
MsgBox "Option captured is " & uOption
到...
MsgBox "Option captured is " & ufrmIPSelection.OptionChoice
最后,如下面Mathieu Guindon的评论所建议,您需要将Unload Me
替换为Me.Hide
。谢谢Mathieu!
答案 1 :(得分:1)
Unload Me
本质上说“销毁此对象”。但是表单的默认实例不仅仅是任何其他对象-它是一个全局实例,只要被销毁,VBA就会在每次再次引用它时自动重新创建它。但是重新创建的实例无法神奇地记住先前的状态:重新创建的实例因此具有初始/设计时状态。
另一种破坏表单及其状态的东西是右上角的[X]小按钮。
模式形式本质上是对话框-对话框可以被接受或取消。当用户通过单击该[X]小按钮关闭对话框时,他们告诉您的程序他们希望取消该对话框打算执行的操作。
由于这个原因,对话框除了从用户收集数据外什么都不做是很重要的。具有{kbd> Ok 和 Cancel 按钮的UserForm
的基本代码模板可能看起来像这样:
Option Explicit
Private cancelled As Boolean
Public Property Get IsCancelled() As Boolean
IsCancelled = cancelled
End Property
Private Sub OkButton_Click()
Hide
End Sub
Private Sub CancelButton_Click()
OnCancel
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
OnCancel
End If
End Sub
Private Sub OnCancel()
cancelled = True
Hide
End Sub
处理QueryClose
事件可以使我们在用户单击[X]按钮时取消对表单的破坏以及其状态的重置。
现在调用代码可以执行以下操作:
ufrmIPSelection.Show
If ufrmIPSelection.IsCancelled Then Exit Sub
但是由于将状态存储在表单的全局/默认实例中,所以这样做是一个更好的主意:
With New ufrmIPSelection
.Show
If .IsCancelled Then Exit Sub
End With
通过这种方式,可以很好地隔离表单的每次使用,并且表单实例及其状态仅在需要时(即在End With
消失)存在。 >
您可以继续从调用代码中查询各个控件的状态,但是一种更简洁的方法是使用属性封装(类似于{{3}中建议的});这些属性仅需要从调用代码中读取,因此仅需要一个Propery Get
成员:
Public Property Get SelectedIPType() As String
SelectedIPType = cboIP.Value
End Property
现在调用代码可以做到这一点:
With New ufrmIPSelection
.Show
If .IsCancelled Then Exit Sub
MsgBox .SelectedIPType
End With
下一步将是提取一个实际的有状态类以封装 model ,以便从数据中完全 decouple 。
几个月前我写过一篇文章,3.1415's answer中提供了更多有关表单默认实例的信息(从那里获取了基本的隐藏代码片段)。