Mas Sobre GridView Heredado Y Su Evento Data


Objetivo: Mas Sobre GridView Heredado Y Su Evento Data
Esto es lo que intento hacer:

Un gridview que contenga en sí mismo todo lo necesario para la visualización de la base de datos, a saber: una conexión, una sentencia sql, un orden, y un Result, de forma que no necesite ser alimentado en cada formulario y que pueda ser manejada como objeto.

Para ello tengo esta nueva clase que llamo, por ejemplo, "migrid"



'' gambas class file
INHERITS GridView

PUBLIC consulta AS String
PUBLIC orden AS String
PUBLIC clave AS Integer
PUBLIC rsDatos AS Result
PUBLIC hconn AS conexion
PUBLIC hcon AS connection

'En creación recibimos todo lo necesario
PUBLIC PROCEDURE _new(elsql AS String, elorden AS String, lacolclave AS Integer, laconec AS Connection, elcontenedor AS Object)
ME.consulta = elsql
ME.orden = elorden
ME.clave = lacolclave
ME.hcon = laconec
ME.width = elcontenedor.width - 50
ME.Height = elcontenedor.height - 60
ME.Header = 3
ME.Resizable = TRUE
ME.ScrollBar = 3
ME.visible = TRUE
refrescar() 'efectuamos la consulta y rellenamos el griview
END

PUBLIC FUNCTION refrescar() AS Boolean

DIM lret AS Boolean
DIM oldtag AS NEW Variant[]
ME.consulta = If(InStr(LCase(ME.consulta), "select"), ME.consulta, "select * from " & ME.consulta)
ME.consulta = If(ME.orden, ME.consulta & " order by " & ME.orden, ME.consulta)
TRY ME.rsDatos = ME.hcon.Exec(ME.consulta) 'la forma de conectar es provisional, pero funciona de momento
IF ERROR THEN
TRY ME.hcon.Open
IF ERROR THEN
TRY ME.hcon.Close
TRY ME.hcon.Open
IF ERROR THEN
Message("Imposible conectar con la base de datos")
RETURN FALSE
ENDIF
ENDIF
TRY ME.rsDatos = ME.hcon.Edit(ME.consulta)
IF ERROR THEN
Message("Imposible efectuar la consulta")
RETURN FALSE
ENDIF
ENDIF
lret = ME.formatear() 'Creamos las columnas, los títulos, los anchos, etc.
RETURN lret
END

PUBLIC FUNCTION formatear() AS Boolean
DIM hTable AS Table
DIM hField AS ResultField
DIM sField AS String
DIM iInd AS Integer
DIM iLen, ileng, n, i AS Integer
DIM lret AS Boolean

INC Application.Busy
lret = TRUE
IF NOT ME.rsDatos THEN
DEC Application.Busy
RETURN lret
ENDIF
ME.Rows.Count = 0
ME.Columns.Count = ME.rsDatos.Fields.Count
FOR EACH hField IN ME.rsDatos.Fields
WITH hField
SUPER.Columns[iInd].Text = .Name
IF .Type <> 9 THEN
iLeng = .Length
ELSE
iLeng = Len(ME.rsDatos[.Name])
IF ileng > 0 THEN
n = (.Length / 3) - ileng
n = n / 2
ileng = Int(ileng + n)
ELSE
ileng = .Length
ENDIF
ENDIF
TRY SUPER.Columns[iInd].Width = ME.anchoportipo(.Type, iLeng, .Name)
IF ERROR THEN
Message(Error.Text)
ENDIF
END WITH

INC iInd
NEXT
' ODBC devuelve mal el total de registros
IF ME.rsDatos.Count = -1 THEN
SUPER.Rows.Count = SUPER.rowcount
ELSE
SUPER.Rows.Count = ME.rsDatos.Count
ENDIF

FINALLY

DEC Application.Busy
RETURN lret

CATCH

Message.Error("Imposible ejectuar la solicitud. Error: " & "\n\n" & DConv(Error.Text))
lret = FALSE

END
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Este es el evento que nunca se ejecuta y no sé dónde colocar
PUBLIC SUB Data(Row AS Integer, Column AS Integer)

