支持 getByName 的最简单的 Unostructure
Posted
技术标签:
【中文标题】支持 getByName 的最简单的 Unostructure【英文标题】:simplest Unostructure that supports he getByName 【发布时间】:2016-08-04 06:29:24 【问题描述】:在 LibreOffice Basic sub 中,我在一个数组中使用了一堆 uno 属性。为了使用 getByName“函数”,我必须“嵌入”它们,哪个是最简单的 Unostructure 或 UnoService?
例子:
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
或类似的东西(假设我将它们“分配”在一个名为“somestruct”的类似结构的对象中):
b = somestruct.getprops.getByName("blahblah2").Value
据我了解,这可以通过创建一个支持 getByName 的“UnoService”来完成,然后以某种方式将这些道具分配给该服务 哪种服务“最轻”? (我是指使用较少资源的服务)
提前致谢。
【问题讨论】:
【参考方案1】:真正支持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 一样支持类编程。
示例:
创建一个名为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
【讨论】:
【参考方案2】: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 中创建一个实现 XPropertySet 的新类。但是,Basic 使用辅助函数而不是类方法。
【讨论】:
(函数是 GetPropertyByName 所以返回值应该有那个名字) 我过去都使用过(集合样式和像 GetPropertyByName 那样搜索数组成员的函数),但我的“想法”是使用类似于现有结构的东西,认为它会更有效并且更快。【参考方案3】:我认为 serviceEnumerableMap 是答案(到目前为止)。创建值并搜索它们比在动态数组中创建道具并在基本中使用 for 循环搜索它们要快得多。 (我“不敢”使用“选项兼容”,虽然我对 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
【讨论】:
以上是关于支持 getByName 的最简单的 Unostructure的主要内容,如果未能解决你的问题,请参考以下文章
InetAddress.getByName(ip).isReachable(timeout);
[java语言]——InetAddress类的getByName()方法
在java中,InetAddress.getLocalHost() 和 InetAddress.getByName("127.0.0.1") 有啥区别
完美解决Android InetAddress.getByName(ip).isReachable(timeout) 一直返回false 的方案
完美解决Android InetAddress.getByName(ip).isReachable(timeout) 一直返回false 的方案