支持 getByName 的最简单的 Unostructure

simplest Unostructure that supports he getByName

在 LibreOffice Basic sub 中,我在一个数组中使用了一堆 uno 属性。我必须 "embed" 它们是最简单的 Unostructure 或 UnoService,以便使用 getByName "function"?

示例:

dim props(1) as new com.sun.star.beans.PropertyValue

props(0).Name = "blahblah1"
props(0).Value = "blahblah1Value"
props(1).Name = "blahblah2"
props(1).Name = 3000

我希望能够使用类似的东西:

b = props.getByName("blahblah2").Value

或类似的东西(假设我 "assigned" 它们在一个名为 "somestruct" 的类似结构的对象中):

 b = somestruct.getprops.getByName("blahblah2").Value

据我所知,这可以通过创建一个支持 getByName 的 "UnoService" 来完成,然后以某种方式将这些道具分配给该服务 哪个是"lightest"这样的服务? (我指的是使用资源较少的服务)

提前致谢。

LibreOffice Basic 支持 vb6 Collection type

Dim coll As New Collection
coll.Add("blahblah1Value", "blahblah1")
coll.Add(3000, "blahblah2")
MsgBox(coll("blahblah1"))

属性 值的数组是唯一适用于某些 UNO 接口(例如调度程序调用)的东西。如果您只是需要一种更好的方法来处理 属性 值的数组,那么请使用辅助函数。

Sub DisplayMyPropertyValue
    Dim props(0 To 1) As New com.sun.star.beans.PropertyValue
    props(0).Name = "blahblah1"
    props(0).Value = "blahblah1Value"
    props(1).Name = "blahblah2"
    props(1).Name = 3000
    MsgBox(GetPropertyByName(props, "blahblah1"))
End Sub

Function GetPropertyByName(props As Array, propname As String)
    For Each prop In props
        If prop.Name = propname Then
            GetPropertyByName = prop.Value
            Exit Function
        End If
    Next
    GetPropertyByName = ""
End Function

XNameAccess 用于 UNO 容器,例如计算表。通常这些容器是从UNO接口获取的,而不是创建的。

oSheet = ThisComponent.Sheets.getByName("Sheet1")

可能 UNO 对象支持 XPropertySet 接口。通常这些也是从UNO接口获取的,不是创建的。

paraStyleName = cellcursor.getPropertyValue("ParaStyleName")

可以在 Java 中创建一个新的 class 来实现 XPropertySet。但是,Basic 使用辅助函数而不是 class 方法。

真正支持接口XNameAccess并不那么容易。实现此接口的服务应该将此接口用于现有的命名属性,而不是用于自己创建的属性。

但是您可以使用服务 EnumerableMap 来实现您可能想要的。

示例:

sub testEnumerableMap

 serviceEnumerableMap = com.sun.star.container.EnumerableMap
 oEnumerableMap = serviceEnumerableMap.create("string", "any")

 oEnumerableMap.put("blahblah1", "blahblah1Value")
 oEnumerableMap.put("blahblah2", 3000)
 oEnumerableMap.put("blahblah3", 1234.67)

 msgbox oEnumerableMap.get("blahblah1")
 msgbox oEnumerableMap.get("blahblah2")
 msgbox oEnumerableMap.get("blahblah3")
 'msgbox oEnumerableMap.get("blahblah4") 'will throw error

 msgbox oEnumerableMap.containsKey("blahblah2")
 msgbox oEnumerableMap.containsValue(3000)

 if oEnumerableMap.containsKey("blahblah4") then 
  msgbox oEnumerableMap.get("blahblah4")
 end if

end sub

但是带有 option Compatible 的 starbasic 也能够像 VBA 一样支持 Class 编程。

示例:

创建一个名为 myPropertySet 的模块。其中放入以下代码:

option Compatible
option ClassModule

private aPropertyValues() as com.sun.star.beans.PropertyValue

public sub setProperty(oProp as com.sun.star.beans.PropertyValue)
 bUpdated = false
 for each oPropPresent in aPropertyValues
  if oPropPresent.Name = oProp.Name then 
   oPropPresent.Value = oProp.Value
   bUpdated = true
   exit for
  end if
 next
 if not bUpdated then 
  iIndex = ubound(aPropertyValues) + 1
  redim preserve aPropertyValues(iIndex) 
  aPropertyValues(iIndex) = oProp
 end if