ME.rellenar(Row, Column)

END
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

PUBLIC SUB rellenar(Row AS Integer, Column AS Integer)
'tipico evento data de sincronización entre la tabla y el gridview
ME.rsDatos.MoveTo(Row)
ME[row, column].Text = Str(ME.rsDatos[ME.Columns[Column].Text])
IF (Row MOD 2) == 0 THEN
ME.Data.Background = Color.White
ELSE
ME.Data.Background = color.RGB(162, 209, 236)
ENDIF
ME.Data.Foreground = Color.black

END

PUBLIC FUNCTION anchoportipo(iType AS Integer, iLength AS Integer, sTitle AS String) AS Integer

'función pillada por ahí, pendiente de mejoras...

DIM iWidth AS Integer

SELECT CASE iType

CASE gb.Boolean
iWidth = SUPER.Font.Width(Str(FALSE)) + 32

CASE gb.Integer
' iWidth = hCtrl.Font.Width("1234567890") + 16
iWidth = SUPER.Font.Width("123456") + 16
CASE gb.Long
iWidth = SUPER.Font.Width("12345678901234567890") + 16
CASE gb.Float
' iWidth = hCtrl.Font.Width(CStr(Pi) & "E+999") + 16
iWidth = SUPER.Font.Width("12345678") + 16
CASE gb.Date
iWidth = SUPER.Font.Width(Str(Now)) + 16
CASE gb.String
IF iLength = 0 THEN iLength = 255
iLength = Min(32, iLength)
iWidth = SUPER.Font.Width("X") * iLength + 16

END SELECT

iWidth = Max(iWidth, SUPER.Font.Width(sTitle) + 8)

RETURN iWidth

END

PUBLIC FUNCTION rowcount() AS Integer

DIM rows AS Integer

rows = 0
DO
ME.rsDatos.MoveTo(rows)
INC rows
LOOP

CATCH

RETURN rows

END

PUBLIC SUB ordenar(Column AS Integer)
' para el evento column_click del gridview
DIM old_orden AS String
DIM n AS Integer
DIM new_orden AS String
INC Application.Busy
old_orden = ME.orden
new_orden = ME.columns[Column].Title
n = InStr(new_orden, ".")
IF n = 1 THEN
new_orden = "`" & Left(new_orden, n - 1) & "`.`" & Right(new_orden, - n) & "`"
ELSE
new_orden = "`" & new_orden & "`"
ENDIF
IF old_orden = new_orden
new_orden &= " DESC"
ENDIF
ME.orden = new_orden
ME.refrescar()
DEC Application.Busy

END



Luego creamos un formulario y le asignamos el siguiente código:


PUBLIC elgrid AS migrid
PUBLIC conec AS connection

PUBLIC SUB form_Open()

'también se podría hacer primero elgrid y luego alimentar las propiedades de la conexion... pero de momento así está
conec = NEW connection
conec.Host = "localhost"
conec.Type = "mysql"
conec.Name = "mitabla"
conec.User = "miusuario"
conec.Password = "mipassword"

'parametros: consulta,orden,columna clave,contenedor,creador
elgrid = NEW migrid("select *from mitabla", "nombre", 1, conec, ME, ME) 'Se repite dos veces el ME, una como contenedor y otra como creador de la clase
'poco elegante que hay que depurar... cuando funcione, claro.

END

PUBLIC SUB elgrid_Data(Row AS Integer, Column AS Integer) 'no funciona. He probado a llamarla Data a secas pero tampoco...

elgrid.rellenar(Row, Column)

END

PUBLIC SUB elgrid_ColumnClick(Column AS Integer)

elgrid.ordenar(Column)

END


Con esto teóricamente debería crearse el gridview, que se crea, con las columnas, que se crean, y sus datos que NO se crean por falta de evento Data...

¿Alguna idea? Me lleva loco el tema....

Suerte

Perfil MP  
Objetivo: Re: Mas Sobre GridView Heredado Y Su Evento Data
Shordi, creo que ya te lo habían dicho, pero no sé si lo probaste: para capturar el evento deberías crear un objeto observer en el constructor (_new)

Creo que algo así debería funcionar:

PRIVATE $hObserver AS Observer

...

PUBLIC PROCEDURE _New()
$hObserver = NEW Observer(ME) AS "myGridView"
....
END

PUBLIC PROCEDURE myGridView_Data(Row AS Integer, Column AS Integer)
ME.rellenar(Row, Column)
END


De todos modos creo que deberías ordenar un poco el código y seguir fielmente algunas pautas de POO:

  • Tu código no respeta el principio de encapsulamiento. Deberías cambiar las variables públicas por propiedades.
  • Veo que usas algunas abreviaturas para nombrar las variables. Si quieres que alguien más que tú mismo entienda tu código sin problemas, no deberías usar abreviaturas.
  • Aunque no lo analicé detenidamente me parece que posiblemente tu clase "migrid" no respete el principio de responsabilidad única (viene a ser lo mismo que con las funciones: deben hacer una única cosa). Deberías tener en cuenta que tu proyecto es un control que puede componerse de varias clases, no necesarimente de una sola. Encontrar cuáles deberían ser esas clases debe ser el primer paso.
  • Hay métodos que me parece no deberían ser públicos: esos también estarían rompiendo el encapsulamiento.

Un consejo Shordi, refactoriza antes de seguir, es decir, intenta hacer lo siguiente.

  • Crea un nuevo proyecto.
  • Escribe primero la interfaz de la clase (propiedades y nombres y argumentos de los métodos que los usuarios de tu control deberían ver) sin su implementación. Así podrás definir cómo quieres que tu control sea usado, sin preocuparte de cómo lo implementarás.
  • Crea un módulo para probar la clase (si ya sé que aún no hace nada, por eso es el momento justo para empezar a probarla). En ese módulo deberás empezar a escribir procedimientos que creen un objeto, establezcan sus propiedades y prueben sus métodos, siempre comparando si los resultados son iguales que los valores esperados.
  • Define las variables y métodos que usará internamente la clase (que deben ser privados), sin su implementación.
  • Analiza un poco el diseño de la/s clase/s, para ver si la interfaz que definiste es adecuada o si le faltan métodos públicos o propiedades.
  • Implementa primero las propiedades y métodos públicos en términos de variables y métodos privados. Es decir, si observas que un método público necesita, por ejemplo, calcular la longitud de una vaca adulta, pon una llamada a un método "PRIVATE FUNCTION getLongAdultCow() AS Float" que implementarás después (la primera implementación de "getLongAdultCow" debería ser algo como Return 2,07 para permitir que puedas ejecutar las pruebas de entrada nomás).
  • Del punto anterior puede surgir evidencia de que necesitas variables o métodos privados adicionales: defíne su interfaz pero no su implementación.
  • Cada vez que implementas un método o propiedad, escribe en un módulo algunas pruebas que podrían hacer fallar ese método o propiedad. Ejecuta el módulo de pruebas y corrige las fallas que vayan surgiendo.
  • Completa la implementación de cada método, ejecutando las pruebas luego de cada modificación importante para asegurarte que no introduces nuevos fallos.


Un proceso así es lo que generalmente se recomienda para lograr un buen diseño y una buena modularización. Es el proceso lo que ayuda a disminuir la cantidad de errores que uno comete; se mejora la comprensión sobre qué se debe hacer en cada momento al definir primero las interfaces y al escribir pruebas y ejecutarlas cada vez que se introducen modificaciones importantes.

Si quieres seguir mi consejo y necesitas ayuda para hacerlo no dudes en avisarme, en el proceso yo aprenderé mucho

Objetivo: Re: Mas Sobre GridView Heredado Y Su Evento Data
¿Ves como sí eres el interlocutor adecuado? jeje.
Mil gracias.
Efectivamente, ese código no es más que un primer intento de convertir un puñado de funciones que tenía agrupadas en un módulo, y que portaba de aplicación en aplicación prácticamente intactas, en un objeto. Tiempo empleado en el análisis: 13 segundos (más o menos).
No podía emplearme más sin saber si era posible hacerlo (nunca he heredado un control gráfico) y ahí me estrellé.

Por otra parte no sabía que se podía declarar un observador vía código, que eso lo dijo Jesús y no me enteré de la copla, me temo.
Una respuesta orientadora como la tuya es lo que esperaba y te estoy super agradecido. Dame unos días para que le dé vueltas al tema y subiré lo que vaya consiguiendo, código o problemas. Posiblemente más de lo segundo que de lo primero... jejeje

Gracias otra vez. Este es el mejo foro del mundo mundial.

Suerte


Edito: otografía, ortografía...

última edición por shordi el Miercoles, 11 Agosto 2010, 18:32; editado 2 veces
Perfil MP  
Objetivo: Re: Mas Sobre GridView Heredado Y Su Evento Data
Hola Shordi, creo que en el hilo en que empezaste esta consulta, ya te dije lo que me paso a mi. La clase creada por mi no era gráfica pero lo de los observer debe de ser igual.
Por defecto un objeto es su propio observador. Yo uso los observer cuando quiero interceptar el funcionamiento de algunos controles (no todos) y responder a ciertos eventos de la misma forma para ese grupo.
Como todos queremos ahorrarnos código escrito, te vuelvo a decir que lo que haría sería, al instanciar tu grid personalizado declararlo con su propio observador.

DIM arrtable AS String[5]
DIM elGrid AS miGrid

elGrid = NEW miGrid AS "observaMiGrid"

'Debería funcionar ahora en este Form desde el que instancias, el evento Data

PUBLIC SUB observaMiGrid_Data(Row AS Integer, Column AS Integer)

'un array con los nombre de los campos aquí pon los tuyos y sácalo de aquí y ponlo en Form_Open()
arrtable[0]="cod"
arrtable[1]="fecha"
arrtable[2]="concepto"
arrtable[3]="cantidad"
arrtable[4]="origen"

ResultDeDatos.MoveTo(Row)
TVultGastos.data.Text = Str(ResultDeDatos[arrtable[Column]])

END

Perdón por volver con lo mismo pero creo que lo fácil es mejor, no se

Antonio

Perfil MP  
Objetivo: Re: Mas Sobre GridView Heredado Y Su Evento Data
Disculpa ahtonio, atribuí más arriba tu respuestas en el otro hilo a Jesús.
En el otro como que no lo entendí. Ahora, juntando todas vuestras ayudas, como que lo entiendo.
Me pongo a probarlo (sin prisas, que es agosto...) y cuando tenga algo que contar ipsofactamente os lo comunico.
Gracias a todos.

Suerte

Perfil MP  
Objetivo: Re: Mas Sobre GridView Heredado Y Su Evento Data
Hola Shordi, como te comente en privado, intento adjuntarte el fuente por si quieres probarlo y/o verlo.


gesper-0.0.4.tar.gz
Descripción:  
Descargar
Nombre del archivo: gesper-0.0.4.tar.gz
Tamaño: 44.53 KB
Descargado: 94 veces
gesper-0.0.4.tar.gz
Descripción:  
Descargar
Nombre del archivo: gesper-0.0.4.tar.gz
Tamaño: 44.53 KB
Descargado: 94 veces
gesper-0.0.4.tar.gz
Descripción:  
Descargar
Nombre del archivo: gesper-0.0.4.tar.gz
Tamaño: 44.53 KB
Descargado: 94 veces

Perfil MP  
Objetivo: Re: Mas Sobre GridView Heredado Y Su Evento Data
Recibido. Ya te cuento... y mil gracias.

Perfil MP  

Página 1 de 1


  
No puede crear mensajes
No puede responder temas
No puede editar sus mensajes
No puede borrar sus mensajes
No puede votar en encuestas
No puede adjuntar archivos
Puede descargar archivos
No puede publicar eventos en el calendario

   

Está utilizando la versión (Lo-Fi). Para ver la versión completa del foro, haga clic aquí.

Powered by Icy Phoenix based on phpBB
Design by DiDiDaDo

Página generada en:: 8.3009s (PHP: -90% SQL: 190%)
Consultas SQL: 48 - Debug off - GZIP Activado