PUBLIC opagedgrid
SET CLASSLIB TO ab\aw\samples\fic\classe\ficsample.vcx ADDITIVE
opagedgrid=NEWOBJECT("pagedgrid")
opagedgrid.Show
RETURN
**************************************************
#INCLUDE "ab\ab.h"
DEFINE CLASS pagedgrid AS ficfrm
Height = 432
DoCreate = .T.
Caption = "Paged Grid"
_memberdata = ""
Name = "PagedGrid"
cntOK.opgStyle.optClassic.Value = 1
cntOK.opgStyle.optClassic.Left = 0
cntOK.opgStyle.optClassic.Top = 0
cntOK.opgStyle.optClassic.Name = "optClassic"
cntOK.opgStyle.optBS.Left = 0
cntOK.opgStyle.optBS.Top = 30
cntOK.opgStyle.optBS.Name = "optBS"
cntOK.opgStyle.Name = "opgStyle"
cntOK.cmdOK.Name = "cmdOK"
cntOK.imgSrce.Name = "imgSrce"
cntOK.imgHelp.Name = "imgHelp"
cntOK.Top = 11
cntOK.Height = 254
cntOK.Name = "cntOK"
waitpic.Top = 0
waitpic.Name = "waitpic"
lblFiC.TabIndex = 4
lblFiC.Name = "lblFiC"
lblTime.Height = 15
lblTime.Left = 387
lblTime.Top = 416
lblTime.TabIndex = 5
lblTime.Name = "lblTime"
ADD OBJECT cntgrdpage AS ficcntgrdpage WITH ;
Anchor = 15, ;
Top = 12, ;
Left = 12, ;
Width = 678, ;
Height = 257, ;
TabIndex = 1, ;
Name = "cntgrdpage", ;
lbl1.TabIndex = 3, ;
lbl1.Name = "lbl1", ;
LBL4.Name = "LBL4", ;
LBL3.Name = "LBL3", ;
lbl2.TabIndex = 4, ;
lbl2.Name = "lbl2", ;
cntSearch.txtSearch.Name = "txtSearch", ;
cntSearch.lbl.Name = "lbl", ;
cntSearch.Top = 180, ;
cntSearch.Left = 588, ;
cntSearch.TabIndex = 5, ;
cntSearch.Name = "cntSearch", ;
cntNav.IMGREFRESH.Name = "IMGREFRESH", ;
cntNav.cboLines.Name = "cboLines", ;
cntNav.imgTop.Name = "imgTop", ;
cntNav.imgPrev.Height = 11, ;
cntNav.imgPrev.Width = 6, ;
cntNav.imgPrev.Name = "imgPrev", ;
cntNav.spnPage.Name = "spnPage", ;
cntNav.imgNext.Name = "imgNext", ;
cntNav.imgBot.Name = "imgBot", ;
cntNav.Top = 226, ;
cntNav.Left = 336, ;
cntNav.TabIndex = 2, ;
cntNav.Name = "cntNav"
ADD OBJECT pagedgrid.cntgrdpage.grid AS ficgrd WITH ;
Height = 204, ;
Left = 360, ;
ReadOnly = .T., ;
RecordSource = "orders_", ;
TabIndex = 1, ;
Top = 12, ;
Width = 320, ;
AllowCellSelection = .F., ;
Name = "grid"
ADD OBJECT cmgnav AS ficcmg WITH ;
ButtonCount = 4, ;
Anchor = 6, ;
BackStyle = 0, ;
BorderStyle = 0, ;
Height = 36, ;
Left = 152, ;
Top = 231, ;
Width = 176, ;
TabIndex = 3, ;
Name = "cmgNav", ;
Ficcmd1.Top = 2, ;
Ficcmd1.Left = 3, ;
Ficcmd1.Height = 31, ;
Ficcmd1.Width = 36, ;
Ficcmd1.Caption = "|<", ;
Ficcmd1.ToolTipText = "First record", ;
Ficcmd1.Name = "cmdTop", ;
Ficcmd2.Top = 2, ;
Ficcmd2.Left = 46, ;
Ficcmd2.Height = 31, ;
Ficcmd2.Width = 36, ;
Ficcmd2.Caption = "<", ;
Ficcmd2.ToolTipText = "Previous record", ;
Ficcmd2.Name = "cmdUp", ;
Ficcmd3.Top = 2, ;
Ficcmd3.Left = 89, ;
Ficcmd3.Height = 31, ;
Ficcmd3.Width = 36, ;
Ficcmd3.Caption = ">", ;
Ficcmd3.ToolTipText = "Next record", ;
Ficcmd3.Name = "cmdDown", ;
Ficcmd4.Top = 2, ;
Ficcmd4.Left = 132, ;
Ficcmd4.Height = 31, ;
Ficcmd4.Width = 37, ;
Ficcmd4.Caption = ">|", ;
Ficcmd4.ToolTipText = "Last record", ;
Ficcmd4.Name = "cmdBottom"
ADD OBJECT tutoinfoboxfic AS ficebxsrcecode WITH ;
Anchor = 14, ;
Height = 140, ;
Left = 12, ;
TabIndex = 6, ;
Top = 274, ;
Width = 774, ;
ZOrderSet = 21, ;
Name = "tutoInfoBoxFic"
ADD OBJECT ficlbl1 AS ficlbl WITH ;
Anchor = 6, ;
Alignment = 1, ;
Caption = "Navigate records", ;
Height = 17, ;
Left = 24, ;
Top = 241, ;
Width = 125, ;
Name = "Ficlbl1"
PROCEDURE wreadme
lparameters cLangUser
cLangUser = Evl(Evl(m.cLangUser, m.this.wcLangUser), cLangUser())
local result as String
* remove '.F. && ' whenever a translation is available
do case
case .F.
text to result noshow flags 1
endtext
case .F.
text to result noshow flags 1
endtext
case .F.
text to result noshow flags 1
endtext
case .F.
text to result noshow flags 1
endtext
case .F.
text to result noshow flags 1
endtext
otherwise
text to result noshow flags 1
Desktop applications can manage long lists ('000 of records) very easily
Conversely, because of the time it takes to:
- serialize the list on server side,
- transfer the list through the network,
- eventually convert the list into HTML and display it in the browser,
Web Applications need be able to reduce the number of lines loaded in the browser and, very easily load another set of lines.
This list management process is generally called 'paging': the entire list is divided into 'pages' that user can display on demand. Ideally, moving between pages should be pretty fast so that paging provides a similar comfort of use as in the desktop experience.
Obviously, if user can sort the list on a column, generally by clicking the corresponding header, sorting should happen on the whole list and not just on the bunch of lines displayed as a page. Similarly, a search feature should address the full list range.
FoxInCloud addresses this problem in a very simple and handy manner: if you have a grid with a Reccount(.RecordSource) that can be greater than 1,000, and this grid.RecordSource has a primary or candidate key (or you can create one):
- drop your subclass of awCntGrdPage (eg. xxxCntGrdPage) next to your grid
- size and move your container based on awCntGrdPage like the grid, send to the background
- select your grid and CUT it
- enter into the container (right-click, edit) and PASTE the grid inside
- resize the grid to leave some space in the bottom for the page navigation bar
- give the container the SAME NAME as the grid
At run time the container will automatically:
- create a paged cursor derived from current grid.recordSource and set it as the new grid.recordSource
- towards the outside world, appear like the grid; in fact the container fakes to be the grid: when code running in some other member of the form addresses the grid, the container handles the call and defers to the contained grid when appropriate.
As mentioned earlier, this can work only if your grid.recordSource has or can have a primary or candidate key.
If grid.recordSource is a cursor, you can simply index it after generation:
this...grid.recordSource = ''
SELECT ... into cursor grdRecordSource
index on xxx candidate tag xxx && you can also use a composite index expression, eg. xxx+yyy
this...grid.recordSource = 'grdRecordSource'
If grid.recordSource is a view, you can index it after first use, in Form.Load() or, if you prefer open the view in the form's dataEnvironement, in the dataEnvironment cursor object's .Init():
use myView nodata in 0 && you may also opened the view in the dataEnvironnement
select myView
index on xxx candidate tag xxx && you can also use a composite index expression, eg. xxx+yyy
If grid.recordSource is a table, you need to figure what column or expression can be unique across all records; you should do this at design time:
select myTable
index on xxx candidate tag xxx && you can also use a composite index expression, eg. xxx+yyy
endtext
endcase
return m.result
ENDPROC
PROCEDURE Load
lParameters void_reminder_to_call_DoDefault_in_your_subclass_when_all_views_and_cursorAdapters_are_open
&& this code could also be located in dataEnvironment's cursor.Init()
select orders_
index on customer_id+order_id tag cust_ord candidate collate 'machine'
set order to
go top
return DoDefault()
ENDPROC
PROCEDURE grid.RightClick
if m.thisForm.wlHTMLgen
return .T.
endif
thisForm.wMessageBox('aw.vcx!awGrd.this_Access() ' + Textmerge(ICase(;
thisform.wcLangUser = 'fr', [redirige this.Parent vers le parent original (formulaire) :],;
[redirects this.Parent to the original parent (form):];
) + CRLF;
+ [this.Parent: '<<Sys(1272, m.this.Parent)>>', class: '<<m.this.Parent.Class>>', BaseClass: '<<m.this.Parent.BaseClass>>'];
);
, 64;
, 'this.Parent?';
)
ENDPROC
PROCEDURE grid.Init
thisForm.Init_SrceCode(m.this, 'RightClick', .T.)
this.AutoFit('20%')
return DoDefault()
ENDPROC
PROCEDURE cmgnav.Init
local cmd as ficCmd of ficSample
for each cmd in this.Objects foxobject
thisForm.Init_SrceCode(m.cmd, 'click', .T.)
wcPropSaveEdit(m.cmd, 'Enabled')
endfor
return DoDefault()
ENDPROC
PROCEDURE cmgnav.cmdTop.refresh_
this.Enabled = !lBOF(thisForm.grid.RecordSource)
ENDPROC
PROCEDURE cmgnav.cmdTop.Click
if m.thisForm.wlHTMLgen
return .T.
endif
go top in (thisForm.grid.RecordSource)
thisForm.refresh
ENDPROC
PROCEDURE cmgnav.cmdUp.refresh_
this.Enabled = !lBOF(thisForm.grid.RecordSource)
ENDPROC
PROCEDURE cmgnav.cmdUp.Click
if m.thisForm.wlHTMLgen
return .T.
endif
skip -1 in (thisForm.grid.RecordSource)
thisForm.refresh
ENDPROC
PROCEDURE cmgnav.cmdDown.refresh_
this.Enabled = !lEOF(thisForm.grid.RecordSource)
ENDPROC
PROCEDURE cmgnav.cmdDown.Click
if m.thisForm.wlHTMLgen
return .T.
endif
skip in (thisForm.grid.RecordSource)
thisForm.refresh
ENDPROC
PROCEDURE cmgnav.cmdBottom.refresh_
this.Enabled = !lEOF(thisForm.grid.RecordSource)
ENDPROC
PROCEDURE cmgnav.cmdBottom.Click
if m.thisForm.wlHTMLgen
return .T.
endif
go bottom in (thisForm.grid.RecordSource)
thisForm.refresh
ENDPROC
ENDDEFINE