Some rough spots exposed by Version 10.2.0.b30

I am seeing some odd behavior with Version 10.2.0.b30 (4183). About a week ago I downloaded it to my M1 Mac, which is running Monterey Version 12.6.1. I am waiting to update to Ventura until I am sure that my current setup with Panorama X is running well.

I did not have any problems with the installation of this new version of Panorama. However, while adding new records and updating others I have seen at least two minor glitches when running my code. If I close Version 10.2.0.b30 and open Version 10.2.0.b24 (3860), all of my code runs without any problems.

I have not yet been able to isolate the first problem that I have had, but I have sorted out the second problem. The change that I made works well for me with my current setup, but I would like to find out if I am missing something.

I add and modify all of my records through a Form that I have set up. It duplicates the fields in the Data Sheet, but the layout is more to my liking. My skills while typing are mediocre at best, so I depend on using Procedures to make things easier. For instance, I have set up code to capitalize when indicated, and to prompt me when necessary to select the proper placement of capitals within a name or to avoid a capital letter at the beginning of a name or inside a name. But that all happens after I have first typed in all of the important information without any capitalization.

The problem is that the new version of Panorama was running this particular Procedure a second time right after I had responded to it the first time. So, it asks me if I want to capitalize this letter, yes or no. And as soon as I make a decision, it asks me again. If I close out Version b30 and open Version b24, the Procedure only runs once.

Version b24 can call this Procedure from the Data Sheet or from the Form. I did not realize that I only needed to call this Procedure from the Data Sheet: it will work when I focus on a name in the Form and select one of the choices it presents. At some point in the distant past when I was first setting up this Procedure, I found that I could not get the Procedure to work in the Data Sheet if the call to the Procedure was only available in the Form. At that time then, I just installed a duplicate call to the Procedure in the Data Sheet code for that Field. And everything worked well until Version b30 was running that code.

Version b30 make two calls to this Procedure, one from the form and one from the Data Sheet. If I respond by making the selection each time, Version b30 is satisfied and moves on to the next step. Now that I know why this is happening, I have removed one of the calls to that Procedure; the one that was in the Form. So, now the only call to the Procedure comes from the Data Sheet. If I am adding information to the Form, when I come to this particular Field the Procedure works correctly and makes the changes that I choose. If I go to the Data Sheet, where the only call to this Procedure resides, the Procedure asks me to make my choices, and then Panorama b30 crashes, almost every time.

Any information would be appreciated. I hope to smooth out the kinks soon.

Ken

First of all, you should delete b24 from your system. And I’m definitely not interested in any reports on how that old version worked.

When you specified field properties, those are not properties of the data sheet. They are properties of the field. For example, if you make a field numeric, it is always numeric, in the data sheet, in a form, wherever. If you attach code to a field, it is always attached to the field, in the data sheet, in a form, etc. So you need to get out of your head that the properties you set apply specifically to the data sheet. The properties panel is in the data sheet, yes, but the properties are not data sheet properties, they are field properties.

On the other hand, if you put code in a form object, that only applies to that particular form object, not to the field itself. So of course that code will not apply to the data sheet, or even to another form or even another object on the form.

You’ve typed in nearly an entire page of text without providing the really useful information of what is the code that you are running. No one here will have any idea how to help without being able to look at the actual code.

Thank you for your response. Yes, I have thought that since the call to the Procedure was triggered from the a particular Field in the Form, the same Field in the Data Sheet might need to make its own call to that Procedure if the adjustments were to be done there.

The Procedure in question is only called by a particular Field; the Field which stores the last name. The code in the Procedure is just a series of manipulations of that last name in order to adjust which letters are capitalized, depending on the type of name that has been entered. So it is a series of repetitive blocks of code for different situations.

I will try to put a copy into this note. I have never done this before, but here goes.

Ken

/*/////////////////////////////////////////////////////////////////////////////////////

    Procedure helps select variations in spelling of last names, including capitalizing
    the second name in a hyphenated name and capitalizing the second letter in names
    with apostrophes after the first letter. 
    
    Called when TEO "LastName" in "Form_Display Separate Selection" selected.

    Field Properties on Data Sheet is set to Auto Caps: Word to capitalize the
    beginning of a word.
    
*//////////////////////////////////////////////////////////////////////////////////////

let startOfWord = ""
let endOfWord = ""
let thirdChar = ""
let shortEndOfWord = ""

//Hyphenated names.
if search(LastName, "-") ≠ 0
	endOfWord = after(LastName, "-")
	startOfWord = before(LastName, "-")	
	endOfWord = upperword(endOfWord)
	LastName = startOfWord + "-" + endOfWord
endif

//Names with apostrophes.
if search(LastName, "'") ≠ 0	
	endOfWord = after(LastName, "'")
	startOfWord = before(LastName, "'")	
	endOfWord = upperword(endOfWord)
	LastName = startOfWord + "'" + endOfWord
endif

//Names with second letter "c". After "Mc" the third letter is capitalized.
startOfWord = left(LastName, 2)
if startOfWord = "Mc"
	endOfWord = after(LastName, "c")	
	endOfWord = upperword(endOfWord)
	LastName = startOfWord + endOfWord
endif

//Names where the first two letters might form a prefix, and where the first letter is always capitalized.
startOfWord = left(LastName, 2)
endOfWord = after(LastName, startOfWord)
thirdChar = left(endOfWord, 1)
shortEndOfWord = after(endOfWord, thirdChar)

