【问题标题】:VBA Wrong number arguments userform code, transfering variables?VBA错误的数字参数用户表单代码,传输变量?
【发布时间】:2018-10-06 11:50:13
【问题描述】:

尝试创建一个预算电子表格,其中从 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

几乎就像它无法在 subs 之间传输“x”的值一样,因为前者在 watch 中显示为 value = 1,在用户表单代码中显示为无法编译。

感谢您的建议!

【问题讨论】:

  • 第一步:将Option Explicit放在每个模块(包括表单代码模块)的顶部,然后修复显示的错误。一旦你这样做了,你就会有一些更简洁的代码,你可能会有更多的问题。
  • 就目前而言,您上面的问题过于宽泛,因为有太多错误需要解决。查看变量的“范围”(本身就是一个完整的教程)以及循环如何工作(为什么在循环中使用.show 是一个坏主意)。以及如何声明变量并没有真正做到它应该做的(提示:x 被声明为 Variant 而不是 Integer,你不应该再使用 Integer)。这段代码需要完全重写,这超出了 Stack Overflow 的预期范围(具体的答案和问题,而不是代码重写服务)。
  • 嗨 - 选项显式实际上在所有部分中(我只复制了部分内容以尝试将其保留在我认为相关的位中)。 x 如何声明为 Variant?我得到的整数不是它的优势,但这只是处理大约 100 行,所以它的习惯而不是 r 。循环在其他地方工作正常 - 只是这个摔倒了。我不是在寻找重写,但这里一定有什么具体的东西吗?
  • 致力于简化和使用“传递”变量,因此构建我想放在用户表单之外的标题中的信息,发送它,显示,捕获用户输入然后重建它全部回到模块中。

标签: vba excel


【解决方案1】:

即使这确实有效,您也不想使用这样的变量。应该给它们尽可能窄的范围,以避免您忘记(或维护您的代码的其他人忘记)它们是全局声明的。

如 cmets 中所述,用逗号分隔的声明是这样的......

Public x, xmax As Integer

...仅对后面有As {Type} 的那些进行强类型化。在这种情况下,xmaxIntegerx 隐含地是 Variant,因为没有声明任何类型。

用户窗体是 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 表单。这很重要,因为您将使用它来将信息返回传递给调用者。

调用代码看起来更像这样:

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

【讨论】:

  • 首先,感谢所有详细的反馈。我不知道你需要像这样声明。有道理,但在某处捡起它是为了节省空间参考多行。虽然我认为它确实开始回来了!我阅读了用户表单链接,并且可以看到并同意它们应该只是演示文稿 - 因为这样做(第一次使用它们)意味着很多跳跃。
  • 就全局变量而言——该死的,我以为我从中学到了一些有用的东西!尽管考虑到这只是个人用途,而且只会是我,而且永远是我,使用它也许不是一个值得纠正的问题,但把重点放在全球化它们上。
  • @ALF 主要的收获是使用表单的默认实例。这是一个难以追踪错误的巨大来源(并且使用显式实例通常只需要几行额外的代码)。
【解决方案2】:

因此决定简化并使用“pass”变量,在用户表单之外构建我想要放入用户表单标题的信息,使用 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

解决方案有效,但至于为什么传递变量数组不起作用,我仍然卡住了。我在其他用户表单上使用相同的策略从公共内存中的数组创建标题。尽管不同之处在于用户表单代码不会对它们进行太多操作,并且只是将答案传回,因为我已对其进行了修改。我想这就是它失败的地方。

【讨论】:

  • 这可能会使代码“工作”,但通常是not good practice
  • “x 是预定义变量”是什么意思?以前在您的代码中?
  • 阅读此线程后,我发现您正处于一个很滑的地方,在那里您有一些很好的 VBA 知识......但也缺少一些重要的关键概念——当您制作一个更改并且代码“再次开始工作”。我的意思绝不是冒犯性的(我们都必须经历那个阶段),但希望你早日意识到你真的应该听从别人的建议,即使这看起来像是更长或更复杂的做事方式事物。我建议你从@Comintern 的回答开始,如果你有什么不明白的,问他们!
  • ref 使用 x,这还不是 excel/vba 函数,因此我不能覆盖它吗? (以及为什么 VBA 编辑器以不同的字体显示它?)
  • 正在研究建议的代码 - 试图真正理解它。在调用用户表单方面已经看到了一些结构,但我的主要努力是让它工作,所以它至少做了一些事情而不是什么都不做。业余的我知道。再次感谢您的耐心和时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 1970-01-01
  • 2015-08-15
  • 1970-01-01
  • 1970-01-01
  • 2012-03-28
相关资源
最近更新 更多