Browse and Grid Performance
Previous topic  First topic  Next topic


Browse and Grid controls base their operation on the GRID model designed for the HBQT library (which is the basis for Marinas-GUI).
Los controles Browse y Grid basan su funcionamiento en el modelo de GRID diseñado para la librería HBQT (que es la base de Marinas-GUI).

In both cases, controls must know in advance which is the maximum number of items available for display (not to be confused with the number of items to display in the window)
En ambos casos, los controles deben saber de antemano, cual es la cantidad máxima de elementos disponibles para mostrar (no confundirse con la cantidad de elementos que va a mostrar en la ventana)

Remember that a Browse Type control is basically a Grid control with the addition of automatic access to the data in a DBF table.
Cabe recordar que un control de tipo Browse es basicamente un control Grid con el agregado de acceso automático a los datos de una tabla DBF.

Grid controls display data from a vector (which is loaded with ADDITEM or ITEMS) and Browse display data from a DBF automatically.
Los controles Grid muestran datos desde un vector (que se carga con ADDITEM o ITEMS) y los Browse muestran datos de una DBF en forma automática.

A Grid control is concerned only to show the number of rows and columns that fit in the available area to him within the window. Therefore, it takes pretty much the same time to show 100 or 10,000 rows, since in both cases only show, for example, 30 or 40 lines, according to the size of the grid.
The total number of items available to display is obtained very easily using the LEN() function applied to the internal vector used to contain the data rows.

Un control Grid solo se preocupa en mostrar la cantidad de filas y columnas que caben en el area disponible para él dentro de la ventana. Por lo tanto, tarda practicamente lo mismo para mostrar 100 rows que 10.000, ya que en ambos casos solo muestra, supongamos, 30 o 40 lineas, de acuerdo al tamaño de la Grid.
La cantidad total de elementos DISPONIBLES para mostrar la obtiene muy facilmente con la funcion len() aplicada al vector interno que utiliza para contener los datos de las rows.


Browse control works very similar to the Grid, but the problem is that the number of records in the table (items available for display) is not always achieved with an acceptable performance.
Un control Browse funciona de forma muy similar al Grid, pero su problema radica en que la cantidad de registros de la tabla (elementos DISPONIBLES para ser mostrados) no siempre se obtiene con una performance aceptable.