if Length(endOfWord) < 3 and (endOfWord contains "a" or endOfWord contains "e" or endOfWord contains "i" or endOfWord contains "o" or endOfWord contains "u")

    gettextdialog LastName, "Prompt", {Capitalize "} + lower(thirdChar) + {" ?}, "Button", "Yes", "Button", "Cancel"
		if info("dialogtrigger") = "Cancel"
			thirdChar = lower(thirdChar)
		else
			thirdChar = upper(thirdChar)
		endif
		
        LastName = startOfWord + thirdChar + shortEndOfWord

        //Adjust the background of TEO "LastName" and focus on TEO "Street" once editing is complete.	    
	    changeobject "LastName", "$Fill", "Hollow"
		changeobject "Street", "$Fill", "Outline"

        //Set TEO "Street" to editing mode.
		objectaction "Street", “open”
endif

if length(endOfWord) > 2 and (startOfWord = "Di" or startOfWord = "La" or startOfWord = "Le" or startOfWord = "Lo")
 
    gettextdialog LastName, "Prompt", {Capitalize "} + lower(thirdChar) + {" ?}, "Button", "Yes", "Button", "Cancel"
		if info("dialogtrigger") = "Cancel"
			thirdChar = lower(thirdChar)
		else
			thirdChar = upper(thirdChar)
		endif
		
        LastName = startOfWord + thirdChar + shortEndOfWord

        //Adjust the background of TEO "LastName" and focus on TEO "Street" once editing is complete.	    
	    changeobject "LastName", "$Fill", "Hollow"
		changeobject "Street", "$Fill", "Outline"

        //Set TEO "Street" to editing mode.
		objectaction "Street", “open”
    endif

//Names where the first two letters might form a prefix, and where the case of the first letter can vary. 
if startOfWord = "da" or startOfWord = "Da" or startOfWord = "de" or startOfWord = "De"
    startOfWord = left(LastName, 1)
    endOfWord = after(LastName, startOfWord)
    thirdChar = left(endOfWord, 1)

    gettextdialog LastName, "Prompt", {Capitalize "} + startOfWord + {" ?}, "Button", "Yes", "Button", "Cancel"
		if info("dialogtrigger") = "Cancel"
			startOfWord = lower(startOfWord)
		else
			startOfWord = upper(startOfWord)
		endif

	LastName = startOfWord + endOfWord
	
	//Capitalize the third letter in this group of names when the first two letters form a prefix.	    
    startOfWord = left(LastName, 2)    
    thirdChar = left(trimleft(LastName, 2), 1)    
    endOfWord = trimleft(LastName,3)
    
    gettextdialog LastName, "Prompt", {Capitalize "} + thirdChar + {" ?}, "Button", "Yes", "Button", "Cancel"        
		if info("dialogtrigger") = "Cancel"
			thirdChar = lower(thirdChar)
		else
			thirdChar = upper(thirdChar)			
		endif		

	LastName = startOfWord + thirdChar + endOfWord
		
    //Adjust the background of TEO "LastName" and focus on TEO "Street" once editing is complete.
    changeobject "LastName", "$Fill", "Hollow"
	changeobject "Street", "$Fill", "Outline"
	
    //Set TEO "Street" to editing mode.
	objectaction "Street", “open”		        
endif

//Names where the first three letters may form a prefix.
startOfWord = left(LastName, 3)
 		
if startOfWord = "Des" or startOfWord = "Mac" or startOfWord = "Van"
    let fourthChar = left(trimleft(LastName, 3), 1)
    endOfWord = trimleft(LastName,4)

    gettextdialog LastName, "Prompt", {Capitalize "} + fourthChar + {" ?}, "Button", "Yes", "Button", "Cancel"        
		if info("dialogtrigger") = "Cancel"
			fourthChar = lower(fourthChar)
		else
			fourthChar = upper(fourthChar)			
		endif		

    LastName = startOfWord + fourthChar + endOfWord
    
    //Adjust the background of TEO "LastName" and focus on TEO "Street" once editing is complete.
    changeobject "LastName", "$Fill", "Hollow"
	changeobject "Street", "$Fill", "Outline"
	
    //Set TEO "Street" to editing mode.
	objectaction "Street", “open”
endif

This procedure never worked properly in the data sheet, in any version of Panorama. It contains numerous changeobject and objectaction statements which can only work in a form, never in the data sheet.

In any case, there is an official method for modifying the tab order. Any other method is not allowed.

The code that runs when you finish editing a field has special restrictions. Panorama is not “free and clear” at that point, it is still processing – this is especially true when the tab key has been pressed. This code must not:

  • change the current field (use the Custom Tab Order technique mentioned above for that)
  • change the current window
  • display an alert or dialot (which is really another way of changing the current window)

What you are trying to do is not supported. If you need to display an alert or dialog, that should be in a separate procedure triggered by a button or menu.

You might be able to get the dialogs to work if you put a wait 0 statement at the beginning. This will definitely not work with the tab key, but might work with Return/Enter. But this is not recommended or supported.

If you want to dynamically change the background of text editors on the fly as you move from field to field then Panorama is probably not the development environment for you. I suggest Xcode with Swift or Objective-C for that level of customization.

Jim, thank you for taking the time to analyze the code in my procedure. I have started to go through the various procedures that I have to see if I have made the same mistakes in other places.

Ken

I was thinking more about automatically run field code over the weekend, and had some additional thoughts that may be helpful. I think some of you tend to think of the automatic field code as being triggered by the Return or Enter key, but there are many other situations where this code is triggered, including:

  • tab key
  • clicking on another field
  • saving the database
  • closing the window
  • many database operations, like sorting, selecting, etc.

Panorama expects the automatic field code to run quickly without making a significant change to Panorama’s state (like opening a dialog or alert, or adding a record), so that Panorama can then continue to complete the operation the user requested. Typically this automatic code is used to change other cells in the current record. It’s not an invitation to completely rewire how Panorama handles data entry.