Using an Offscreen Window to do a Scripts Work

By Daniel Wood, 15 December 2010

This is a simple technique that I use all the time and find works very reliably. It involves having a script create a new window into which the script executes it's necessary steps, before closing it when done.

Sometimes during a scripts execution it may be required to switch the current layout to another, perform some operations on that other layout, before returning back to the main layout. When this happens, the user should expect to see nothing out of the ordinary occur - to them, the layout didn't change at all.

There are however a number of things that will change/happen when a layout loads:

  • Tab controls will revert to their default tab
  • Portals will reset to the top of the list
  • OnLayoutLoad and OnRecordLoad script triggers will execute if set.

Sometimes these are undesirable and you don't want them to happen when a script is run. To remedy this, you can use the offscreen window technique.

As an example, consider a simple 2 table database, containing a Customer table, and an Invoice table. A one to many relationship exists between the two, that is to say, one Customer may have many Invoices.

The customer "Joe Bloggs" has about 100 invoices, which are displayed in a portal on the layout. In addition to this, there is a tab control object with 4 tabs to separate information such as "Personal Details" , "Banking" , "Relationships" and "Invoices".

One of the databases features is a "Duplicate Invoice" button that is located inside the Invoices portal. When a user clicks the duplicate invoice button, the selected invoice needs to be duplicated.

A typical script to duplicate the chosen invoice might look like this:

Set Variable [ $InvoiceNumber ; Get ( ScriptParameter ) ]
Go to Layout [ "Invoices" (Invoices) ]
Enter Find Mode []
Set Field [ Invoices::Invoice Number ; $InvoiceNumber ]
Perform Find []
Duplicate Record/Request
Go to Layout [ Original Layout ]

Here, the chosen Invoice number from the portal is passed as a script parameter. The script goes to the Invoices layout, finds the invoice in question, and duplicates it before returning back to the original layout.

The trouble here lies with what happens when the script returns to the original layout:

  • The visible tab will no longer be "Invoices", instead, it will revert back to the default tab, most likely "Personal Details". For the user, all they will see is a tab change, with no other feedback, it is a very disorientating and unwanted result.
  • The invoices portal will have jumped back to the top. If the Invoice the user clicked was halfway down the portal, it will no longer be visible.
  • If the layout has any OnLayoutLoad, or OnRecordLoad triggers, they will run. This can be particularly annoying especially if these scripts do unintended user interface things (such as changing tabs, or record).

And the Alternative Approach:

The alternative approach here is to first create a temporary offscreen window, have the script operate in that window, and close it when done. The main benefit of this approach is that the original window remains untouched, this means active tabs will be preserved, script triggers will not run, and no portal positions will be affected.

The modified script is shown below, with new steps in bold:

 

Set Variable [ $InvoiceNumber ; Get ( ScriptParameter ) ]
New Window [Name: "Temp"; Height: 0; Width: 0; Top; 0 ; Left: -5000]
Go to Layout [ "Invoices" (Invoices) ]
Enter Find Mode []
Set Field [ Invoices::Invoice Number ; $InvoiceNumber ]
Perform Find []
Duplicate Record/Request
Close Window [ Current Window ]

Here, you can see a new window is created as the second step. It's left coordinate is set at a low negative number, ie -5000. The script executes in this window, before closing when done.

It may be that -5000 may not work for you, it all depends on your screen size, or whether you operate dual monitors. Whatever the case, a negative number should be found that works for you. To abstract this, you could set this value into a global variable $$OffScreenLeft upon startup. This means you will only need to set it in one place in your solution.

You should also note that given the fact an offscreen window is created, we don't want to end up in the situation where the script bombs out, leaving the user in this small offscreen window. Even worse, you don't want to leave this window open ever or it may create confusion later on. You will need to be smart in your scripting to ensure that no situation will arise where this window can be left open.

In the case of the script above, I felt it safe enough not to include error checking on the find, however if you feel the script may be used elsewhere, or for another purpose, it may be useful to include error checking, such as the following (in bold):

 

Set Variable [ $InvoiceNumber ; Get ( ScriptParameter ) ]
New Window [Name: "Temp"; Height: 0; Width: 0; Top; 0 ; Left: -5000]
Go to Layout [ "Invoices" (Invoices) ]
Enter Find Mode []
Set Field [ Invoices::Invoice Number ; $InvoiceNumber ]
Set Error Capture [ On ]
Perform Find []
Set Variable [ $Error ; Get ( LastError ) ]
Set Error Capture [ Off ]
If [ Get ( LastError ) = 0 and Get ( FoundCount ) = 1 ]
Duplicate Record/Request
End If
Close Window [ Current Window ]

Here, error checking has been added to the find to ensure that a) the find is successful, and b) that we are only going to duplicate 1 invoice only. Whether or not the script worked or not, a window was created, and thus must be closed as the final step.

Final Thoughts..

Remember, you are ultimately building databases for users, and so usability and the users experience should be one of your top priorities when developing a solution, more often than not it is the little things that matter!

Something to say? Post a comment...

Comments

  • John Vermeulen 09/08/2014 9:03pm (6 years ago)

    This method works fine but while working under Windows with a maximized window, when the temp window is created, the current window will be 'unmaximized'. It can be maximized again after the temp window is closed but the user will experience some (confusing) screen flicker. I couldn't find a way around that so far.

  • Jack Rodgers 10/01/2011 12:01pm (10 years ago)

    One additional value of opening a new window, whether or not it is off screen.

    Changing layouts causes Filemaker to save the record but NOT if you open a new window.

    You may not want to save the record (reason currently unknown).

    You do not want to lose control of that record by releasing it into the unknown of your local lan or the world at large.

    Commiting the record triggers a follow up script and you aren't ready for that.

RSS feed for comments on this page | RSS feed for all comments