by Unknown user
I originally chose the School.app as my test bed for applying my many-to-many checkbox classes to an ABC app. I had a browse that looked like this:
...
I previously created a persister class that can write the linking data to a TPS file, and looking at that code I can see that it contains much of the code that I'll need if I want to write to any file managed by the ABC classes. But I don't want to derive my ABC persister from that class because CML_Data_ManyToManyLinksPersisterForTPS contains an actual definition if definition of a TPS file which I won't use and which will only confuse the situation.
...
When I first threw the checkbox code into my test app I put together a couple of routines in place of some embed code. I didn't have a really good reason for doing that (too many legacy apps on my brain lately?), and when Mike Hanson looked at the code he quickly pointed out that the code should be in local class methods.
Here's the procedure-level class that wraps up all of the functionality:
Code Block |
---|
CheckboxList class ListCheckbox &CML_UI_ListCheckbox Persister &CML_Data_ManyToManyLinksPersisterForABC Links &CML_Data_ManyToManyLinks Construct procedure Destruct procedure DisplayCheckboxData procedure Init procedure LoadEnrollmentData procedure SaveEnrollmentData procedure end |
And here are the methods, declared at the end of the procedure:
Code Block |
---|
CheckboxList.Construct procedure code self.ListCheckbox &= new CML_UI_ListCheckbox self.Persister &= new CML_Data_ManyToManyLinksPersisterForABC self.Links &= new CML_Data_ManyToManyLinks CheckboxList.Destruct procedure code dispose(self.ListCheckbox) dispose(self.Persister) dispose(self.Links) CheckboxList.DisplayCheckboxData procedure code self.ListCheckbox.LoadDisplayableCheckboxData() CheckboxList.Init procedure code self.Persister.Init(Access:Enrollment,ENR:kStudentIDCourseInstanceID,| ENR:StudentID,ENR:CourseInstanceID) self.Links.SetPersister(self.Persister) self.ListCheckbox.Initialize(Queue:Browse,Queue:Browse.InClass_Icon,| Queue:Browse.CLA:CourseInstanceID,?List:Enrollment,,self.Links) CheckboxList.LoadEnrollmentData procedure code log.write('CheckboxList.LoadEnrollmentData') self.SaveEnrollmentData() StudentBrowse.UpdateBuffer() self.links.LeftRecordID = STU:StudentID self.Links.LoadAllLinkingData() self.ListCheckbox.LoadDisplayableCheckboxData() display(?List:Enrollment) CheckboxList.SaveEnrollmentData procedure code self.Links.SaveAllLinkingData() |
...
To be safe, call either MyBrowse.UpdateBuffer (which fetches the highlighted record from the queue and updated the corresponding fields in the record), or MyBrowse.UpdateViewRecord (which additionally fetches the record from the database). Avoid Avoid low level code like GET(Queue:Browse:1,CHOICE(?Browse:1)).
...
I thought I was all set, but my procedure still had some serious problemsissues. I discovered that although my linking records were saved to the database, the display was more than a little funky especially when I tried scrolling through the page loaded list of courses.
...
This time the problem was with the scroll bar buttons. When you click a scroll bar button the list box doesn't fire a TakeNewSelection event until you release the mouse. Meanwhile any new list box items that scroll up don't have their list boxes drawn:
The first solution I settled on tried was to add one line of code to the end of the CheckboxList.DisplayCheckboxData method:
...
That partially solved the problem. While the mouse was held down the icons were still blank, but as soon as I released the mouse the icons were drawn. I also tried a Display() on the list but that caused the entire control to flicker. I think I'll need to take control of the icon value in SetQueueRecord.Although the code still has a flaw I haven't fixed to my satisfaction, I did find it
I fixed the problem by adding a method call to the SetQueueRecord method, which is where you normally insert code to modify the displayed values.
Here's the code for SetCheckboxIcon:
Code Block |
---|
CheckboxList.SetCheckboxIcon procedure
code
if self.links.IsLinkBetween(self.Links.LeftRecordID,self.ListCheckbox.ListQRightRecordID)
self.ListCheckbox.ListQIconField = CML_UI_ListCheckbox_TrueValue
else
self.ListCheckbox.ListQIconField = CML_UI_ListCheckbox_FalseValue
end |
As all of the values specified here are already being tracked by the classes I think I can move the code down a level rather than have to write it out every time I use the classes. I'll look into that next time.
A nice side effect
The checkbox list has a benefit I hadn't really thought through beforehand. Ordinarily if you have a child list box, any time you change the parent list box selection the child list box reloads completely. But because the list of linking records is managed internally by the class, and then applied to the right hand list box in whatever state it happens to be, you can go to whatever page you want on the right hand list box, then select any record on the left hand list box and the right hand list box will still display the same records. Only the checkboxes will change based on the underlying data.
...
I often have this experience when writing classes - although there's more work up front, there are many little paybacks (and sometimes big paybacks) later on in the process.
Next time: A template to make it all easy.
Download the source (the checkbox classes are also available on GitHub but are not yet exported from the library).