end sub

public function getPropertyValue(sName as string) as variant
 getPropertyValue = "N/A"
 for each oProp in aPropertyValues
  if oProp.Name = sName then 
   getPropertyValue = oProp.Value
   exit for
  end if
 next
end function

然后在标准模块中:

sub testClass

 oPropertySet = new myPropertySet
 dim prop as new com.sun.star.beans.PropertyValue

 prop.Name = "blahblah1"
 prop.Value = "blahblah1Value"
 oPropertySet.setProperty(prop) 

 prop.Name = "blahblah2"
 prop.Value = 3000
 oPropertySet.setProperty(prop)

 prop.Name = "blahblah3"
 prop.Value = 1234.56
 oPropertySet.setProperty(prop)

 prop.Name = "blahblah2"
 prop.Value = 8888
 oPropertySet.setProperty(prop)

 msgbox oPropertySet.getPropertyValue("blahblah1")
 msgbox oPropertySet.getPropertyValue("blahblah2")
 msgbox oPropertySet.getPropertyValue("blahblah3")
 msgbox oPropertySet.getPropertyValue("blahblah4")

end sub

我认为 serviceEnumerableMap 是答案(到目前为止)。创建值并搜索它们比在动态数组中创建 props 并在 basic 中使用 for 循环搜索它们要快得多。 (我不"dare"使用"option Compatible",虽然我是VB6和VBA的一大乐趣,因为代码中可能出现的问题)。 我使用此代码以一种形式测试时间:

SUB testlala(Event)
    TESTPROPS(Event)
'   TESTENUM(Event)
    MSGBOX "END OF TEST"
END SUB

SUB TESTENUM(Event)
    DIM xcounter AS LONG

    'b = now()
    serviceEnumerableMap = com.sun.star.container.EnumerableMap
    oEnumerableMap = serviceEnumerableMap.create("string", "any")
    FOR xcounter= 0 TO 10000
        oEnumerableMap.put("pr" & FORMAT(xcounter,"0000"), xcounter -10000)
    NEXT
    'b=now()-b
    b = now()
    FOR xcounter = 1 TO 5000
        lala = Int((9000 * Rnd) +1)
        g =oEnumerableMap.get("pr" & FORMAT(lala,"0000"))
        'MSGBOX GetValueFromName(props,"pr" & FORMAT(xcounter,"0000"))
    NEXT
    b=now()-b
    MSGBOX b*100000
END SUB

SUB TESTPROPS(Event)
    DIM props()
    DIM xcounter AS LONG

    'b = now()
    FOR xcounter= 0 TO 10000
        AppendProperty(props,"pr" & FORMAT(xcounter,"0000"), xcounter -10000)
    NEXT
    'b=now()-b
    b = now()
    FOR xcounter = 1 TO 5000
        lala = Int((9000 * Rnd) +1)
        g = GetValueFromName(props,"pr" & FORMAT(lala,"0000"))
        'MSGBOX GetValueFromName(props,"pr" & FORMAT(xcounter,"0000"))
    NEXT
    b=now()-b
    MSGBOX b*100000
END SUB

REM FROM Andrew Pitonyak's OpenOffice Macro Information ------------------
Sub AppendToArray(oData(), ByVal x)
  Dim iUB As Integer  'The upper bound of the array.
  Dim iLB As Integer  'The lower bound of the array.
  iUB = UBound(oData()) + 1
  iLB = LBound(oData())
  ReDim Preserve oData(iLB To iUB)
  oData(iUB) = x
End Sub

Function CreateProperty(sName$, oValue) As com.sun.star.beans.PropertyValue
  Dim oProperty As New com.sun.star.beans.PropertyValue
  oProperty.Name = sName
  oProperty.Value = oValue
  CreateProperty() = oProperty
End Function

Sub AppendProperty(oProperties(), sName As String, ByVal oValue)
  AppendToArray(oProperties(), CreateProperty(sName, oValue))
End Sub