As stated earlier, this is not part of LibreOffice but rather a third party add on. Questions on this should be asked of that author and not here on the LO Ask site.
My question is in no way specific to the framework. This is so apparent it is hardly worth saying.
It seems like you are unable to answer the question "set up a listener on [the Form object], one method of which will fire when the form is loaded (opened)", but for some reason don’t want to say so. Such an object can be obtained in a normal macro, as you must be aware.
As you can see from the tentative answer I have given, there is a way of detecting, using a listener, when a form is opened.
No. The problem I have is trying to figure out just what you are trying to accomplish. Have one more post for you → Base macro that opens a new/clean record in another form using python
.
Also did present Calc file showing methods to modify listeners using code. Have come at various angles with this and have no idea why none of this is seemingly near to shat is wanted.
With OooDev
, in script mode, after a document is loaded the Lo.XSCRIPTCONTEXT
is available (or Lo.xscript_context).
The same is true for Lo.this_component.
In Macro Mode Lo.XSCRIPTCONTEXT
and Lo.this_component
are available when the document is opened.
Usually these properties are not needed because OooDev
gives you access to what you need via it various modules such as Calc
, Write
, Char2
etc.
sqlite3 is a built in package of python. The issues is (on Windows) when installing the search tool in a vritual environment set for LibreOffice the sqlite package is missing. This is a LibreOffice thing, LibreOffice does not ship with complete python. See bug 116412. If you install the search tool in a normal python environment it should work fine.
A possible answer. But I think it’s a workaround, not the real answer.
When I click on the form icon and the form opens, I have found that a listener is indeed triggered, but not on the form itself:
doc = Base.open_doc('test_db.odb', loader)
GUI.set_visible(is_visible=True, odoc=doc)
class DocEventListener(unohelper.Base, XDocumentEventListener):
def documentEventOccured(self, event):
print_out_element(event, 'doc event')
doc.addDocumentEventListener(DocEventListener())
… one possible hypothesis is thus that the “property” “When loading” which you can use to attach a macro to the event of a form being opened is in fact a sort of pseudo-property: this event is actually attached to the object at the top of the hierarchy, which I shall refer to as the “ODB document”, with the following spec: implementationName=com.sun.star.comp.dba.ODatabaseDocument, supportedServices={com.sun.star.sdb.OfficeDatabaseDocument,com.sun.star.document.OfficeDocument}
Interestingly, before a form is opened, although it implements the interface XComponent
, actually getComponent()
returns None
. After a form is opened, however, this returns an object, which is essentially a Writer document, since Base forms are obviously modelled on Writer documents. This might explain why form objects implement XCloseListener
, but (apparently) nothing to listen in on the event of opening.
I tentatively call it a “pseudo property”, because the user who edits the form, and attaches a macro to this event, is no doubt tempted to think that they are configuring an event of the form itself. Which then begs the question, are all these form events pseudo properties, or just this one: for example, what about the event “After record change”, which I also need to configure?
A bit later: I now don’t think this is right. Clearly the Writer document which is used to make the component when a form is loaded must be stored somewhere inside the .odb file. Having examined the component after opening, this has a method getEvents
, one of which is OnLoad
(however, there is nothing there which corresponds to the form’s “After record change” event: maybe this can be found from the form’s data provider objects …).
So the question is: how to obtain a reference to this Writer document, before the form is loaded? It must be present in some storage location.
Embedded form opening can be listened to with database document event OnSubComponentOpened.
Interface XDatabaseDocumentUI provides access to the user interface of a database document.
Thanks. I saw from exploration that doc.getEvents()
includes OnSubComponentOpened
(type str
)… but I don’t know how you set up a listener on that. This doesn’t work:
def on_sub_opened(*args, **kwargs):
print(f'args {args} kwargs {kwargs}')
doc.getEvents().OnSubComponentOpened = on_sub_opened
uno.RuntimeException: Couldn’t convert <function main..on_sub_opened at 0x00000125C29F99D0> to a UNO type; caught exception: <class ‘AttributeError’>: ‘function’ object has no attribute ‘getTypes’
I’ve previously added a function-attribute (in the Python sense) getTypes
to the function here. But then I get a fail with
uno.RuntimeException: Couldn’t convert <function main..on_sub_opened at 0x00000275E415C9D0> to a UNO type
… could you show what I’m meant to do?
Re your other point, could you illustrate how I obtain an object which implements that interface? The com.sun.star.comp.dba.ODatabaseDocument
object doesn’t appear to do so.
This is because you start with the most complicated (and underdeveloped and unexplored) component of all. IMHO, whatever you try to do here, will turn out as virtually impossible to do.
In the standard way.
Open the database document and Menu / Tools / Customize… / Events.
Event: “Loaded a sub component”.
@sokol92
Oh dear. From your previous answer I thought you had understood. Please review the posts in this thread, and read the question thoroughly. I am trying to do this programmatically.
You may be the first person ever who wants to do that programmatically. Go ahead and don’t forget to tell us what you found out.
@Villeroy
I’ve already shown one way of doing this, using XDocumentEventListener
.
I don’t know why someone who seems to have no interest in programming UNO using Python, and without the courtesy to have read the question in the first place, would want to contaminate a thread with pointless posts. I’ve heard your opinion. Could you stop posting now? Thanks.
There are many similar examples on the forum.
I stop posting now, Thanks.
For future readers of the topic:
Sub OnSubFormOpened(oEvent)
Msgbox "OnSubFormOpened"
End Sub
Sub AddEventListener
Dim oEvents
Dim mEventProps(1) as new com.sun.star.beans.PropertyValue
mEventProps(0).Name = "EventType"
mEventProps(0).Value = "Script"
mEventProps(1).Name = "Script"
mEventProps(1).Value = "vnd.sun.star.script:Standard.Module1.OnSubFormOpened?language=Basic&location=document"
oEvents=ThisComponent.Events
oEvents.replaceByName "OnSubComponentOpened", mEventProps
End Sub
Thank you for showing how to attach a function to events designated by strings.
But in Python … hmmm! Very intriguing. I’ve just looked at the API and searching to see how a com.sun.star.beans.PropertyValue
is created in Python UNO… and the gist seems to be
event_props = PropertyValue(Name='EventType', Value='Script')
… but as yet I haven’t found an example where, seemingly, you have TWO entries involved in a single PropertyValue
. …
Again, you start at the wrong end. How to create UNO structs in your preferred language should be known before solving esoteric issues.
import uno
prop = uno.createUnoStruct(whatever)
Thanks. You gave me a clue. I’m certainly out of my depth. However, I have a certain belief that most of the objects I want to expose and manipulate in Base shouldn’t be that difficult to get to.
def on_sub_form_opened(*args, **kwargs):
print(f'args {args} kwargs {kwargs}')
sortproptuple=()
PropVal = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
PropVal.Name = 'EventType'
PropVal.Value = 'Script'
sortproptuple+=(PropVal,)
PropVal = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
PropVal.Name = 'Script'
# this next, of course, is very unlikely to result in a call to the above function:
PropVal.Value = 'on_sub_form_opened'
sortproptuple+=(PropVal,)
doc.getEvents().replaceByName('OnSubComponentOpened', sortproptuple)
… last line raised exception:
Traceback (most recent call last):
File "start_base_auto.py", line 337, in <module>
raise SystemExit(main())
File "start_base_auto.py", line 176, in main
doc.getEvents().replaceByName('OnSubComponentOpened', sortproptuple)
__main__.IllegalArgumentException: []any
Its a frustating job with you!
On the one hand, you think you know everything better… on the other hand, you need support at a beginner level.
from com.sun.star.beans import PropertyValue as PropVal
pv_0 = PropVal()
pv_0.Name = "EventType"
pv_0.Value = "Script"
pv_1 = PropVal()
pv_1.Name = "Script"
pv_1.Value = ("vnd.sun.star.script:Standard"
".Module1.OnSubFormOpened?"
"language=Basic&location=document")
doc = XSCRIPTCONTEXT.getDocument()
events = doc.Events
events.replaceByName("OnSubComponentOpened", (pv_0, pv_1) )
Thanks for trying. Unfortunately the same exception gets raised on the last line:
__main__.IllegalArgumentException: []any