VBA错误的数字参数用户窗体代码,正在传递变量?

时间:2018-10-06 00:17:41

标签: vba excel-vba

尝试创建一个预算电子表格,从csv文件读取支出,我将其分配到类别(通过用户表单),为此,入金获得了单独的用户表单,可以在其中进行简短描述在文本框中,然后在输出表中的值旁边记录该文本框。

使用此站点加载来确定如何完成所有操作-但仅限于此。

宏效果很好,但是在用户表单代码中出现了“参数数量错误或属性分配无效”,并突出显示了expend.Caption行中的indescript(x)位。

原始子项是

Public x, xmax As Integer
Public incmng(1 To 100) As Variant
Public incdescript(1 To 100), inctot As String

' add in the incoming payments with user entered short description
    inctot = ""
    For x = 1 To xmax
        indes.Show
        inctot = incdescript(x) & "; " & inctot
        Cells(r - 2, 7) = inctot
    Next x

用户表单(名为indes)代码为

Private Sub UserForm_Initialize()
    ' Load the expenditure details
    expend.Caption = incdescript(x) & ": " & incmng(x)
    incans.Value = "change me :-)"
End Sub

Private Sub OKButton_Click()
    ' Allow user to put in a short description
    incdescript(x) = incmng(x) & " " & incans.Text
Unload Me
End Sub
Private Sub CancelButton_Click()
    Unload Me
    End
End Sub

几乎就像它不能在子对象之间传输“ x”的值一样,就像在前者中它在值中显示为value = 1,在用户窗体代码中它显示为无法编译。

感谢您的任何建议!

2 个答案:

答案 0 :(得分:2)

即使这样做确实可行,您也不想使用这样的变量。应该为它们提供尽可能小的范围,以避免您忘记(或者其他维护您的代码的人)忘记了它们在全局范围内的声明。

如评论中所述,声明用逗号分隔,例如...

Public x, xmax As Integer

...仅针对紧跟其后的As {Type}的那些键入。在这种情况下,xmaxInteger,而x隐式是Variant,因为尚未声明任何类型。

UserForms是VBA中的类,作为类,可以使用公共方法和属性进行扩展。问题在于您使用的是表单的默认实例,而不是在循环中创建新实例。当您从表单内部调用Unload时,只需执行此操作,所有信息都将丢失。

解决方案是显式创建表单实例。这样,您既可以使用自定义的初始化器或属性对其进行配置,又可以轻松地从调用者之间来回传递信息。表单代码如下所示:

'indes
Option Explicit

Private incdescript As String
Private incmg As String
Private userEntry

Public Sub LoadValues(descript As String, incoming As String)
    expend.Caption = descript & ": " & incoming
    incdescript = descript
    incmg = incoming
End Sub

Public Property Get UserDescription() As String
    UserDescription = incdescript = incmg & " " & incans.Text
End Property

Private Sub OKButton_Click()
    Me.Hide
End Sub

需要注意的几件事-这种形式的没有什么取决于全局变量。所有配置都通过将参数传递给LoadValues过程来处理,并且“返回值”通过自定义UserDescription属性公开。

此外,请注意,“确定”按钮不会Unload表单。这很重要,因为您将使用它将信息 back 传递给调用方。

调用代码看起来像这样:

Dim x As Integer, xmax As Integer
Dim incmng(1 To 100) As Variant
Dim incdescript(1 To 100) As String, inctot As String

' add in the incoming payments with user entered short description
inctot = ""
Dim paymentDialog As indes
For x = 1 To xmax
    Set paymentDialog = New indes
    paymentDialog.LoadValues incdescript(x), incmng(x)
    paymentDialog.Show vbModal
    inctot = paymentDialog.UserDescription & "; " & inctot
    Unload paymentDialog
    Cells(r - 2, 7) = inctot
Next x

您创建表单的新实例,在显示表单之前将表单所需的值传递给它。当表单调用Me.Hide时,控制权返回到调用过程,然后您询问表单以了解用户输入的内容。然后 调用过程 将其卸载。

请注意,这只是我认为用于处理UserForm的“最佳实践”的粗略概图。有关更详细的描述,我将看看@MathieuGuindon的this answer并阅读他的博客文章here

答案 1 :(得分:0)

因此决定简化并使用“通过”变量,在用户表单外部构建要放入用户表单标题的信息,使用 pass 发送,显示并捕获用户使用相同的变量(可以是不同的但不需要)输入,然后将我的字符串重新构建到核心模块中。

' add in the incoming payments with user entered short description
    Cells(r - 2, 5) = inctot
    For m = 1 To mmax
        pass = incdescript(m) & ": " & Incmng(m)
        indes.Show
        Inctotdes = Incmng(m) & " " & pass & "; " & Inctotdes
        Cells(r - 2, 7) = Inctotdes
    Next m

哦,我意识到x是一个预定义的变体。并不是说改变带来了改变。我从来没有用过它(因为我现在记得这个原因-这是我使用VBA以来10年来最好的部分!),但是我喜欢的计数信已经在使用中。

Private Sub UserForm_Initialize()
    ' Load the expenditure details
    expend.Caption = pass
    incans.Value = "change me :-)"
End Sub

Private Sub OKButton_Click()
    ' Allow user to put in a short description
    pass = incans.Text
Unload Me
End Sub
Private Sub CancelButton_Click()
    Unload Me
    End
End Sub

解决方案有效,但是关于为什么不能通过变量数组的问题,我仍然感到困惑。我在从公共内存中的数组创建标题的其他用户形式上使用相同的策略。尽管区别在于用户窗体代码不会对它们进行太多操作,而只是将答案传递回去,因为我对此做了修改。我想那是失败的地方。