【问题标题】:How do I use variables to set properties in VBA (Excel)如何使用变量在 VBA (Excel) 中设置属性
【发布时间】:2011-08-08 02:04:02
【问题描述】:

获取此代码:

With ActiveSheet.Shapes.AddShape(msoShapeRectangle, x, y, w, h).TextFrame
  .Parent.Line.Visible = False
  .Parent.Fill.ForeColor.RGB = RGB(r, g, b)
End With

是否有任何 VBA 方式来“执行”或“评估”,例如可以在 perl/python/...编码?

ParentLine = ".Parent.Line.Visible"
ParentLineValue = "False"

With ActiveSheet.Shapes.AddShape(msoShapeRectangle, x, y, w, h).TextFrame
  **eval**(ParentLine & "=" & ParentLineValue)
  .Parent.Fill.ForeColor.RGB = RGB(r, g, b)
End With

编辑:我发现MSDN information for Access 提到了 Eval,但是当我执行我的代码时,它说“未定义的子或函数”,指向 Eval(Excel 似乎不知道这个函数)。

编辑 2:找到definitive (negative) answer on SO

编辑 3:似乎毕竟有一个答案,因为我不追求任意代码执行的通用解决方案。感谢 GSerg 帮助使用 CallByName。

【问题讨论】:

  • 我很好奇什么时候会想要这样做?
  • 我只是想参数化一个宏而不是强迫用户阅读 VBA,只是玩他们的电子表格。我知道安全隐患,但这仅用于有限的用途。可能想要设置不同的属性,而不是那个。
  • ScriptControl ActiveX 可以帮助您评估包含任何Application 成员的字符串,检查this answer

标签: vba excel eval


【解决方案1】:

False 的计算结果为零。您可以构造一个等于零的整数变量,并使其结果与 False 相同。

【讨论】:

  • 很好,但我的问题比这更基本。我编辑了我的问题以完善我的问题。我意识到这更像是一个支持问题,但我无法在任何地方找到相关信息。
【解决方案2】:

您可以尝试查看CallByName,但我认为它不会达到您想要的效果(至少,如果您想要评估多点对象/属性引用,这并不容易)。

【讨论】:

  • 不错的尝试,但ActiveSheet.Cells(x, y) 不支持CallByName
  • 现在我明白了,CallByName 只是一个级别。多级需要GSerg的解决方案。
【解决方案3】:

解决方案 1。

使用CallByName

Option Explicit

Private Type Callable
  o As Object
  p As String
End Type

Public Sub SetProperty(ByVal path As String, ByVal Value As Variant, Optional ByVal RootObject As Object = Nothing)
  With GetObjectFromPath(RootObject, path)
    If IsObject(Value) Then
      CallByName .o, .p, VbSet, Value
    Else
      CallByName .o, .p, VbLet, Value
    End If
  End With
End Sub

Public Function GetProperty(ByVal path As String, Optional ByVal RootObject As Object = Nothing) As Variant
  With GetObjectFromPath(RootObject, path)
    GetProperty = CallByName(.o, .p, VbGet)
  End With
End Function

Public Function GetPropertyAsObject(ByVal path As String, Optional ByVal RootObject As Object = Nothing) As Object
  With GetObjectFromPath(RootObject, path)
    Set GetPropertyAsObject = CallByName(.o, .p, VbGet)
  End With
End Function


Private Function GetObjectFromPath(ByVal RootObject As Object, ByVal path As String) As Callable
  'Returns the object that the last .property belongs to
  Dim s() As String
  Dim i As Long

  If RootObject Is Nothing Then Set RootObject = Application

  Set GetObjectFromPath.o = RootObject

  s = Split(path, ".")

  For i = LBound(s) To UBound(s) - 1
    If Len(s(i)) > 0 Then
      Set GetObjectFromPath.o = CallByName(GetObjectFromPath.o, s(i), VbGet)
    End If
  Next

  GetObjectFromPath.p = s(UBound(s))
End Function

用法:

? getproperty("activecell.interior.color")
16777215 

SetProperty "activecell.interior.color", vbYellow
'Sets yellow background

? getproperty("names.count", application.ActiveWorkbook)
0 

? getproperty("names.count", GetPropertyAsObject("application.activeworkbook"))
0

解决方案 2。

动态添加代码。
不要这样做。这是错误的,它需要设置 "Allow access to VB project" 刻度。

添加对Microsoft Visual Basic for Applications Extensibility X.X的引用。

创建一个名为ModuleForCrap的模块。

添加一个动态构造的子/函数:

ThisWorkbook.VBProject.VBComponents("ModuleForCrap").CodeModule.AddFromString _
"function foobar() as long" & vbNewLine & _
"foobar = 42" & vbNewLine & _
"end function"`

叫它:

msgbox application.run("ModuleForCrap.foobar")

删除它:

With ThisWorkbook.VBProject.VBComponents("ModuleForCrap").CodeModule
  .DeleteLines .ProcStartLine("foobar", vbext_pk_Proc), .ProcCountLines("foobar", vbext_pk_Proc)
End With

【讨论】:

  • 太棒了。它适用于SetProperty "interior.color", vbYellow, Data.Cells(1, 5),但由于某种原因它不喜欢SetProperty "Data.Cells(1,5).interior.color", vbYellow - 但这对我来说很好。
  • @asoundmove:是的,路径字符串中只支持点。如果您要支持嵌入式参数,您最终会编写一个全面的解析器,此时使用第二种方法会更容易。
猜你喜欢
  • 2021-04-19
  • 1970-01-01
  • 2019-05-13
  • 1970-01-01
  • 1970-01-01
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多