En este post veremos como mostrar el contenido de una tabla en un tableView y como insertar nuevos valores en la base de datos.
Dividiremos el post en dos partes, mostrar datos, insertar datos (dar cera, pulir cera).
Mostrar datos:
Bueno, en el último capítulo vimos como conectar con la base de datos y ahora que ya somos amigos intimos de ella, vamos a "verla por dentro" ...
Para ello, debemos crear una función en el modulo (modulo de base de datos) que rellene el tableview que hemos insertado, porque lo hemos insertado ¿verdad? ...
(si, eso de añadir la libreria o biblioteca de qt.ext en proyecto - propiedades y seleccionar el tableview de las nuevas herramientas que aparecerán).
Muy bien, tenemos un gran cuadro blanco que no hace nada, vamos a rellenarlo.
Para ello , debemos usar una funcion en el modulo Mdb que ... ups, esto ya lo he dicho antes, ayyy ese Alemán que me vuelve loco ... bueno la función es la siguiente y lo que hace es determinar cuantas filas y columnas le pondremos a esa tableview, ya que estas dependen de la consulta :
'
' Rellenar una tabla con los resultados '
'
PUBLIC SUB fill_view(tbv AS tableview, qry AS String)
rs1 = db.exec(qry)
WITH rs1
tbv.rows.count=0 ' Muy importante
IF .count<>0 THEN
tbv.columns.count=.fields.count
tbv.rows.count=.count
END IF
END WITH
END
Expliquemos un poquillo el código:
Comentarios al principio, ejecutamos la consulta (que, como vemos es pasada con el parametro qry) con db.exec y guardamos el resultado en la variable global ya definida rs1.
El WITH significa que a partir de esa linea y hasta que encontremos un END WITH si ponemos un punto (.) es como si hubiesemos puesto rs1, esto hace que tengamos que escribir menos.
Con (WITH) rs1 (la consulta) ...
Ponemos el numero de filas a cero. (Muy importante cuando eliminamos, que si no, habria una fila de menos y daria error (buffer overflow, jijiji)).
Si el numero de filas de la consulta (rs1) es distinto de cero (o sea, que hay datos que mostrar) ENTONCES hacer:
a) - Poner el numero de columnas a la tableview (que se la hemos pasado como parámetro a la función con el nombre de tbv) igual al de campos que tenga el resultado de la consulta.
b) - Poner el número de filas de la table view igual que el número de filas devueltas por la consulta.
Cerramos todo lo abierto y ala, ya esta dimensionada la tabla.
Ahora hemos de rellenar la tabla ...
Y aquí es donde estuve dejándome los ojos un buén rato hasta que me dió por leer la ayuda,
Pués lo que me decia la cabeza es que una primera lectura habia que hacerla nada más cargar el formulario ... asi que en el evento open del formulario inicial le añadí lo siguiente:
query = "SELECT cod, DATE_FORMAT(fecha, '%d/%m/%Y') as fecha, concepto, CONCAT(cantidad, ' €') as cantidad, origen FROM HomeGestion.gastos ORDER BY fecha ASC"
Mdb.fill_view(TVultGastos, query)
WITH TVultGastos
.columns.Resizable = TRUE
.columns.Moveable = TRUE
.columns.count=5
.columns[0].text="Cod"
.columns[0].Width = 50
.columns[1].text="Fecha"
.columns[1].Width = 100
.columns[2].text="Concepto"
.columns[2].Width = 248
.columns[3].text="Cantidad"
.columns[3].Width = 100
.columns[4].text="Origen"
.columns[4].Width = 100
END WITH
Que es una consulta cuya única cosa a destacar son las funciones DATE_FORMAT (que podreis adivinar para que sirve) y CONCAT (que tambien es muy sencillo, concatena).
Y después llamo a la funcion que creamos antes.
Luego "acondiciono" el tableview, poniendole titulos, dimensiones y demas ...
Y al darle a ejecutar lo único que sale es la tableview, con sus títulos con el número de columnas y filas correcto, pero ningún dato en su interior.
Y es que resulta que cargar los datos a la tableview se hace con una función propia del objeto.
O sea, que hay que usar el "evento" de la tableview Data(boton secundario sobre la tabla y evento, seleccionamos Data). y escribimos lo siguiente en ese evento:
PUBLIC SUB TVultGastos_Data(Row AS Integer, Column AS Integer)
'el nombre de los campos del array
arrtable[0]="cod"
arrtable[1]="fecha"
arrtable[2]="concepto"
arrtable[3]="cantidad"
arrtable[4]="origen"
WITH Mdb
.rs1.MoveTo(Row)
TVultGastos.data.Text = Str(.rs1[arrtable[Column]])
END WITH
END
Que hace lo siguiente ...
En arrtable (que es un array que hemos definido al principio del código, y si aún no lo hemos hecho, lo hacemos ahora con:
' Gambas class file
' Variables del modulo
arrtable[5] AS
Siempre al principio del código.)
En arrtable metemos el nombre de los campos que devuelve nuestra consulta, que son cod, fecha, concepto, cantidad, origen.
Es conveniente segur el mismo orden que en la query que hicimos, si no nos liaremos más, también decir que habra una forma 10.000 veces mas facil de rellenar un tableview con gambas sin armar tanto follón, pero en estas pocas horas que le he hechado al gambas no la he encontrado.
Bueno, despues y CON (WITH) Mdb vamos a la fila de la consulta que lleve el tableview (don't worry, la cuenta la lleva Gambas), ya que Row le llega como parámetro y es la fila actual de la tabla.
Y despues:
TVultGastos.data.Text = Str(.rs1[arrtable[Column]])
que es más dificil explicarlo que entenderlo ... pero bueno, se intentará:
Bueno, pues el data.text (que no esta documentado en la ayuda ...) es el texto que irá en la celda actual (recordemos que gambas lleva la cuenta de la columna, fila y, por tanto, la celda donde estamos). ¿Y que debemos meter en esa celda? pues, pasandolo antes a cadena con la función Str, (aqui viene lo liante, preparaos !!) se coje de Mdb.rs1 (la consulta actual con la fila correspondiente ya seleccionada antes) y se lee el campo correspondiente a la Columna (Column) actual del tableView (cuenta que lleva gambas), con lo cual se escribe el contenido correcto ... y la parte contratante de la segunda parte corresponde a la parte contratante de la primera parta y ....
En resumen, cuando se guarde todo y se le dé a ejecutar debe rellenarse el tableview con los datos de la base de datos y si, funcionó. (UUuuufffff, trabajito costo).
Insertar datos:
Bueno, ahora que la base de datos está mostrandonos todo lo que tiene y hemos jugado con ella, será más facil la "penetración" en ella de los datos (me parezco a la Verdú, dos rombos, jeje).
Para ello nos vamos al evento de click del boton insertar(doble click sobre el boton)
y rellenamos el evento con el siguiente código:
PUBLIC SUB Button1_Click()
DIM query AS String
DIM fechaArray AS String[]
DIM fechaSQL AS String
fechaArray = Split(fecha.Text, "/")
fechaSQL = fechaArray[2] & "-" & fechaArray[1] & "-" & fechaArray[0]
IF ((NOT cantidad.Text) OR Val(cantidad.Text) = 0) THEN
Message.Warning("Debe especificar una cantidad")
ELSE IF (NOT concepto.Text) THEN
Message.Warning("Debe especificar un concepto")
ELSE
query = "INSERT INTO HomeGestion.gastos "
query = query & "SET fecha='" & fechaSQL & "', "
query = query & "cantidad='" & Val(cantidad.Text) & "', "
query = query & "concepto='" & concepto.Text & "', "
query = query & "origen='" & CBorigen.Current.Text & "'"
'Message.Info(query) ' Test de query
Mdb.consulta(query)
query = "SELECT cod, DATE_FORMAT(fecha, '%d/%m/%Y') as fecha, concepto, CONCAT(cantidad, ' €') as cantidad, origen FROM HomeGestion.gastos ORDER BY fecha ASC"
Mdb.fill_view(TVultGastos, query)
END IF
END
Este codigo podemos dividirlo en dos partes, Insercion y muestreo.
Primero definimos algunas variables que nos harán falta
y "rompemos" la cadena de la fecha por el simbolo "/" (barra del siete, jeje) y creamos la fecha tal y como le gusta a mysql. (que si, que hay mejores manera, pero bueno, cada cuál hace lo que puede, o lo que tiene ganas de poder)
Una vez creado el formato de la fecha y pasado las comprobaciones (ya comentado en anteriores post) pasamos a la insercción de los datos.
A mi personalmente me gusta crear la query o consulta a "cachos" asi que es facil deducir lo que hace cada trozo, aunque merece especial atención la función Val() que parsea (pasa a un tipo) el valor que recibe (Más info en la ayuda).
Es muy conveniente ver que se ha creado antes de darselo a mysql, de ahí ese test de query, aunque ahora este comentado.
Para insertar la consulta podriamos haber usado Mdb.db.exec(), pero me pareció más "bonito" hacer una funcion en Mdb (asi practicaba un poquillo las funciones en Gambas).
'
' Realiza una consulta en la db '
'
PUBLIC SUB consulta(qry AS String)
rs1 = db.exec(qry)
END
Lo mas simple, no creo que merezca la pena ni comentarlo.
Aquí me di cuenta de un "pequeño" error, y es que las fechas no las formateaba bién (ese jodio formato inglés), entonces, me tocó usar la función Format$(), en todas las funciones que escribian en la caja de texto de la fecha.
Format$(DPselFecha.Value, "dd/mm/yyyy")
Esto en las funciones del datapicker (ya que aún sigo sin saber como se pone en español)
y esto:
fecha.Text = Format$(Date(), "dd/mm/yyyy")
En la función open del formulario principal (la fecha por defecto).
Una vez hecho esto ya estamos insertando datos en nuestra queridisima base de datos.
Pero no debemos olvidar que hay que decirle a la tableview que atualice los datos (nueva fila), asi que repetimos la consulta inicial y le cambiamos el numero de filas y columnas (el refresco de los datos lo hace el solito).
Y con esto y un bizcocho, ya insertamos y vemos lo que hay en la base de datos ... pero somos humanos y nos equivocaremos al meter gastos, y querremos corregirlo (modificar datos) o eliminarlo (eliminar datos), pero eso ya lo veremos en el siguiente post.