gpt4 book ai didi

excel - 不同subs中全局变量和局部变量的使用

转载 作者:行者123 更新时间:2023-12-04 19:54:04 29 4
gpt4 key购买 nike

我正在使用 VBA 将内容从 Excel 复制到 PowerPoint。它正在工作,但我需要清理我的代码。问题是我不知道当涉及多个过程中使用的变量(或对象)时,什么是好的做法。我认为我在这方面缺乏一些基本的了解。

  • 将变量从一个过程传递到另一个过程时,在两个过程中使用相同的名称是不是一个坏主意?所以例如
    Sub 1()
    Dim a As Long, b As Long
    Call Sub2(a, b)
    '...
    End Sub

    Sub2(a As Long, b As Long)
    '...
    End Sub

    应该 Sub2以不同的方式调用变量,例如 x 和 y?如果不是,我回到问题 1):直接从 Sub1 传递这些变量的原因是什么?至Sub2而不是在全局范围内声明它们?当我打算使用 a 的原始值时,我得到它和 bSub1调用 Sub2 后(所以基本上将它作为 ByVal 传递给 Sub2 ),但在我的情况下并非如此。
  • 是否有理由限制全局变量的使用?我将它们作为本地代码留在了我的代码中,但我应该定义 lRowAn , lRowData等全局?
  • 我什么时候应该将一个变量从一个子传递给另一个?在我下面的代码中,使用 iSlides 执行此操作对我有意义,但不适用于 wsEm .

    以下是我实际代码的一部分。潜艇 EmDataEmDataAn非常相似,我会看看是否可以合并它们,但它们很好地说明了我遇到的问题,因为它们使用了许多相同的变量。
    Public mySlide As PowerPoint.Slide
    Public PowerPointApp As PowerPoint.Application
    Public myPresentation As PowerPoint.Presentation
    Public MonatNum As String, JahrNum As String, MonatStr As String

    Sub CreateReport()
    Dim DestinationPPT As String
    Dim iSlides As Integer
    Dim fRowAn As Long, lRowAn As Long, lRowData As Long
    Dim wbEm As Workbook
    Dim wsEm As Worksheet

    Set PowerPointApp = New PowerPoint.Application
    DestinationPPT = "C:\VBA\ReportTemplate.pptm"
    Set myPresentation = PowerPointApp.Presentations.Open(DestinationPPT)

    Set wbEm = Workbooks.Open("C:\VBA\Report.xlsx")
    Set wsEm = wbEm.Sheets("Sheet1")

    lRowAn = wsEm.Cells(Rows.Count, 3).End(xlUp).Row
    fRowAn = wsEm.Cells(Rows.Count, 3).End(xlUp).End(xlUp).Row + 1

    If lRowAn >= 127 Then
    If lRowData <= 127 Then '4 Slides, but separate Annotations from Data
    iSlides = 1
    Call EmData(wsEm, iSlides)
    Call EmDataAn(wsEm, iSlides)
    Else '4 Slides
    iSlides = 3
    Call EmData(wsEm, iSlides)
    End If
    Else '3 Slides
    Call EmData(wsEm, iSlides)
    End If

    Application.DisplayAlerts = False
    wbEm.Close SaveChanges:=False
    Application.DisplayAlerts = True

    PowerPointApp.Visible = True
    PowerPointApp.Activate
    Application.CutCopyMode = False
    End Sub



    Sub EmData(wsEm As Worksheet, iSlides As Integer)
    Dim i As Integer
    Dim fRowDataCalc As Long, lRowDataCalc As Long, lRowCopy As Long
    Dim rowHght As Long
    Dim rng As Range

    For i = 0 To iSlides
    fRowDataCalc = 4 + 40 * i + i * 1
    lRowDataCalc = 4 + 40 * (i + 1) + i * 1

    With wsEm
    .Range("B2:K3").Copy .Range("B500")
    .Range("B" & fRowDataCalc & ":K" & lRowDataCalc).Copy .Range("B502")
    rowHght = .Range("B3").EntireRow.Height
    .Range("B501").RowHeight = rowHght
    lRowCopy = .Cells(Rows.Count, "C").End(xlUp).Row
    Set rng = .Range("B500:K" & lRowCopy)
    End With

    Set mySlide = myPresentation.Slides.AddSlide(myPresentation.Slides.Count + 1, PPLayout("LayoutEmittenten"))
    mySlide.Shapes.Placeholders(1).TextFrame.TextRange.Text = "Headline (" & i + 1 & ")"
    Call PasteEm(mySlide, rng)
    rng.Clear
    Next i

    End Sub

    Sub EmDataAn(wsEm As Worksheet, iSlides As Integer)
    Dim lRowAn As Long, fRowAn As Long, lRowData As Long, fRowDataCalc As Long, lRowDataCalc As Long
    Dim rng As Range
    Dim rowHght As Long, lRowCopy As Long

    lRowAn = wsEm.Cells(Rows.Count, 3).End(xlUp).Row
    fRowAn = wsEm.Cells(Rows.Count, 3).End(xlUp).End(xlUp).Row - 1
    lRowData = wsEm.Cells(Rows.Count, 10).End(xlUp).Row

    iSlides = iSlides + 1
    fRowDataCalc = 4 + 40 * iSlides + iSlides * 1
    lRowDataCalc = lRowData

    'Last sheet with data
    With wsEm
    .Range("B2:K3").Copy .Range("B500")
    .Range("B" & fRowDataCalc & ":K" & lRowDataCalc).Copy .Range("B502")
    rowHght = .Range("B3").EntireRow.Height
    .Range("B501").RowHeight = rowHght
    lRowCopy = .Cells(Rows.Count, "C").End(xlUp).Row
    Set rng = .Range("B500:K" & lRowCopy)
    End With

    Set mySlide = myPresentation.Slides.AddSlide(myPresentation.Slides.Count + 1, PPLayout("LayoutEmittenten"))

    mySlide.Shapes.Placeholders(1).TextFrame.TextRange.Text = "Headline (" & iSlides + 2 & ")"
    Call PasteEm(mySlide, rng)
    rng.Clear
    'Annotations
    Set rng = wsEm.Range("B" & fRowAn & ":K" & lRowAn)
    rng.Copy
    Set mySlide = myPresentation.Slides.AddSlide(myPresentation.Slides.Count + 1, PPLayout("LayoutEmittenten"))
    mySlide.Shapes.Placeholders(1).TextFrame.TextRange.Text = "Headline (" & iSlides + 2 & ")"
    Call PasteEm(mySlide, rng)
    End Sub



    Sub PasteEm(mySlide As PowerPoint.Slide, rng As Range)
    Dim myShape As PowerPoint.Shape

    rng.Copy
    DoEvents
    mySlide.Shapes.PasteSpecial DataType:=ppPasteEnhancedMetafile ' = 2
    Set myShape = mySlide.Shapes(mySlide.Shapes.Count)
    With myShape
    .Width = 683
    .Top = 70
    .Left = 5
    End With
    End Sub

  • 这不是关于代码功能,而是关于一般如何使用变量。

    最佳答案

    局部变量
    首先,尽可能将每个变量声明为本地变量。例如,如果仅在一个过程/函数中需要它,则在此处声明它。
    局部变量(作为参数传递)
    如果您需要访问多个过程/函数中的变量,那么最好将其作为参数传递给下一个函数。这可以做到ByRef (默认)或 ByVal .

    Sub ProcedureA()
    Dim ParamA As String
    ParamA = "AAA"
    Dim ParamB As String
    ParamB = "BBB"

    ProcedureB ParamA, ParamB

    Debug.Print ParamA 'returns 111
    Debug.Print ParamB 'returns BBB
    End Sub

    Sub ProcedureB(ByRef Param1 As String, ByVal Param2 As String)
    Param1 = "111" 'this will change ParamA in ProcedureA too
    Param2 = "222" 'this value will only be changed in ProcedureB
    End Sub
    使用 ByRef 时(通过引用)可以更改 ProcedureB 中的参数并且在 ProcedureA 中也进行了更改,但是传递的参数 ByVal (按值)在 ProcedureA 中没有变化.
    如果您以不同的方式命名变量或使用相同的名称,这在技术上没有任何区别。使用在每个过程中最有意义的名称将是一个好习惯(请参阅下面的标题变量名称)。
    实际上,我认为始终指定是否为 ByRef 也是一个好习惯。或 ByVal并且不使用默认值。使用默认值时,您必须始终记住它是 ByRef默认情况下在 VBA 中,但在 VB.NET 中默认为 ByVal这很容易让人困惑(至少我是这样)。
    之后 ProcedureA结束变量不再可用(数据丢失)。
    全局变量
    如果您希望数据在多个函数中持久且可访问,则使用全局变量(尽可能少地使用它们)。
    Dim GlobalVarA As String

    Sub ProcedureA()
    GlobalVarA = "AAA"
    End Sub

    Sub ProcedureB()
    Debug.Print GlobalVarA 'return AAA (if ProcedureA was run before)
    End Sub
    请注意,在这种情况下 任意 程序可以改变 GlobalVarA的值.如果您按照上面的说明将其作为参数传递,则只有传递变量的过程才能访问该变量。
    Excel VBA 结束(或文件关闭)时,全局变量将丢失其数据。
    在过程中使用全局变量的一个缺点是,在第一次使用它之前总是需要检查它的值。因为如果它还没有初始化它是 EmptyNothing .例如(上)运行时 ProcedureB你不能依赖 ProcedureA之前已经运行过。所以你需要检查 GlobalVarA 的值在 ProcedureB 中使用它之前特别是如果它是一个对象,你必须测试它是否不蜜蜂 Nothing否则你很容易遇到错误。
    本地与全局
    所以我们可以总结一下,尽可能地限制对变量的访问可以让你的代码更安全、更可靠(如果只在本地声明,没有其他函数可以意外更改它)。仅在确实需要时才使用全局变量。
    重用变量名
    如果变量名是在本地声明的,那么重用变量名通常是没有问题的。但是,如果您对全局变量和局部变量使用相同的名称,就会变得棘手(然后 VBA 更喜欢本地变量!)
    Dim VarA As String 'global

    Sub ProcedureA()
    Dim VarA As String 'same name local
    VarA = "AAA" 'this uses always the local variable!
    End Sub

    Sub ProcedureB()
    Debug.Print VarA 'this uses the global variable and it is empty (after ProcedureA is run)
    End Sub
    一般来说,只使用有意义的变量名是一种很好的做法。这意味着不是调用变量 rng1rng2例如给他们打电话 InputRangeOutputRange .此外,如果您经常需要一个计数器(例如循环遍历行和列) ij被使用,但如果你使用例如 iRow,它的可读性会更高。和 iCol作为变量名。
    选项显式
    为了强制进行正确的变量声明,我建议始终激活 Option Explicit : 在 VBA 编辑器中转到工具 › 选项 › Require Variable Declaration .这可以防止您错误键入变量名称并意外引入新变量。

    关于excel - 不同subs中全局变量和局部变量的使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56054018/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com