How to manipulate GUI controls when loading a form?

Questions

  1. How should I correctly initialise GUI controls so that my example always works?
  2. Can I bind the checkbox status directly to the current dataset?
  • like an expression: id > 0 for checked and otherwise unchecked

Problem

Short:

Autochecking a checkbox when loading my form (in view mode) sometimes isn’t working.

Details:

I have a checkbox that is checked or unchecked depending on a foreign key being null or not. There is a drop down list that will be toggled active/inactive accordingly. The drop down list is also toggled when checking / unchecking the checkbox.

This works so far. But in some cases, which I CANNOT reproduce, it just doesn’t. When this happens it loads the default status for the checkbox (unchecked) and for the list (disabled). After a crash and restore it was always disabled until I opened the odb again some time later.

I think the GUI form might sometimes not be done initialising when I try to access the bound column. And then it just does not toggle the drop down list. But I don’t understand why that would happen.

Maybe I have to bind it to the MainForm loading instead of the form document opening? The problem testing a solution is that it happens very rarely. So I will not know if something worked or not. That’s why I hope someone has an idea or an example how this is usually done.

Example

I reused my dog database example (see my other question for DB details). It happens in this example too, just very rarely. I left my macro structure as close to the original as possible just in case variable scope is the reason. Hope it is not confusing.

CheckboxTest.odb

Edit a dog

How to reproduce (happens very rarely) :

  1. open “Dogs” form
  2. double click a dog without an owner (this will open the “Dog” form)
  3. apply an owner to the dog
  4. save and go back
  5. open any dog that has an owner
  6. the checkbox will be unchecked and the list will be disabled
  7. if it’s not disabled remove an owner from a dog, save, then go back to 2
  • it can help to close the odb first, then go back to 1

Relevant Macros

Only some parts here. See example file for full macros. You can enable DEBUG_MODE in utils if you want to see message box popups for each step.

utils

REM Return a form by name
Public Function GetGuiForm(formDocName As String, formName As String) As Object
	Dim formDoc As Object
	formDoc = ThisDatabaseDocument.FormDocuments.getByName(formDocName)
	GetGuiForm = formDoc.Component.DrawPage.Forms.getByName(formName)
End Function

Public Function IsDoubleClick(event As Object) As Boolean
	IsDoubleClick = event.ClickCount > 1
End Function

frm_dog

REM  *****  BASIC  *****

REM Form: Dog

Option Explicit
Option Compatible

Public Property Get FORM_NAME As String
	Static thisName
	thisName = "Dog"
	FORM_NAME = thisName
End Property

Private Const GUI_FORM_MAIN = "MainForm"
Private Const GUI_CHK_OWNER = "chk_hasOwner"
Private Const GUI_LST_OWNERS = "lst_owners"

Private Const COLUMN_OWNER = "owner_id"

REM When opening the form
Sub OnLoad
	utils.Debug("OnLoad called", "frm_dog:OnLoad")
	utils.Maximise()
	Init()
End Sub

REM Load filter data and set MainForm filter
Sub Init()
	utils.Debug("Init called", "frm_dog::Init")
	Dim sQuery As String
	sQuery = "SELECT  ""filter_int"" FROM ""_Filters"" WHERE ""filter_name"" = 'Forms_Dog'"
	
	Dim oResult As Object
	oResult = utils.SQL_getQueryResults(sQuery)
	
	Dim dogId As Integer
	While oResult.next
  		dogId = oResult.getInt(1)
	Wend
	utils.Debug("DogId from Filter: " & dogId, "frm_dog::Init")

	Dim oMainForm As Object
	oMainForm = utils.GetGuiForm(FORM_NAME, GUI_FORM_MAIN)
	oMainForm.Filter = "dog_id = " & dogId
	utils.Debug("Set MainForm filter to: " & oMainForm.Filter, "frm_dog::Init")

	utils.Debug("Reloading MainForm now", "frm_dog::Init")
	oMainForm.reload()	
	
	SetOwnerStatus()
End Sub

REM Go back to dogs overview
Sub SwitchToDogs()
	utils.SwitchForm(FORM_NAME, frm_dogs.FORM_NAME)
End Sub

REM Check owner checkbox if this dog has an owner
Private Sub SetOwnerStatus()
	utils.Debug("SetOwnerStatus called", "frm_dog::SetOwnerStatus")
	Dim oMainForm As Object
	oMainForm = utils.GetGuiForm(FORM_NAME, GUI_FORM_MAIN)
	
	Dim chkOwner As Object
	chkOwner = oMainForm.getByName(GUI_CHK_OWNER)

	Dim bStatus As Boolean
	Dim dataExists As Boolean
	dataExists = oMainForm.Columns.hasByName(COLUMN_OWNER)
	utils.Debug("MainForm column '" & COLUMN_OWNER & "' exists: " & dataExists, "frm_dog::SetOwnerStatus")
	If dataExists Then
		Dim colOwner As Object
		colOwner = oMainForm.Columns.getByName(COLUMN_OWNER)
		utils.Debug(COLUMN_OWNER & ".Value = " & colOwner.Value)
		bStatus = (NOT colOwner.wasNull()) AND (NOT IsEmpty(colOwner.Value))
	End If
		
	Dim status As Integer
	If bStatus Then status = 1
	chkOwner.State = status
	utils.Debug("Checkbox set to '" & status, "frm_dog::SetOwnerStatus")
	
	If dataExists Then ToggleOwners()
End Sub
    
REM Enable/Disable dropdown list depending on checkbox status
Sub ToggleOwners()
	utils.Debug("ToggleOwners called", "frm_dog::ToggleOwners")
	CONST CHECKED = 1
	
	Dim mainForm As Object
	Dim lstOwners As Object
	Dim chkOwner As Object
	
	mainForm = utils.GetGuiForm(FORM_NAME, GUI_FORM_MAIN)
	chkOwner = mainForm.getByName(GUI_CHK_OWNER)
    lstOwners = mainForm.getByName(GUI_LST_OWNERS) 

	If chkOwner.State = CHECKED Then
		utils.Debug("Owners checked, enabling dropdown list", "frm_dog::ToggleOwners")
		lstOwners.Enabled = True
	Else
		utils.Debug("Owners unchecked, disabling dropdown list and clearing its value", "frm_dog::ToggleOwners")
		lstOwners.Enabled = False
		lstOwners.SelectedValue = ""
		mainForm.Columns.getByName(COLUMN_OWNER).updateNull()
	End If
End Sub

LO

Version: 7.1.3.2 (x64) / LibreOffice

OS: Win10

Hello,

On Ubuntu 20.04 and LO v7.1.3.2 and I cannot get it to fail. Have used you testing process. Will try a bit later on Win 10.

Hey, thanks for having a look. I’ll give it a try with Ubuntu too.

As I mentioned it happens rarely so I don’t know what affects it. Once it happens all the dogs show up with a disabled list and unchecked box. I can only fix it by reopening the form or the odb file, I think.

If it is a bug and not wrong code on my part then I would have to remove the checkbox and add an empty item to the top of the dropdown list to mimic that functionality somewhat.

But it would be cool if I could keep the checkbox in.

Hello,

OK, moved over to Win 10 and problem occurred immediately. Was able to remedy.

In Init routine added a Wait statement:

oMainForm.reload()	
Wait 200	
SetOwnerStatus()

200 worked for my system but may need to increase for another.

Thanks. The first few tests looked good. I’ll keep this as unanswered for now in case it’s just coincidence. I will implement it in the real file and then watch it for a few days.

Edit: No issues so far. Seems to be working.