Results 1 to 10 of 36

Thread: cCJGrid with Grouping and Preview Text.

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Feb 2009
    Location
    Birmingham, UK
    Posts
    958

    Default cCJGrid with Grouping and Preview Text.

    I've often pondered how hard it might be to take a cCJGrid and add the ability to group and show preview text. Over the last two days I thought I'd try. And guess what? It turns out the answer is "quite" bordering on "very". But I've had a stab and I thought I'd submit my results.


    A few general statements to begin with.


    I did this 'for fun' and just to see what the results might be. Please feel free to play with the code or change it in any way you so wish. I don't intend to support this or submit new functionality but if anyone else wants to then of course feel free. I can't say I've particularly tested it much either so there could be some unexpected behaviour.


    The Grid is a read-only grid and so is effectively like the cSigCJReportControl. Is it a replacement for the cSigCJReportControl? No. Not at all. The cSigCJReportControl offers greater functionality I'm sure. I'd still advice using the SIG class.


    So if it isn't a replacement for the SIG control then what's the point? Well in a nutshell because it is a subclass of the cCJGrid it means it means that it will work and model just like the cCJGrid. The API is the same. You fill it in the same way. You set properties in the same way. It uses the same events etc. So basically it simply means that you don't have two completely different styles of coding should you already have various cCJGrid objects but would also like to add some read-only style report grids.

    I will attach some images along with the code so you can see the different styles. One if just the plain grid. One is the Grid once grouped. Once is the Grid grouped and also showing preview text. The other is not grouped but still shows preview text.


    It was quite a challenge. The cCJGrid really isn't written in a way that lends itself easily to grouping. Firstly it is in Virtual mode but that's easy enough to turn off. The main challenge is that the Grid and the datasource are kept in synch with each other via use of the ReportControls RowIndex. This is a pointer to the row in the datasource struct such that data can be moved from one to the other.

    So here was the first challenge. Say you add 100 rows to your data source (just in the same way as you would fill a cCJGrid). Once this is grouped in the ReportControl you have more than 100 rows. You have 100 records PLUS the rows that show the Groups. So straight away the Grid and the data source are out of step and you get "Index Number out of Range" errors when it tries to move the cell data in.

    To be honest ultimately to do all this properly you would need to completely re-write the code in the background that concerns the data source and how it is all kept in step but that was too big a job than I was prepared to take on. So I took the pragmatic approach and added dummy group rows in to the data source. This means that the data source should always have the same number of rows as the Grid.

    This is great but then you collapse one of the groups (or expand one). In the ReportControl (cCJGrid) this reduces the number of rows/changes all the Row Indexes (as rows are shunted up) and once more the grid is out of synch with the data source. So the next challenge was to make it that when you collapse a group we also remove the rows from the data source. Conversely when you expand a group you need to put them back in again (so they need to be stored).

    You do all this and you think you're nearly there. But then sorting becomes a problem. Firstly when sorting you need to make sure that rows are sorted within their groups. Secondly if you collapse a group and THEN sort the grid you have to remember to ALSO sort the rows that were temporarily removed from the data source - otherwise when you expand the group and add in the rows they won't honor the current sort order.

    So anyway, most of the code is done inside the DataSource and some in the SortHandler (to make sure we sort within the groups).

    To be honest, it is all a bit messy but at first glance at least seems to work.


    The code is as follows. You create a normal grid and fill it in the normal way:

    Code:
        Object oGroupedGrid is a cCJGrid
            Set Size to 200 300
            Set Location to 0 0
            Set peAnchors to anAll 
    
            Object oCustomer_Customer_Number is a cCJGridColumn
                Set piWidth to 63
                Set psCaption to "Number"
                Send CreateNumericMask 6 0
            End_Object
        
            Object oCustomer_Name is a cCJGridColumn
                Set piWidth to 295
                Set psCaption to "Customer Name"
            End_Object
        
            Object oCustomer_Status is a cCJGridColumn
                Set piWidth to 53
                Set psCaption to "Status"
                Set pbCheckbox to True
                Set psCheckboxTrue to "Y"
                Set psCheckboxFalse to "N"
            End_Object
            
            Object oCustomer_Balance is a cCJGridColumn
                Set piWidth to 114
                Set psCaption to "Balance"
                Send CreateCurrencyMask 6 2
                
                Procedure OnSetDisplayMetrics Handle hoGridItemMetrics Integer iRow String ByRef sValue
                    If (sValue>=1000) Begin
                        Set ComForeColor of hoGridItemMetrics to clRed    
                    End
                End_Procedure
            End_Object
            
            Object oCustomer_State is a cCJGridColumn
                Set piWidth to 50
                Set psCaption to "State"
            End_Object
    
    
            Procedure LoadData 
                Handle hoDataSource
                tDataSourceRow[] TheData
                Boolean bFound
                Integer iRows iNum iName iStatus iState iBalance
                
                Get phoDataSource to hoDataSource
                
                // Get the datasource indexes of the various columns
                Get piColumnId of oCustomer_Customer_Number to iNum
                Get piColumnId of oCustomer_Name            to iName
                Get piColumnId of oCustomer_Status          to iStatus
                Get piColumnId of oCustomer_Balance         to iBalance
                Get piColumnId of oCustomer_State           to iState
                
                // Load all data into the datasource array
                Clear Customer
                Find ge Customer by 1
                Move (Found) to bFound
                While bFound
                    Move Customer.Customer_Number to TheData[iRows].sValue[iNum] 
                    Move Customer.Name            to TheData[iRows].sValue[iName] 
                    Move Customer.Status          to TheData[iRows].sValue[iStatus] 
                    Move Customer.Balance         to TheData[iRows].sValue[iBalance] 
                    Move Customer.State           to TheData[iRows].sValue[iState]
                    Find gt Customer by 1
                    Move (Found) to bFound
                    Increment iRows
                Loop
                
                // Initialize Grid with new data
                Send InitializeData TheData
                Send MovetoFirstRow
            End_Procedure
    
    
            Procedure Activating
                Forward Send Activating
                Send LoadData
            End_Procedure
        End_Object
    This will create a standard cCJGrid.

    So we now change the cCJGrid to be a cCJGroupedGrid. This will then operate in the same way (except will be read-only)

    Then identify the column that you wish to group by and set a property "phoGroupColumn" to that column ID.

    Code:
            Object oCustomer_State is a cCJGridColumn
                Set piWidth to 50
                Set psCaption to "State"
                Set phoGroupColumn to Self
            End_Object
    Here (above) we will group by the state. Compile and Run and will do just that. By default the Group caption will be the value from the column but if you don't want that there is an event where you can change it. Here I will change it to the name of the state instead of the code (although I could have added the name to the datasource in the first place of course!)

    Code:
            Procedure OnSetGroupCaption String ByRef sCaption
                Get Find_Code_Description of Customer_State_VT sCaption to sCaption
            End_Procedure
    This is an event within the Grid, not the column.

    If you want the Groups to be sorted in reverse order there is a property for this:

    Code:
    Set pbReverseGroupOrdering to True
    There is also a property that controls whether you also want to see the row count as part of the group caption.

    Code:
    Set pbShowGroupCounts to True
    By default this IS true but can be set to False.


    As for preview text, you have to add it as the TAG value of the DataSource:

    Code:
                // Load all data into the datasource array
                Clear Customer
                Find ge Customer by 1
                Move (Found) to bFound
                While bFound
                    // You can add preview text by setting it to be the TAG value
                    Move Customer.Comments        to TheData[iRows].vTag
                    
                    Move Customer.Customer_Number to TheData[iRows].sValue[iNum] 
                    Move Customer.Name            to TheData[iRows].sValue[iName] 
                    Move Customer.Status          to TheData[iRows].sValue[iStatus] 
                    Move Customer.Balance         to TheData[iRows].sValue[iBalance] 
                    Move Customer.State           to TheData[iRows].sValue[iState]
                    Find gt Customer by 1
                    Move (Found) to bFound
                    Increment iRows
                Loop
    Once you've done this you can set the property pbShowPreviewText to True (by default it is FALSE)

    Code:
    Set pbShowPreviewText to True

    And that should be that. You don't have to group to show preview text - if you don't set the phoGroupColumn value you can still do everything else.

    Anyway - have fun. It may inspire someone else to take this on further but as I say it is NOT intended to be a replacement for the SIG control. It was done just to see how hard it might be. Others may have tackled this differently but in my desire to try to do something quickly the route I took seemed to be the line of least resistance.

    Oh yes - I should add that because the grid is loading the Customer data you'll need to add the source to the Order Entry sample. Or a copy of.
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	GridGrouped.jpg 
Views:	723 
Size:	36.9 KB 
ID:	5586   Click image for larger version. 

Name:	GridGroupedWithPreviewText.jpg 
Views:	630 
Size:	39.9 KB 
ID:	5587   Click image for larger version. 

Name:	GridNotGrouped.jpg 
Views:	595 
Size:	50.7 KB 
ID:	5588   Click image for larger version. 

Name:	GridNotGroupedWithPreviewText.jpg 
Views:	593 
Size:	64.0 KB 
ID:	5589  
    Attached Files Attached Files
    Last edited by Peter Bragg; 27-Sep-2012 at 10:27 AM.
    My colleagues keep accusing me of plagiarism. But that's their words, not mine.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •