Page 1 of 1

Ayuda para desarrollar un control de navegacion y edicion

Posted: Thu Apr 28, 2011 11:08 pm
by carlos vargas
Estimados, todos

Recientement me veo en la necesidad de construir un control que muestre 10 botones en un dialogo:
*4 de ellos son para navegar por la tabla ( Inicio, anterior, siguiente, final), y otros botones para *Localizar, *Listar, *Agregar, *Editar, *Borrar y *Cerrar.
y que en modo Edicion o Agregar registro (*Agregar y Editar) cambien su funcion a *Grabar y *Deshacer, y luego de grabar o descartar _ retomen su funcion inicial.

Mi necesidad es que deseo abandonar la modalidad browse, para centrame en el registro a registro.
por motivo que la app sera cliente/servidor, y todos sabemos que los browse no comulgan bien con esta arquitectura.
he mirado un control en VFP que me gusta y es a lo que aspiro a realizar.

En este momento he avanzado algo, esto es lo que tengo:
una clase para el manejo del movimiento del puntero en la tabla ( TBtnNav ), y una clase derivada para las otras acciones a realizar. ( TBtnABC )


http://www.megaupload.com/?d=J0QMNN6H

Image

test.prg

Code: Select all

PROCEDURE Test()
   LOCAL oDlg
   LOCAL oBNav

   USE D:\FWH\SAMPLES\CLIENTES.DBF NEW ALIAS CUST

   DEFINE DIALOG oDlg NAME "TEST"

   //oBNav := TBtnNav():new( oDlg, "CUST" ) //primera clase
   oBNav := TBtnABC():new( oDlg, "CUST" )    //segunda clase
   oBNav:bOnChange := { | o | msginfo( (o:cAlias)->NOMBRE ) }
   oBNav:SetAction( 10,  {|| oDlg:END() }, "CERRAR TEST" )

   ACTIVATE DIALOG oDlg CENTER

   USE

RETURN
 
clases.prg

Code: Select all

/*-------------------------------------------------------------------------------------------------*/
/*incluye fichero cabezera de sistema*/
#include "hbclass.ch"
#include "fivewin.ch"

/*-------------------------------------------------------------------------------------------------*/
#define BN_TOP      01
#define BN_BACK     02
#define BN_NEXT     03
#define BN_END      04
#define BN_LOCATE   05
#define BN_PRINT    06
#define BN_NEW      07
#define BN_EDIT     08
#define BN_DELETE   09
#define BN_CLOSE    10

/*-------------------------------------------------------------------------------------------------*/

CLASS TBtnNav
   DATA oDlg
   DATA cAlias
   DATA aoButtons
   DATA abActions
   DATA bOnChange

   METHOD New( oDlg, cAlias, bOnChange )
   METHOD DisableAll()                    INLINE AEval( ::aoButtons, { |o| o:disable() } )
   METHOD EnableAll()                     INLINE AEval( ::aoButtons, { |o| o:enable()  } )
   METHOD SetAlias( cAlias )
   METHOD Navigate( cMoveTo )
   METHOD EnableDisable()

ENDCLASS

/*-------------------------------------------------------------------------------------------------*/

METHOD TBtnNav:new( oDlg, cAlias, bOnChange )

   ::oDlg      := oDlg

   ::aoButtons := Array( 04 )
   ::abActions := Array( 04 )

   AFill( ::abActions, {|| NIL } )

   REDEFINE BUTTONBMP ::aoButtons[01] ID 601 OF oDlg BITMAP "BM_DTOP"   ACTION ::abActions[01]
   REDEFINE BUTTONBMP ::aoButtons[02] ID 602 OF oDlg BITMAP "BM_DBACK"  ACTION ::abActions[02]
   REDEFINE BUTTONBMP ::aoButtons[03] ID 603 OF oDlg BITMAP "BM_DNEXT"  ACTION ::abActions[03]
   REDEFINE BUTTONBMP ::aoButtons[04] ID 604 OF oDlg BITMAP "BM_DEND"   ACTION ::abActions[04]

   ::aoButtons[01]:cToolTip := "Primer registro"
   ::aoButtons[02]:cToolTip := "Registro anterior"
   ::aoButtons[03]:cToolTip := "Siguiente registro"
   ::aoButtons[04]:cToolTip := "Ultimo registro"

   IF Empty( cAlias )
      IF Used()
         ::SetAlias( Alias() )
      ENDIF
   ELSE
      ::SetAlias( cAlias )
   ENDIF

   IF bOnChange <> NIL .and. ValType( bOnChange ) == "B"
      ::bOnChange := bOnChange
   ELSE
      ::bOnChange := NIL
   ENDIF

RETURN Self

/*-------------------------------------------------------------------------------------------------*/

METHOD TBtnNav:SetAlias( cAlias )

   ::cAlias := cAlias

   ( ::cAlias )->( DBGoTop() )

   ::aoButtons[ BN_TOP  ]:bAction := {|| ::Navigate( "TOP"  ), ::EnableDisable() }
   ::aoButtons[ BN_BACK ]:bAction := {|| ::Navigate( "BACK" ), ::EnableDisable() }
   ::aoButtons[ BN_NEXT ]:bAction := {|| ::Navigate( "NEXT" ), ::EnableDisable() }
   ::aoButtons[ BN_END  ]:bAction := {|| ::Navigate( "END"  ), ::EnableDisable() }

   ::EnableDisable()

RETURN NIL

/*-------------------------------------------------------------------------------------------------*/

METHOD TBtnNav:Navigate( cMoveTo )
   LOCAL cNewPos, nRec

   IF VALTYPE( cMoveTo ) <> "C" .OR. EMPTY( cMoveTo )
      RETURN .F.
   ENDIF

   cMoveTo := UPPER( ALLTRIM( cMoveTo ) )
   cNewPos := 'MID'

   DO CASE
   CASE cMoveTo = "NEXT"
      ( ::cAlias )->( dbskip() )
      IF ( ::cAlias )->( eof() )
         ( ::cAlias )->( dbgobottom() )
         cNewPos = "END"
      ELSE
         nRec = ( ::cAlias )->( recno() )
         ( ::cAlias )->( dbskip() )
         IF ( ::cAlias )->( eof() )
            cNewPos = "END"
         ENDIF
         ( ::cAlias )->( dbgoto( nRec ) )
      ENDIF
   CASE cMoveTo = "BACK"
      ( ::cAlias )->( dbskip( -1 ) )
      IF ( ::cAlias )->( bof() )
         ( ::cAlias )->( dbgotop() )
         cNewPos = "TOP"
      ELSE
         nRec = ( ::cAlias )->( recno() )
         ( ::cAlias )->( dbskip( -1 ) )
         IF ( ::cAlias )->( bof() )
            cNewPos = "TOP"
         ENDIF
         ( ::cAlias )->( dbgoto( nRec ) )
      ENDIF
   CASE cMoveTo = "END"
      ( ::cAlias )->( dbgobottom() )
      cNewPos = "END"
   CASE cMoveTo = "TOP"
      ( ::cAlias )->( dbgotop() )
      cNewPos = "TOP"
   OTHERWISE
      RETURN .F.
   ENDCASE

   IF ValType( ::bOnChange ) == "B"
      Eval( ::bOnChange, Self )
   ENDIF

RETURN .T.

/*-------------------------------------------------------------------------------------------------*/

METHOD TBtnNav:EnableDisable()
   LOCAL lOk := TRUE
   LOCAL nRec, nTop, nBottom

   IF Empty( ::cAlias ) .or. ( ::cAlias )->( Eof() )
      ::DisableAll()
      RETURN FALSE
   ENDIF

   nRec := ( ::cAlias )->( RecNo() )

   ( ::cAlias )->( DBGoTop() )
   nTop := ( ::cAlias )->( RecNo() )

   ( ::cAlias )->( DBGoBottom() )
   nBottom := ( ::cAlias )->( RecNo() )

   ( ::cAlias )->( DBGoTo( nRec ) )

   DO CASE
   CASE nRec = nTop
      ::aoButtons[ BN_TOP  ]:disable()
      ::aoButtons[ BN_BACK ]:disable()
      ::aoButtons[ BN_NEXT ]:enable()
      ::aoButtons[ BN_END  ]:enable()
   CASE nRec = nBottom
      ::aoButtons[ BN_TOP  ]:enable()
      ::aoButtons[ BN_BACK ]:enable()
      ::aoButtons[ BN_NEXT ]:disable()
      ::aoButtons[ BN_END  ]:disable()
   OTHERWISE
      ::EnableAll()
   ENDCASE

RETURN lOk

/*-------------------------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------------------------*/

CLASS TBtnABC FROM TBtnNav
   DATA lAppend
   DATA lEdit
   METHOD New( oDlg, cAlias, bOnChange )
   METHOD SetAction( nButton, bAction, cToolTip )
   METHOD SetBitmap( nButton, cBitmap, cPrompt, cTooltip ) VIRTUAL
   METHOD EnableDisable2()

ENDCLASS

/*-------------------------------------------------------------------------------------------------*/

METHOD TBtnABC:New( oDlg, cAlias, bOnChange )

   ::lAppend := FALSE
   ::lEdit   := FALSE

   Super:New( oDlg, cAlias, bOnChange )

   ASize( ::aoButtons, 10 )
   ASize( ::abActions, 10 )

   AFill( ::abActions, {|| NIL }, 5, 6 )

   REDEFINE BUTTONBMP ::aoButtons[05] ID 605 OF oDlg BITMAP "BM_DLOCATE"   ACTION ::abActions[05]
   REDEFINE BUTTONBMP ::aoButtons[06] ID 606 OF oDlg BITMAP "BM_DPRINT"    ACTION ::abActions[06]
   REDEFINE BUTTONBMP ::aoButtons[07] ID 607 OF oDlg BITMAP "BM_DNEW"      ACTION ::abActions[07]
   REDEFINE BUTTONBMP ::aoButtons[08] ID 608 OF oDlg BITMAP "BM_DEDIT"     ACTION ::abActions[08]
   REDEFINE BUTTONBMP ::aoButtons[09] ID 609 OF oDlg BITMAP "BM_DDELETE"   ACTION ::abActions[09]
   REDEFINE BUTTONBMP ::aoButtons[10] ID 610 OF oDlg BITMAP "BM_DCLOSE"    ACTION ::abActions[10]

   ::aoButtons[05]:cToolTip := "Localizar dato"
   ::aoButtons[06]:cToolTip := "Listar información"
   ::aoButtons[07]:cToolTip := "Nuevo registro"
   ::aoButtons[08]:cToolTip := "Editar Registro"
   ::aoButtons[09]:cToolTip := "Eliminar registro"
   ::aoButtons[10]:cToolTip := "Cerrar modulo"

   ::EnableDisable2()

RETURN Self

/*-------------------------------------------------------------------------------------------------*/

METHOD TBtnABC:SetAction( nButton, bAction, cToolTip )

   IF nButton <= Len( ::aoButtons )
      IF ValType( bAction ) == "B"
         ::aoButtons[ nButton ]:bAction := bAction
         IF !Empty( cToolTip )
            ::aoButtons[ nButton ]:cToolTip := cToolTip
         ENDIF
      ENDIF
   ENDIF

RETURN NIL

/*-------------------------------------------------------------------------------------------------*/

METHOD TBtnABC:EnableDisable2()
   LOCAL lOk

   lOk := Super:EnableDisable()

   IF lOk
      ::aoButtons[ BN_LOCATE ]:enable()
      ::aoButtons[ BN_PRINT  ]:enable()
      ::aoButtons[ BN_NEW    ]:enable()
      ::aoButtons[ BN_EDIT   ]:enable()
      ::aoButtons[ BN_DELETE ]:enable()
      ::aoButtons[ BN_CLOSE  ]:enable()
   ELSE
      ::aoButtons[ BN_LOCATE ]:disable()
      ::aoButtons[ BN_PRINT  ]:disable()
      ::aoButtons[ BN_NEW    ]:enable()
      ::aoButtons[ BN_EDIT   ]:disable()
      ::aoButtons[ BN_DELETE ]:disable()
      ::aoButtons[ BN_CLOSE  ]:enable()
   ENDIF

RETURN NIL

/*-------------------------------------------------------------------------------------------------*/

 
test.rc

Code: Select all


TEST DIALOG 0, 0, 253, 228
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "Ms Shell Dlg"
{
    PUSHBUTTON      "", 601, 7, 207, 21, 14, NOT WS_TABSTOP
    PUSHBUTTON      "", 602, 28, 207, 21, 14, NOT WS_TABSTOP
    PUSHBUTTON      "", 603, 49, 207, 21, 14, NOT WS_TABSTOP
    PUSHBUTTON      "", 604, 70, 207, 21, 14, NOT WS_TABSTOP
    PUSHBUTTON      "", 605, 96, 207, 21, 14, NOT WS_TABSTOP
    PUSHBUTTON      "", 606, 117, 207, 21, 14, NOT WS_TABSTOP
    PUSHBUTTON      "", 607, 143, 207, 21, 14, NOT WS_TABSTOP
    PUSHBUTTON      "", 608, 164, 207, 21, 14, NOT WS_TABSTOP
    PUSHBUTTON      "", 609, 185, 207, 21, 14, NOT WS_TABSTOP
    PUSHBUTTON      "", 610, 211, 207, 21, 14, NOT WS_TABSTOP
}
BM_DBACK           BITMAP         ".\\tb\\back.bmp"
BM_DCLOSE         BITMAP         ".\\tb\\close.bmp"
BM_DDELETE        BITMAP         ".\\tb\\delete.bmp"
BM_DEDIT            BITMAP         ".\\tb\\edit.bmp"
BM_DEND             BITMAP         ".\\tb\\end.bmp"
BM_DLOCATE        BITMAP         ".\\tb\\locate.bmp"
BM_DNEW            BITMAP         ".\\tb\\new.bmp"
BM_DNEXT           BITMAP         ".\\tb\\next.bmp"
BM_DPRINT          BITMAP         ".\\tb\\print.bmp"
BM_DSAVE            BITMAP         ".\\tb\\save.bmp"
BM_DTOP            BITMAP         ".\\tb\\top.bmp"
BM_DUNDO           BITMAP         ".\\tb\\undo.bmp"
 
Pero de momento existe algunas cuestiones a resolver.

1.- no es un control, lo cual me gustaria. (yo he hecho mis pinitos crendo clases tales como TTitle, xBackupLite, etc., pero no con controles que interactuen con el usuario, o que contenga otros controles)

2.- el metodo que determina e estado activado o desactivado de los botones de navegacion, tiene un codigo no optimizado para la modalidad cliente/servidor ya que usa saltos al inicio y al final para determinar la posicion del puntero en la tabla asociada, esto en cada interaccion de los botones, esto funciona bien en modo local, pero lo veo ineficiente en c/s. ( lo curioso es que hae tiempo habia hecho un codigo para esto ms optimizado y lo perdi :-) )

3- en la segunda clase TBtnABC el metodo EnableDisable2 lo queria definir como en la clase superior TBtnNav que se llamara EnableDisable, pero me fallo cuando hice uso de TBtnABC, ya que me llamaba al metodo EnableDisable de la clase TBtnABC.

Si alguien se anima a ayudarme bienvenido sea, ya que creo firmemente que necesitamos algo como esto, para ir cambiando el chip de que para todo es con browses.
Nota: no estoy en contra de los browse, es mas, fue lo que me llamo la atencion en clipper desde un inicio, pero los tiempos han cambiado, y segun leo no es recomendable en c/s.

por algo se inicia, y yo pues doy el primer paso.

agradeciendo su atencion, y su ayuda.

salu2
carlos vargas

Re: Ayuda para desarrollar un control de navegacion y edicion

Posted: Sat Apr 30, 2011 11:53 pm
by Ramon Paredes
Carlos,

El asunto de los browses depende del uso que hagas de ellos, yo tengo un sistema con 7 modulos integrados entre si y hago uso intensivo de browse sin _ el rendimiento de la aplicacion C/S, claro esta con sus LIMIT correspondientes y sus Filtros para mostrar lo estrictamente necesario, claro que ya no podemos como en dbf browse sin condiciones pero segun mi criterio aun siguen siendo un atractivo en nuestro ambiente,

Claro que lo que pretendes es perfectamente valido,

Saludos

Desde Managua, Nicaragua nuestra tierra,

Ramon Paredes