For Example:

  • To obtain the number of records in a table, reccount() function is used and does not cause any delay as it takes the information from the header of the DBF
  • To obtain the number of records in an indexed table, ordkeycount() function is used and does not cause any delay as it takes the information from the header of the index.
  • To obtain the number of records in a filtered table is necessary to do a COUNT of the records. This command is very expensive and if the table is very large, the performance of start and refresh of the browse is reduced significantly.
  • To obtain the number of records in a table with the global parameter SET DELETED .T. (not display the deleted records) is necessary to do a COUNT of the records. This command is very expensive and if the table is very large, the performance of start and refresh of the browse is reduced significantly
  • .

    Por ejemplo:

  • Para obtener la cantidad de registros de una tabla se usa la funcion reccount() que no provoca delay alguno ya que toma la informacion del header de la DBF
  • Para obtener la cantidad de registros de una tabla indexada se usa la funcion ordkeycount() que no provoca delay alguno ya que toma la informacion del header del indice.
  • Para obtener la cantidad de registros de una tabla filtrada es necesario hacer un COUNT de los registros. Este comando es muy costoso y si la tabla es muy grande perjudica sensiblemente la performance de inicio del browse y del refresh del browse
  • Para obtener la cantidad de registros de una tabla con el parámetro global SET DELETED en .T. (o sea que no muestre los registros borrados) es necesario hacer un COUNT de los registros. Este comando es muy costoso y si la tabla es muy grande perjudica sensiblemente la performance de inicio del browse y del refresh del browse
  • .


    Refreshing Browse Control:

    The Browse REFRESH method must be used in a very prudent way as it recalculate the number of records in our DBF, in addition to redesigning the control grid that contains the Browse.
    El método REFRESH de un Browse debe utilizarse con suma prudencia ya que vuelve a determinar la cantidad de registros de nuestra DBF, ademas de volver a diseñar la grilla que contiene al control Browse.

    When you execute a REFRESH, the first thing that this method do is:

  • Suspend the sync (if enabled)
  • Suspend the screen refresh.
  • Suspend the callback function (this may not be familiar to the user)
  • .

    Cuando se ejecuta un REFRESH, lo primero que hace dicho método es:

  • Suspender el sincronismo (si esta activado)
  • Suspender el refresco de la pantalla.
  • Suspender la función de CallBack (esto posiblemente no sea familiar para el usuario)
  • .

    Then it is dedicated to rebuild:

  • The fields to display
  • The titles of the columns
  • The widths of the columns
  • The alignments of the columns
  • .

    Luego se dedica a reconstruir:

  • Los campos a mostrar
  • Los titulos de las columnas
  • Los anchos de las columnas
  • Las alineaciones de las columnas
  • .

    Finally calculate the amount of records in the DBF (which as we saw earlier, this process can produce significant time delay according to the number of records, active filters and the state of SET DELETED) and then restore original values of the properties suspended in the first step.
    Finalmente calcula la cantidad de registros de la DBF (que como ya vimos antes, puede producir que este proceso demore gran cantidad de tiempo de acuerdo a la cantidad de registros, los filtros activados y el estado del SET DELETED) y luego vuelve a restaurar los valores originales de las propiedades suspendidas en el primer paso.

    Cases where it is necessary to use REFRESH (after the browse is already in use):

  • When you dynamically add or change a field to display
  • When you add or delete records in the DBF
  • When you change the index of a DBF
  • .

    Casos en los que es necesario usar REFRESH (luego que el browse ya esta en uso):

  • Cuando se agrega o modifica dinamicamente un campo a mostrar
  • Cuando se agregan o eliminan registros a la DBF
  • Cuando se cambia el indice de una DBF
  • .

    Cases in which is NOT necessary to use REFRESH:

  • When you change the value of a field in the DBF
  • When you dynamically add or modify a header of a column
  • When you dynamically add or modify a width of a column
  • When you dynamically add or modify an alignment of a column
  • When within a function the index of the DBF is changed temporarily and then returned to the original index
  • When record position changes
  • .

    Casos en los que NO es necesario usar REFRESH:

  • Cuando se modifica el valor de un campo de la DBF
  • Cuando se agrega o modifica dinamicamente un header de una columna
  • Cuando se agrega o modifica dinamicamente un width de una columna
  • Cuando se agrega o modifica dinamicamente una alineacion de una columna
  • Cuando dentro de una funcion se cambia el indice de la DBF temporariamente y luego que retorna el indice original
  • Cuando se cambia de registro posicionado.
  • .


    DISABLESYNC:

    The Browse control remains by default a sync with the DBF table specified in the WORKAREA property, this means that every time we change our row, the table pointer automatically moves to the corresponding register in DBF table.
    El control Browse mantiene por default un sincronismo con la tabla DBF especificada en la propiedad WORKAREA, esto significa que cada vez que nos cambiamos de row, el puntero de la table se mueve automáticamente al registro de la DBF que se corresponde.

    This behavior is suspended with DISABLESYNC property:
    Este comportamiento se suspende con la propiedad DISABLESYNC:

    mg_Set( "myWin" , "myBrowse" , "DisableSync" , .T. )

    and re-activate with:

    y se vuelve a activar con:

    mg_Set( "myWin" , "myBrowse" , "DisableSync" , .F. )

    Note that this synchronization can interfere with movements in the record pointer that the programmer want to perform in the DBF that is related to the browse.
    So when you want to change the register position of a browse through a DBSEEK, DBGOTO, etc.., It is recommended to use a routine like this:

    Nótese que este sincronismo puede interferir con movimientos en el puntero de registro que el programador desee realizar en la DBF que se tiene relacionada al Browse.
    Por eso, cuando se desea cambiar de registro de un browse por medio de un DBSEEK, DBGOTO, etc., lo aconsejado es utilizar una rutina similar a esta:


    Function ProgressiveSearch( cName )
       LOCAL nRecOld := d_browse->( recno() )
       LOCAL bSync := mg_Get( "d_window" , "myBrowse" , "disableSync" )
       if len( cName ) > 0
          cName := padr( upper( cName ) , len( d_browse->myName ) , " " )
          mg_Set( "d_window" , "myBrowse" , "disableSync" , .T. )
          d_browse->( dbgotop() )
          d_browse->( dbseek( cName , .T. ) )
          mg_Set( "d_window" , "myBrowse" , "value" , mg_getVisibleOrdKeyNo( "d_browse" ) )
          mg_Set( "d_window" , "myBrowse" , "disableSync" , bSync )
       endif
    Return .T.


    That is,
    1 .- save the current state of DISABLESYNC
    2 .- put DISABLESYNC property on. T.
    3 .- do needed movements in the DBF
    4 .- change the pointer in browse control
    5 .- return to the initial state of DISABLESYNC


    O sea,
    1.- se guarda el estado actual del DISABLESYNC
    2.- se pone el DISABLESYNC en .T.
    3.- se hacen los movimientos necesarios en la DBF
    4.- se cambia el puntero en el control browse
    5.- se vuelve al estado inicial del DISABLESYNC


    Note that item 4 is crucial, because if we do not change the position line of the browser with the DBF record, when we activate the sync, our DBF will re-position itself in the registry that corresponds to the line of control Browse.
    So, if before register change were in line 3 of the browse , which corresponds to register 3 of the DBF and then jump to record 10 of the DBF record whitout reposition the Browse on line 10, when whe activate the synchronism, the pointer inside the DBF return to 3 (which correspond to the line 3 of the Browse control )
    In the Browse tab of maindemo you can see working this methodology

    Nótese que el item 4 es fundamental, porque si no posicionamos la linea del Browse con el registro de la DBF, cuando volvamos a activar el sincronismo, nuestra DBF va a volver a posicionarse en el registro que se corresponde con la linea del control Browse.
    O sea, si antes de cambiarnos de registro estabamos en la linea 3 del Browse que se corresponde con el registro 3 de la DBF y despues de saltar al registro 10 de la DBF no volvemos a posicionar el Browse en la linea 10, cuando activemos el sincronismo, el puntero dentro de la DBF volverá al registro 3 (que se corresponde con la linea 3 del control Browse)
    En la pestaña Browse del maindemo se puede ver funcionando esta metodología



    DISABLEUPDATE:

    If you want to update many rows and you want that the Grid or Browse control do not produce a "flicker" effect while we make our changes, we can eliminate that behavior suspending control update temporarily and then back on.
    Si se desea realizar una actualización de gran cantidad rows y se desea que el Browse o la Grid no produzcan un efecto de "parpadeo" mientras realizamos nuestra operación, podemos eliminar dicho comportamiento suspendiendo la actualización del control en forma temporaria y luego volver a activarlo.

    For Example:
    Por ejemplo:

    Function MyAddRows()
       LOCAL nInx
       mg_Set( "d_window" , "myGrid" , "disableUpdate" , .T. )
       for nInx := 1 to 100
          mg_Do( "d_window" , "myGrid" , "additem" , { nInx , "Item " + str( nInx ) } )
       next
       mg_Set( "d_window" , "myGrid" , "disableUpdate" , .F. )
    Return .T
    .



    Marinas-GUI Version 03.06 and
    Marinas-IDE Version 05.06 and
    LEX Files Version 02.06


    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    last update: April 27
    2017
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------




    A Harbour/QT framework to make multiplatform programs

    (©) Copyright 2009-2017 by Fernando Santolin (aka CarozoDeQuilmes)
    CarozoDeQuilmes@gmail.com

    2009-2017 Beta tester and full English translator: Bruno Luciani
    Bruno.Luciani@gmail.com

    2014-2015 Final English corrector: David Worboys
    DavidWorboys@hotmail.com

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    www.marinas-gui.org


    www.marinas-gui.org  

    Previous topic  First topic  Next topic