Creating and Using Invisible Window IDs

§%p%§This article was originally published at Kevin Frank's filemakerhacks.com§%/p%§ §%p%§FileMaker is very flexible. As developers we are given options as to how to reference things; fields, scripts and layouts can be referenced by name or number/id. Whilst we know that referencing things by name is more fragile, it is still a very useful capability to have, but it is definitely more robust to reference by ID…§%/p%§ §%p%§Layout Options§%/p%§ §%h4%§Windows are a bit of an odd one out; we can only reference them by name.§%/h4%§ §%p%§Window Options§%/p%§ §%p%§As windows are probably the most likely things to have their names changed during normal day to day usage of a FileMaker Database it would be really useful if we could keep track of them by an ID independent of the displayed window title. Another benefit of having access to an ID to identify a window is that we then have to option to very easily store and access window specific variables. Kevin has made use of window specific variables based upon the window name in several articles and I suggest that access to a numeric ID that was independent of the window title would be an improvement§%/p%§ §%p%§The idea for this article came from a product idea posted to the FileMaker Community requesting native support for window IDs (https://community.filemaker.com/ideas/1169). In the comments to this Idea, David Wikström was kind enough to share a technique he uses to combine a binary representation of a window ID number with the window title using invisible characters. David’s solution (which you can download from the Idea thread on the community site) uses a number of scripts and custom functions and stores data in several global variables using XML.§%/p%§ §%p%§Since version 16, I like to use the native JSON functionality instead of XML and I was inspired by David’s work to change the storage mechanism to JSON. As I discovered when converting another utility solution (BrowserNav) to use JSON, it is possible to significantly reduce the number of global variables used for data storage as the native functions make it really easy to access the information we need. I also decided that I wanted to make adding window IDs as simple and lightweight as possible so that it can easily be added to an existing database.§%/p%§ §%h4%§So here is my solution…§%/h4%§ §%p%§Demo file: WindowID_JSON.fmp12 (requires FM 16 or later)§%/p%§ §%ol%§ §%p%§The window ID is really more like a layout number; it is a simple number based upon the creation order of the windows. So when you open a solution the the first window will have a window ID of §%li%§Open another window and it’s window ID will be 2 and so on. These window IDs are stored in a JSON array with the index position in the array being the window ID.§%/li%§§%/p%§ §%/ul%§ §%pre%§§%code%§ [ null, { "id" : 1, "name" : "WindowID_JSON", "open" : "2019-01-11 1:09:27 PM", "portalFilterValue" : "p" }, { "close" : "2019-01-11 2:17:33 PM", "id" : 2, "name" : "WindowID_JSON - 2", "open" : "2019-01-11 1:49:30 PM" }, { "id" : 3, "name" : "WindowID_JSON", "open" : "2019-01-11 2:17:32 PM", "windowMessage" : "Example of window scoped variable text" } ] §%/code%§§%/pre%§ §%p%§So let’s start by reviewing the contents of the JSON array. The first entry in the array is null as there is no window zero and it is just easier to use the window ID as the array index pointer. The JSON for each window also includes a time stamp for when the window was opened and in the case of window 2, a time stamp when the window was closed. I decided not to reuse the window ID of closed windows as it avoids the possibility of contamination (a new window picking up data from the array that belonged to the previous owner of that window ID). It also makes it easier to count the items in the array and add 1 to get the window ID of the next new window.§%/p%§ §%p%§The JSON for the first window contains the object “portalFilterValue” and the JSON for the third window includes “windowMessage”. These are examples of how this technique can be used to store window specific information. Whilst it would be nice to have variables that are limited to the scope of a window, it seems to me that this is a reasonable alternative that is available now.§%/p%§ §%p%§Now let’s take a look at the windows represented by the above JSON which is stored in a global variable $$WINDOW.JSON.§%/p%§ §%p%§Side by wide windows with the same name§%/p%§ §%p%§The two windows shown above are the same layout in the same file. They appear to have exactly the same name whilst window one has the portal filtered to show only fruits beginning with ‘p’ and window two is displaying the contents of the “windowMessage” object. The final thing to note is that the window IDs are calculated from the window names. The window names are actually different and each includes an invisible binary ID…§%/p%§ §%h4%§Under the bonnet ( or \'lifting the hood\' if you are in the US)§%/h4%§ §%p%§In order to manage the window IDs we need to make use of the OnWindowOpen and OnWindowClose script triggers which are set in File Options:§%/p%§ §%p%§File Options§%/p%§ §%p%§‘WindowOpen’ on the other hand has quite a lot to do:§%/p%§ §%p%§1 Remove any invisible characters from the window title 2 Calculate a new window ID – the number of items in the JSON array + 1 3 Store the window information in a new array item in $$WINDOW.JSON 4 Convert the window ID to binary number 5 Transform the binary number into invisible characters and append it to the window title§%/p%§ §%p%§Two recursive custom functions are needed to convert to and from binary (the release of 17 means that all developers have access to custom functions which is great):§%/p%§ §%ul%§ §%li%§Dec2Bin(integer)§%/li%§ §%li%§Bin2Dec(binary)§%/li%§ §%/ul%§ §%p%§There are also 3 custom functions specific to the technique: §%ul%§ §%li%§Win.ID( WindowTitle ) – extracts the invisible binary ID from the Window Name and converts it to an integer ( I tried to name the parameter ‘WindowName’ but FileMaker wouldn’t let me!)§%/li%§ §%li%§Win.NewName( OldName;NewName ) – This function is designed to be used by the ‘Set Window Title’ script step and ensures that the new name includes the invisible ID and also updates the variable $$WINDOW.JSON§%/li%§ §%li%§Win.Name( WindowID ) – constructs the full Window Name with the invisible binary ID appended from the integer WindowID using the name stored in $$WINDOW.JSON§%/li%§ §%/ul%§ David Wikström’s brilliant idea to convert the Window ID number to binary means that we only need two different invisible characters instead of 10.§%/p%§ §%p%§So to convert our integer Window ID to an invisible binary number we use: §%pre%§§%code%§ Substitute ( Dec2Bin ( $windowID )