Base macro that opens a new/clean record in another form using python

Based on this I created a BASIC macro that opens a form and moves to insert record. The macro also “pokes” a value based on the “caller”.

I tried to move this macro to python but is not working. It looks like the moveToInsertRow has totally different implementation in python than in BASIC (or the forms have different implementation…).

I include an example (testpython.odb) where in form “Companies” there are two buttons. One working using BASIC and a second using python

update: Is this a non reported bug or is by design?

For one thing, the code similar to Basic’s ThisDatabaseDocument should be thisODB = XSCRIPTCONTEXT.getDocument().getParent() when run from inside a form.

Perhaps this bug report is relevant: https://bugs.documentfoundation.org/show_bug.cgi?id=83737. However, since it works from Basic, I’m not sure that’s the issue.

Actually, the problem often occurs in Basic as well. I’m trying to narrow down now under what circumstances it occurs.

Likely it’s a matter of what window has the focus.

Since I have thisODB get its value outside any def (a.k.a. is a global) I think it is not a problem. It works (until now…) even for buttons inside subforms.

As of my understanding, this behavior (of moveToInsertRow) is somehow “by design” since BASIC is executed-interpreted line by line, but python modules are “pre-compiled” before run.

Hello,

First, THIS IS NOT A COMPLETE SOLUTION FOR YOUR QUESTION!

Posting this because I am running out of methods to try & maybe this information along with someone else’s view may provide a complete solution.

Had a similar problem when using a button event in a dialog (see → Dialog problem when using Python). The solution was to use Threading. The basis of the problem was that you couldn’t act on an object which still had a process running. This situation seems similar. When the form is being opened, the record can’t be set because the form won’t be completely opened until Python routine is completed. Kind of a catch-22 situation.

moveToInsertRow does work in Python and can be done from a button on an open form. So this eliminates the question of it working or of a different implementation.

The other noticable item was during a simple test, if the second form was open before the code was run the form would display a new record correctly upon execution of my code. As further evidence of this, using various events I had the routine execute two times and the form opened and was at a new record. Now it seems more obvious as to the similarities to the dialog problem.

However, tried Threading to no avail. Also tried atexit to no success. Have tried multiple variations and other oddball mechanisms but none worked. Again, what does work is to run a script to open the form and when that script completes run a second script to set the form at “new record”. This was accomplished using the Approve action event to open the form & the Execute action event to set form to new record. See → Events

Have attached original sample replacing original embedded python with the two simple python routines for demonstration.

Sample ---- PostedTestPython.odb

Edit 2018-05-29:

It appears both @jimk and I had the correct approach in mind but the wrong items. I have now got a working version. Using the version published by Jim K, changed the items which were threaded. The dialog thread was replaced with the opening of the form itself. The second thread was to pause ( .3 seems to be OK ) while form completed & then set to new record.

Much thanks to @jimk ( & +1 ) for much appreciated help!

Sample #2 ----- RevisedJimKVersion.odb

1 Like

Thanks for making to me clear that from python the form won’t be completely opened until Python routine is completed. I will now need to search other solutions since this is not used in a single form.

Just to make clear. Pausing depends very on CPU, memory, opened applications, user clicks (accidental or not) etc. etc. So, for the moment I am stacked with my BASIC version (which in checked computers works as expected, for the moment).

Even the Basic routine will not work on my Linux Mint 18.3 without the Wait 100. This was missing in your routine (but in original post you refer to) but worked because of MRI ( as mentioned by Jim K in his answer). Your routine as posted above displays MRI & also msg box with Error 1.....Function sequence error ..(line:65).

Regardless, the process works as per the original request.

My “personal…” programming policy prohibits me for using “pause” this way, for reasons mentioned above. I confirm the above error in some computers. Error (as well as scrambling of form’s and subform’s widgets, that pushes some right widgets to left, even when all are anchored to page) occurs only the first time user opens the form. All subsequent opens, show all widgets in place and code seems to work as expected.

In researching another issue, I came back to this post for information on threading in Python. Also reference → Management in status bar

In testing the samples here with threading they no longer worked on my system. This was using LO v7.2.2.2 on Ubuntu 20.4. Loading out an older version (pre v7.0.x) all worked. Increasing the sleep from .3 to 1 again allowed the macros to work with the current version. However this confirms the concerns of the OP.

Now along comes ScriptForge. While I am not a proponent of this library (at least the Base portion), it turns out it will solve the issue here and may be useful in niche situations.

Adding to OP’s original sample:

# Added - for ScriptForge
from scriptforge import CreateScriptService

and with this functions modifications as noted:

def set_form_to_new(opened_form, fieldname=None, fieldvalue=None):

    dataform = opened_form.DrawPage.Forms.getByIndex(0)

    if not dataform.IsNew:#only show if there is at least one record
        #dataform.moveToInsertRow(False) #=> incorrect number of parameters
        #dataform.moveToInsertRow() #=> SQLException

# Commented out of original
#        dataform.moveToInsertRow
#        mri(dataform)

# Added - from ScriptForge
        bas = CreateScriptService("Basic")
        doc = CreateScriptService('SFDocuments.Document', bas.ThisDatabaseDocument)
# Get access to document `Fuel` with internal `Mainform`
        form = doc.Forms("Πληρωμή", 'MainForm')
        form.MoveNew()
# End additional code

there is no longer a need to use threading or wait/sleep times to get this to work.

1 Like

Here is a complete solution, or maybe it could be considered a workaround. What I noticed is that when a window such as MRI is opened first, everything works correctly. This may have been why it seemed to work for your Basic code.

So, my solution creates a threaded dialog to temporarily remove the focus from the form. Then another thread closes the dialog after half a second. Finally, the second thread calls dataform.moveToInsertRow() at the end of the closing thread. These threads allow the form the necessary time to finish.

Here is the modified file: testpython2.ods

This solution would be nearly impossible to implement in Basic. As mentioned in the comments, the problem occurs in Basic as well, so I recommend using Python, which seems to be your goal anyway.

I tested this on Windows. Other operating systems handle window management differently, so the code may need to be adjusted for each operating system.

This ended up being more difficult to solve than expected. I originally tried simply running in a different thread, as probably @Ratslinger tried as well, but apparently, the form does not finish while it has the focus, so it simply blocks forever.

1 Like

@jimk Thanks for some more info. Will take closer look. Have once already seen two forms opened with a single push of the button - one at new record & one at the first record.

As for the comment about the code in basic, my post (in the question) has no problems with the process without MRI. However the code in this sample left out a key element - Wait 100 just before the moveToInsertRow().

@jimk After a lot more tests the two forms opening has not recurred. However, I was getting a fair amount of application freezes at the form opened by the script and was displaying the first record (nothing generated in log file). This was easily rectified by increasing the time delay from .5 to 1 (probably didn’t need to go that high). No problems after that.