Как использовать переменные для установки свойств в VBA (Excel) - PullRequest
8 голосов
/ 18 апреля 2011

Возьмите этот код:

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 / ..., так что текст .Parent.Line.Visible может быть нарисован из переменной (или значения ячейки), а не из жесткого закодированы?

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-информацию для Access , в которой упоминается Eval, но когда я выполняю свой код, он говорит "Undefined Sub или Function", указывая на Eval (Excel, кажется, не знает эту функцию).

РЕДАКТИРОВАТЬ 2: Нашел окончательный (отрицательный) ответ на SO .

РЕДАКТИРОВАТЬ 3: Кажется, в конце концов, есть ответ, поскольку я не после общего решения для выполнения произвольного кода. Спасибо GSerg за помощь в использовании CallByName.

Ответы [ 3 ]

10 голосов
/ 18 апреля 2011

Решение 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.

Динамически добавлять код.
Не делай этого. Это неправильно и требует наличия «Разрешить доступ к проекту VB» .

Добавить ссылку на 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
1 голос
/ 18 апреля 2011

Вы можете попробовать посмотреть на CallByName, но я не думаю, что это будет делать то, что вы хотите (по крайней мере, не так просто, если вы хотите оценить многоточечные ссылки на объекты / свойства).

0 голосов
/ 18 апреля 2011

False оценивается как ноль.Вы можете создать целочисленную переменную, равную нулю, и получить ее так же, как False.

...