简体   繁体   English

Excel VBA:将Click事件中的Target变量传递给用户窗体

[英]Excel VBA: Pass `Target` Variable from Click Event to Userform

I am building an Excel 2016 Userform using VBA and need to collect the row and column of the cell from which the form is opened. 我正在使用VBA构建Excel 2016用户窗体,需要收集从中打开窗体的单元格的行和列。 I open the form on a cell double click with Worksheet_BeforeDoubleClick and then initialize the Userform with UserForm_Initialize() . 我使用Worksheet_BeforeDoubleClick在单元格上双击打开表单,然后使用UserForm_Initialize()初始化Userform。 I would like to pass the Target of the double click event to UserForm_Initialize() but am not sure how to. 我想将双击事件的Target传递给UserForm_Initialize()但不确定如何传递。 This forum thread addresses this issue, but the provided solutions did not work for me. 这个论坛主题解决了这个问题,但是提供的解决方案对我不起作用。

Here is my Worksheet_BeforeDoubleClick : 这是我的Worksheet_BeforeDoubleClick

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
    Column = Target.Column
    Row = Target.Row

    'Find the last non-blank cell in column B(2)
    lRow = Cells(Rows.Count, 2).End(xlDown).Row

    'Find the last non-blank cell in row 2
    lCol = Cells(2, Columns.Count).End(xlToRight).Column
     If Not Intersect(Target, Range(Cells(3, 3), Cells(lRow, lCol))) Is Nothing Then
        Cancel = True
        EdgeEntryForm.Show
    End If

End Sub

And my UserForm_Initialize() : 和我的UserForm_Initialize()

Private Sub UserForm_Initialize()
    Dim Column As Long, Row As Long 'I would like to fill these with the Target values
    MsgBox ("Row is " & Row & " Column is " & Column)
     'Description.Caption = "Fill out this form to define a network edge from " & Cells(2, Row).Value & " to " & Cells(Column, 2).Value
End Sub

As suggested in my comments, one way would be to just use the ActiveCell and assign that to a variable. 如我的评论所建议,一种方法是仅使用ActiveCell并将其分配给变量。

Alternatively, if you do want to pass it as a variable, you can do it with a bit of a workaround, by having a global variable to temporarly hold that information: 另外,如果您确实希望将其作为变量传递,则可以通过一些全局变量临时保存该信息来进行一些变通:

In your worksheet code: 在您的工作表代码中:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
'.....
    With UserForm1
        Set .rngTarget = Target
        .Show
    End With
'.....
End Sub

In your userform : 在您的用户表单中

Public rngTarget As Range
Private Sub UserForm_Activate()
'....
    If Not rngTarget Is Nothing Then
        MsgBox ("Row is " & rngTarget.Row & " Column is " & rngTarget.Column)
    Else
        MsgBox "something went wrong with assigning rngTarget variable"
    End If
'....
End Sub

EDIT: I was trying initially to propose something similar to @MathieuGuindon's answer , but was failing due to my limited knowledge on the difference between initialise and activate (thanks Mathieu). 编辑:我最初试图提出类似于@MathieuGuindon的答案的方法 ,但是由于我对初始化和激活之间的区别的了解有限而失败了(感谢Mathieu)。

I've updated the answer to make use of the global variable at userform level, rather than use one from a module. 我已经更新了答案,以便在用户窗体级别使用全局变量,而不是使用模块中的全局变量。

The form is shown modally, so ActiveCell isn't going to change on you, and should be safe to use in the form's code-behind. 表单以模态显示,因此ActiveCell不会对您造成任何影响,因此应安全地用于表单的代码隐藏中。

The problem with that, is that you've now tied the form to ActiveSheet / ActiveCell , and now in order to test anything you need to Select or Activate a cell. 这样做的问题是,您现在已经将表单绑定到ActiveSheet / ActiveCell ,并且现在为了测试需要SelectActivate单元格的任何内容。

If the form code only needs to know about the cell's Address , then it shouldn't be given a Range (give it a Range and it can access any cell in any sheet in any workbook in the Application instance) - that's the principle of least knowledge at play. 如果表单代码只需要知道单元格的Address ,则不应为其指定Range (给它一个Range ,它可以访问Application实例中任何工作簿的任何工作表中的任何单元格)-这是最小原则知识在起作用。 But this is obviously example code, so let's go with a Range : 但这显然是示例代码,因此让我们来看一下Range

Option Explicit
Private internalWorkingCell As Range

Public Property Get WorkingCell() As Range
    Set WorkingCell = internalWorkingCell
End Property

Public Property Set WorkingCell(ByVal value As Range)
    Set internalWorkingCell = value
End Property

Now your form code can use WorkingCell or internalWorkingCell to do its thing, and no global variable needs to float around; 现在,您的表单代码可以使用WorkingCellinternalWorkingCell来完成它的工作,并且不需要全局变量浮动;

With New UserForm1 ' Initialize handler runs here
    Set .WorkingCell = Target 
    .Show ' Activate handler runs here
End With

The WorkingCell belongs to the form - it has no business being in global scope. WorkingCell 属于以下形式-它不在全球范围内开展业务。

Careful with the Initialize handler in forms - especially when you use its default instance (ie when you don't New it up): you don't control when that handler runs, the VBA runtime does; 小心的Initialize的形式处理- 尤其是当你使用它的默认实例 (即当你不New它):该处理程序运行时你不控制,在VBA运行时做; UserForm_Initialize will run the first time the form instance is referenced (in your case, immediately before the .Show call), and then never again unless the instance is destroyed (clicking the red X button would do that). UserForm_Initialize将在第一次引用表单实例时(在您的情况下,紧接在.Show调用之前)运行,然后再运行一次,除非实例被销毁(单击红色的X按钮即可)。

A MsgBox call in the Initialize handler will run before the form is shown; Initialize处理程序中的MsgBox调用将显示表单之前运行; you probably want to move that code to the Activate handler before it causes problems. 您可能希望在导致问题之前将该代码移至Activate处理程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM