Monday, May 5, 2014

More Objects in a Grid Cell - Part III

I shared last time a way to show several objects within a grid's cell and I was surprised that it landed 2nd on my top posts.  Said tutorial and sample uses 4 containers, if I can recall properly, and usage of DynamicCurrentControl.  I did that when I was still in the process of experimenting on my assets masterfile module of which I use a grid with 3 columns with each columns showing different info:


This blog though achieves the same result, deals with using a single container. Manipulation is done via Dynamic Fake method approach.  Using this approach will give you more control over the objects inside a grid cell and can control those better to suit your needs.  Please read on:

What is Dynamic Fake Method?

In VFP, we are given several Dynamic Properties on grid for the purpose of showing Dynamic results based on conditions.  When we say Dynamic, it means it is changing.  And so if you wanted to show for instance different backcolors of cells based on conditions, then you will have to use DynamicBackColor.  If you want to show different objects in a column like for one cell a textbox, the next cell an editbox, the 3rd a spinner... you can use DynamicCurrentControl.  If you want to change bolding of fonts, use DynamicFontBold like this:

This.Column1.DynamicFontBold = "IIF(alltrim(gender)='Male',.T.,.F.)"

And that will show the Gender column on an alternating Bolded font and not.  Some more Dynamic Properties are DynamicFontItalic, DynamicAlignment, etc (please look at your grid properties in PEM).

But aside from those fixed usage, I am not sure if this is by design or an unexpected feature of VFP's Dynamic Properties, we are allowed to use certain Dynamic Properties on something not totally meant for its name, i.e., via redirecting those to a form method instead and so the term DynamicFake Method.  For instance, in this sample, I will be using DynamicFontBold but not to control bolding or not of a font but to manipulate all the objects inside the container inside the cell.

How Does DynamicFake Method works?

This works via passing a parameter of the objects you wanted to control later to the method you will create.  The method does not need to be necessarily named Fake or similar but since the first developers who found this out and shows us as well coined the DynamicFake method name, then I will use the same as I agree we are faking those dynamic properties into believing they are doing what they are meant to do.  But we control the naming of a method so you can give it any name you like such as ScoobyDoo if you wish.

Now in this sample, I use one container and 5 labels.  You can use any objects you like and put those inside said container like a checkbox, spinner, editbox, textbox, etc.  But this is just a demo and I am fine with labels so 5 labels.  We can either pass all objects individually (in this case 5 labels) or just pass the container object.  I prefer to do the latter.

From inside that method, I now control things like forecolor, fontbold, fontname, fontsize, etc.  Again, we are not limited onto those.  You can manipulate those objects based on its available properties.  Sky is the limit per object's available properties, your choice.

DynamicFake Method implemented



Sample Codes


loTest = Createobject("Form1")
loTest.Show(1)

Define Class Form1 As Form
      AutoCenter= .T.
      Height = 400
      Width = 600
      Caption = 'DynamicFake Method Trick'

      Add Object grid1 As Grid With ColumnCount= 1,;
            Top = 0, Left = 0, HeaderHeight= 0, Width = Thisform.Width, Height = Thisform.Height,;
            RowHeight= 70, RecordMark= .F.,DeleteMark= .F., ScrollBar = 2

      Procedure Load
      Select * From Home(2)+'Northwind\employees' Into Cursor junk NOFILTER
      Endproc

      Procedure Init
      With This.grid1 As Grid
            .RecordSourceType= 1
            .RecordSource= 'junk'
            .Column1.RemoveObject('Text1')
            .Column1.AddObject('Container1','myContainer')
            .Column1.Container1.Visible = .T.
            .Column1.Sparse = .F.
            .Column1.DynamicFontBold = 'thisform._DynamicFake(this.Column1.Container1)'
            .Column1.Width = 590

      Endwith
      Endproc

      Procedure _DynamicFake
      Lparameters oContainer
      Local lcCountry, lcCity, lcEmployee, lcTitle

      * Manipulate Country label
      lcCountry = Alltrim(Country)
      oContainer.lblCountry.ForeColor= Iif(m.lcCountry='UK',Rgb(0,128,255),Rgb(255,0,0))
      oContainer.lblCountry.Caption= m.lcCountry
      oContainer.lblCountry.FontSize= 14

      *Manipulate City label
      With oContainer.lblCity As Label
            lcCity = Alltrim(City)
            .Caption = m.lcCity
            .ForeColor = Icase(m.lcCity = 'Seattle',Rgb(128,128,255),m.lcCity = 'Tacoma',Rgb(0,128,0),;
                  m.lcCity = 'Kirkland',Rgb(255,128,0),m.lcCity = 'Redmond',Rgb(0,128,255),Rgb(255,0,128))
            .FontItalic= .T.
      Endwith

      * Manipulate Employee label
      With oContainer.lblEmployee As Label
            lcEmployee = Alltrim(titleofCourtesy)+' '+Alltrim(firstname)+' '+Alltrim(lastname)
            .Caption = m.lcEmployee
            .FontBold=.T.
            .ForeColor= Rgb(255,128,0)
            .FontName= 'Calibri'
            .FontSize= 20
      Endwith

      * Manipulate Title
      With oContainer.lblTitle As Label
            lcTitle = Alltrim(Title)
            .Caption = m.lcTitle
            .FontName= 'Calibri'
            .FontSize= 12
            .ForeColor= Icase(m.lcTitle = 'Sales Representative',Rgb(128,0,0),;
                  m.lcTitle = 'Vice President, Sales',Rgb(128,128,255),;
                  m.lcTitle = 'Sales Manager',Rgb(128,128,128),Rgb(128,128,192))
      Endwith

      * Manipulate Date of Birth
      With oContainer.lblDOB As Label
            .Caption = 'Date of Birth: '+Mdy(birthdate)
            .FontName= 'Calibri'
      Endwith
      Endproc

Enddefine

Define Class myContainer As Container
      BorderStyle= 0
      BackStyle= 0
      Height = 70
      Width = 590
      BorderWidth= 0

      Add Object lblEmployee As myLabel With Top = 0, Left = 0
      Add Object lblTitle As myLabel With Top = 30, Left = 0
      Add Object lblCountry As myLabel With Top = 0, Left = 500
      Add Object lblCity As myLabel With Top = 20, Left = 500
      Add Object lblDOB As myLabel With Top = 50, Left = 0
Enddefine

Define Class myLabel As Label
      BackStyle= 0
      AutoSize= .T.
Enddefine

Part III vs Part II Trick

I found this easier to control via codes plus grid is lighter having lesser objects.

Epilogue

Are we limited to the usage of DynamicFontBold for this faking need?  Nope!  All of the Dynamic properties can be faked with only one exception, i.e., DynamicAlignment.  So for instance, instead of DynamicFontBold above, you can do this:

.Column1.DynamicBackColor = 'thisform._DynamicFake(this.Column1.Container1)'

or
.Column1.DynamicCurrentControl = 'thisform._DynamicFake(this.Column1.Container1)'

Actually if I will be faking again in the future, I will use a Dynamic that remained unused for Windows being those are designed for another OS such as:

.Column1.DynamicFontShadow = 'thisform._DynamicFake(this.Column1.Container1)'


So is VFP really powerful?  You bet your a....err.... Without a shadow of a doubt!!!!

Cheers!

2 comments: