从Visual Basic中的用户窗体获取单个变量

时间:2018-07-18 15:15:21

标签: excel vba

我对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

谢谢

2 个答案:

答案 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中提供了更多有关表单默认实例的信息(从那里获取了基本的隐藏代码片段)。