NoN*_*123 3 excel powerpoint vba
我正在使用 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
Run Code Online (Sandbox Code Playgroud)
应该Sub2以不同的方式调用变量,例如 x 和 y?如果没有,我将回到问题 1):直接从Sub1to传递这些变量Sub2而不是全局声明它们的原因是什么?当我打算在调用后使用aand bin的原始值时,我得到了它(所以基本上将其传递为to ),但在我的情况下情况并非如此。Sub1Sub2ByValSub2
是否有理由限制全局变量的使用?我将它们保留在代码中作为本地,但我应该在全局范围内定义lRowAn等lRowData吗?
我什么时候应该将变量从一个子传递到另一个?在下面的代码中,使用 执行此操作iSlides对我来说有意义,但对于 则不然wsEm。
以下是我的实际代码的一部分。SubEmData和EmDataAn非常相似,我会看看是否可以合并它们,但它们很好地说明了我遇到的问题,因为它们使用了许多相同的变量。
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
Run Code Online (Sandbox Code Playgroud)这与代码功能无关,而是如何一般使用变量。
首先,将每个变量声明为尽可能局部的。例如,如果仅在一个过程/函数中需要它,则在那里声明它。
\n如果您需要访问多个过程/函数中的变量,那么最好将其作为参数传递给下一个函数。这可以完成ByRef(默认)或ByVal.
Sub ProcedureA()\n Dim ParamA As String\n ParamA = "AAA"\n Dim ParamB As String\n ParamB = "BBB"\n\n ProcedureB ParamA, ParamB\n\n Debug.Print ParamA \'returns 111\n Debug.Print ParamB \'returns BBB\nEnd Sub\n\nSub ProcedureB(ByRef Param1 As String, ByVal Param2 As String)\n Param1 = "111" \'this will change ParamA in ProcedureA too\n Param2 = "222" \'this value will only be changed in ProcedureB\nEnd Sub\nRun Code Online (Sandbox Code Playgroud)\n虽然使用ByRef(通过引用)可以更改 中的参数ProcedureB并在 中也更改它ProcedureA,但(按值)传递的参数ByVal不会在 中更改ProcedureA。
从技术上讲,如果您以不同的方式命名变量或使用相同的名称,那么这里没有任何区别。在每个过程中使用最有意义的名称是一个很好的做法(请参阅下面的标题变量名称)。
\n实际上,我认为始终指定是否使用默认值也是一个很好的ByRef做法ByVal。使用默认值时,您始终必须记住,它ByRef在 VBA 中是默认值,但在 VB.NET 中,默认值ByVal很容易让人困惑(至少我是这样)。
结束后ProcedureA变量不再可用(数据丢失)。
如果您希望数据在多个函数中持久且可访问,则使用全局变量(尽可能少使用它们)。
\nDim GlobalVarA As String\n\nSub ProcedureA()\n GlobalVarA = "AAA"\nEnd Sub\n\nSub ProcedureB()\n Debug.Print GlobalVarA \'return AAA (if ProcedureA was run before)\nEnd Sub\nRun Code Online (Sandbox Code Playgroud)\n请注意,在这种情况下,任何过程都可以更改 的值GlobalVarA。如果如上所述将其作为参数传递,则只有该变量传递到的过程才能访问该变量。
当 Excel VBA 结束(或文件关闭)时,全局变量将丢失其数据。
\n在过程中使用全局变量的一个缺点是,在第一次使用它之前,您始终需要检查它的值。因为如果它尚未初始化,那么它就是Emptyor Nothing。例如(上面),当运行时,ProcedureB你不能依赖ProcedureA之前已经运行过的。因此,您需要GlobalVarA在使用它之前检查它的值ProcedureB,特别是如果它是一个对象,您必须测试是否存在Nothing,否则很容易遇到错误。
所以我们可以总结一下,尽可能限制对变量的访问使您的代码更安全、更可靠(如果仅在本地声明,则其他函数不会意外更改它)。仅在确实需要时才使用全局变量。
\n如果变量名是在本地声明的,那么重用变量名通常没有问题。但如果您对全局变量和局部变量使用相同的名称,就会变得很棘手(那么 VBA 更喜欢局部变量!)
\nDim VarA As String \'global\n\nSub ProcedureA()\n Dim VarA As String \'same name local\n VarA = "AAA" \'this uses always the local variable!\nEnd Sub\n\nSub ProcedureB()\n Debug.Print VarA \'this uses the global variable and it is empty (after ProcedureA is run) \nEnd Sub\nRun Code Online (Sandbox Code Playgroud)\n一般来说,仅使用有意义的变量名称是一个非常好的做法。这意味着不要调用变量而是rng1调用rng2它们,例如InputRange和OutputRange。另外,如果您经常需要一个计数器(例如循环遍历行和列)i并且被使用,但如果您使用例如and作为变量名,j它的可读性会更高。iRowiCol
为了强制进行正确的变量声明,我建议始终激活Option Explicit:在 VBA 编辑器中,转到“工具” \xe2\x80\xba “选项” \xe2\x80\xba “需要变量声明”。这可以防止您错误输入变量名称并意外引入新变量。