jueves, 30 de enero de 2014

Primer programa en Gambas 2, Agenda

Luego de estar bastante tiempo sin publicar nada vuelvo con un nuevo post básico de programación, en este caso vamos a hacer un pequeño calendario donde podremos guardar actividades organizadas por fecha y hora en una base de datos SQLite 3.


Vista del proyecto terminado
Bueno para empezar ejecutamos Gambas, Seleccionamos la opción de nuevo proyecto, Aplicación gráfica y luego tildamos la opción de Acceso a base de datos, continuamos con el asistente y al finalizar llegaremos a la siguiente pantalla donde vemos el formulario vació y las barras de herramientas. 

Ahora nos dirigiremos a la barra de proyecto (la que se encuentra a la izquierda de la pantalla y donde se puede ver la estructura de nuestro proyecto) y creamos dos módulos nuevos (eligiendo la correspondiente opción), uno llamado "Globales" donde definiremos las variables globales que se usarán dentro del programa y otro "BasedeDatos" donde estará el código que utilizaremos para realizar las operaciones de lectura y edición sobre la base de datos.

Módulo "Globales"


PUBLIC Conexion AS Connection 'Identificador de la conexión de base de datos
Donde definimos la variable conexión que servirá de identificador para utilizar la base de datos.

Módulo "BasedeDatos"


Luego necesitamos definir la estructura de almacenamiento de datos, para lo cual crearemos una tabla que llamaremos "Actividades" con los campos, id, fecha y actividad, para lo cual necesitaremos del siguiente código (que posteriormente lo escribiremos dentro del módulo "BasedeDatos"):

  DIM hTable AS Table
 
  hTable = hConn.Tables.Add("Actividades")
  WITH hTable
    .Fields.Add("id", db.Serial, 0)
    .Fields.Add("fecha", db.Date, 0)
    .Fields.Add("actividad", db.String, 0)

    .PrimaryKey = ["id"]
    .Update
  END WITH
Definimos el campo "id" como clave principal ya que podremos tener varias actividades situadas en la misma fecha y hora y a futuro nos simplificará el proceso de eliminación y edición de registros.

Ahora para guardar datos utilizamos el siguiente código:
'Procedimiento para agregar una nueva actividad
PUBLIC SUB AgregarActividad(Conexion AS Connection, Actividad AS String, Fecha AS Date)
 
  DIM Resultado AS Result
   
  Resultado = Conexion.Create("Actividades")
  Resultado["fecha"] = Fecha
  Resultado["actividad"] = Actividad
  Resultado.Update
  IF ERROR THEN
    Message("No se puede crear el registro", "Aceptar")
  ENDIF
 
END
Para eliminar los registros necesitamos del código:
PUBLIC SUB Borrar_seleccionado(Conexion AS Connection, id AS String)
  DIM Resultado AS Result
 
  Resultado = Conexion.edit("Actividades", "id=&1", id)
  TRY Resultado.Delete
  IF ERROR = FALSE THEN

    Message("Actividad eliminada",
"Aceptar")
  ELSE
    Message("No se pudo eliminar el registro", "Aceptar")
  ENDIF
 
END
Para poder cargar los registros en un control Tableview

PUBLIC SUB MostrarActividades(Conexion AS Connection, Tabla AS TableView, Fecha AS Date)
 
  DIM Resultado AS Result
  DIM Fecha_ing AS Date
 
  DIM Py AS Integer
  'Hacemos la consulta a la base de datos, seleccionamos todos los campos y los ordenamos por fecha de forma ascendente
  Resultado = Conexion.Exec("Select * from Actividades order by fecha ASC")
  'Definimos la tabla
  Tabla.Clear
  Tabla.Columns.Count = 4
  Tabla.Rows.Count = Resultado.Count
  Tabla.Columns[0].Text = "Hora"
  Tabla.Columns[0].Width = 100
  Tabla.Columns[1].Text = "Actividad"
  Tabla.Columns[1].Width = 250
  Tabla.Columns[2].Text = "Id"
  Tabla.Columns[2].Width = 50
 
  py = 0
  DO WHILE Resultado.Available
    'Cargamos los registros de la tabla actividades que coincidan con la fecha
    IF Date(Resultado["fecha"]) = Fecha THEN
      Tabla[py, 0].Text = Time(Hour(Resultado["fecha"]), Minute(Resultado["fecha"]), 0)
      Tabla[py, 1].Text = Resultado["actividad"]
      Tabla[py, 2].Text = Resultado["id"]
      'Coloreamos los registros
      IF py MOD 2 = 0 THEN
        Tabla[py, 0].BackColor = &FAFEFF&
        Tabla[py, 1].BackColor = &FAFEFF&
        Tabla[py, 2].BackColor = &FAFEFF&
      ELSE
        Tabla[py, 0].BackColor = &DEFFE4&
        Tabla[py, 1].BackColor = &DEFFE4&
        Tabla[py, 2].BackColor = &DEFFE4&
      ENDIF
      py = py + 1
    ENDIF
    Resultado.MoveNext()
  LOOP
 
END 
Para hacer la carga de base de datos:
'Procedimiento para abrir la base de datos o crearla en caso de que no exista
PUBLIC SUB InicializaBase()
  Globales.Conexion = NEW Connection
  Globales.Conexion.Type = "sqlite3"
  Globales.Conexion.Host = User.home
  Globales.Conexion.Name = ""
  TRY Globales.Conexion.Open()
  IF NOT Globales.Conexion.Databases.Exist("Calendario") THEN
    Message("La base de datos no existe, se creará una nueva", "Aceptar")
    Globales.Conexion.Databases.Add("Calendario")
    WAIT 0.5
  ENDIF
  Globales.Conexion.Close()
  Globales.Conexion.Host = User.home
  Globales.Conexion.Name = "Calendario"
  TRY Globales.Conexion.Open()
  IF ERROR THEN
    Message.Error("No se puede establecer conexión con la base de datos")
  ELSE
    IF NOT Globales.Conexion.Tables.Exist("Actividades") THEN
      CrearBase(Globales.Conexion)
    ENDIF  
  ENDIF
END

Por lo que el código entero del archivo nos quedará:
'Creamos la tabla de la base de datos
PUBLIC SUB CrearBase(hConn AS Connection)
   
  DIM hTable AS Table
 
  hTable = hConn.Tables.Add("Actividades")
  WITH hTable
    .Fields.Add("id", db.Serial, 0)
    .Fields.Add("fecha", db.Date, 0)
    .Fields.Add("actividad", db.String, 0)

    .PrimaryKey = ["id"]
    .Update
  END WITH
END

'Procedimiento para abrir la base de datos o crearla en caso de que no exista
PUBLIC SUB InicializaBase()
  Globales.Conexion = NEW Connection
  Globales.Conexion.Type = "sqlite3"
  Globales.Conexion.Host = User.home
  Globales.Conexion.Name = ""
  TRY Globales.Conexion.Open()
  IF NOT Globales.Conexion.Databases.Exist("Calendario") THEN
    Message("La base de datos no existe, se creará una nueva", "Aceptar")
    Globales.Conexion.Databases.Add("Calendario")
    WAIT 0.5
  ENDIF
  Globales.Conexion.Close()
  Globales.Conexion.Host = User.home
  Globales.Conexion.Name = "Calendario"
  TRY Globales.Conexion.Open()
  IF ERROR THEN
    Message.Error("No se puede establecer conexión con la base de datos")
  ELSE
    IF NOT Globales.Conexion.Tables.Exist("Actividades") THEN
      CrearBase(Globales.Conexion)
    ENDIF  
  ENDIF
END

'Procedimiento para agregar una nueva actividad
PUBLIC SUB AgregarActividad(Conexion AS Connection, Actividad AS String, Fecha AS Date)
 
  DIM Resultado AS Result
   
  Resultado = Conexion.Create("Actividades")
  Resultado["fecha"] = Fecha
  Resultado["actividad"] = Actividad
  Resultado.Update
  IF ERROR THEN
    Message("No se puede crear el registro", "Aceptar")
  ENDIF
 
END

PUBLIC SUB Borrar_seleccionado(Conexion AS Connection, id AS String)
  DIM Resultado AS Result
 
  Resultado = Conexion.edit("Actividades", "id=&1", id)
  TRY Resultado.Delete
  IF ERROR = FALSE THEN

    Message("Actividad eliminada",
"Aceptar")
  ELSE
    Message("No se pudo eliminar el registro", "Aceptar")
  ENDIF
 
END


'Procedimiento para mostrar la lista de actividades
PUBLIC SUB MostrarActividades(Conexion AS Connection, Tabla AS TableView, Fecha AS Date)
 
  DIM Resultado AS Result
  DIM Fecha_ing AS Date
 
  DIM Py AS Integer
  'Hacemos la consulta a la base de datos, seleccionamos todos los campos y los ordenamos por fecha de forma ascendente
  Resultado = Conexion.Exec("Select * from Actividades order by fecha ASC")
  'Definimos la tabla
  Tabla.Clear
  Tabla.Columns.Count = 4
  Tabla.Rows.Count = Resultado.Count
  Tabla.Columns[0].Text = "Hora"
  Tabla.Columns[0].Width = 100
  Tabla.Columns[1].Text = "Actividad"
  Tabla.Columns[1].Width = 250
  Tabla.Columns[2].Text = "Id"
  Tabla.Columns[2].Width = 50
 
  py = 0
  DO WHILE Resultado.Available
    'Cargamos los registros de la tabla actividades que coincidan con la fecha
    IF Date(Resultado["fecha"]) = Fecha THEN
      Tabla[py, 0].Text = Time(Hour(Resultado["fecha"]), Minute(Resultado["fecha"]), 0)
      Tabla[py, 1].Text = Resultado["actividad"]
      Tabla[py, 2].Text = Resultado["id"]
      'Coloreamos los registros
      IF py MOD 2 = 0 THEN
        Tabla[py, 0].BackColor = &FAFEFF&
        Tabla[py, 1].BackColor = &FAFEFF&
        Tabla[py, 2].BackColor = &FAFEFF&
      ELSE
        Tabla[py, 0].BackColor = &DEFFE4&
        Tabla[py, 1].BackColor = &DEFFE4&
        Tabla[py, 2].BackColor = &DEFFE4&
      ENDIF
      py = py + 1
    ENDIF
    Resultado.MoveNext()
  LOOP
 
END 

Formulario principal

 Luego en el formulario principal agregamos el componente Datechooser, que nos servirá para elegir la fecha para ver las actividades que concuerdan con aquella que se haya seleccionado y al mismo tiempo disponer de un valor de fecha para crear un nuevo registro.

Una vez situado hacemos doble click sobre el lo que nos llevará a la ventana de edición de código del formulario situándonos en el evento de cambio de fecha. En dicho lugar escribimos el siguiente código:

DIM Dia, Mes, Anio AS Integer
 
  Dia = DateChooser1.Day
  Mes = DateChooser1.Month
  Anio = DateChooser1.Year
  'Mostramos las actividades del dia seleccionado
  BasedeDatos.MostrarActividades(Globales.Conexion, TableView1, Date(Anio, Mes, Dia, 0, 0, 0))
Donde definimos variables locales donde almacenamos los valores de los componentes de la fecha seleccionada para poder pasárselos como parámetro al procedimiento que muestra las actividades que concuerdan con día (procedimiento escrito anteriormente en el módulo "BasedeDatos").

Luego creamos un control Tableview1 donde más tarde mostraremos las actividades guardadas

Creamos controles
  • TextArea1: Para introducir la descripción de la actividad
  • Spinbox1: Para introducir el valor de la hora
  • Spinbox2: Para introducir el valor de los minutos
Un botón agregar donde  hacemos doble click para acceder al evento button_click y escribir el siguiente código:
DIM Dia, Mes, Anio AS Integer
 
  'Validamos que se completen los campos nesesarios
  IF TextArea1.Text <> "" THEN
    Dia = DateChooser1.Day
    Mes = DateChooser1.Month
    Anio = DateChooser1.Year
    'Guardamos la actividad ingresada en la tabla "Actividades" llamando al procedimiento AgregarActividad del modulo BasdeDatos
    BasedeDatos.AgregarActividad(Globales.Conexion, TextArea1.Text, Date(Anio, Mes, Dia, SpinBox1.Value, SpinBox2.Value, 0))
    'Borramos el campo de actividad
    TextArea1.Text = ""
    'Actualizamos la lista de actividades
    BasedeDatos.MostrarActividades(Globales.Conexion, TableView1, Date(Anio, Mes, Dia, 0, 0, 0))
  ELSE
    Message("Se debe completar el campo actividad", "Aceptar")
  ENDIF
Y un botón para eliminar las actividades que se muestren en el control TableView1 (es importante definir la propiedad Mode = Single del TableView para poder elegir los registros), dentro del evento Button_click de dicho control escribimos el siguiente código:
DIM Dia, Mes, Anio AS Integer
 
  Dia = DateChooser1.Day
  Mes = DateChooser1.Month
  Anio = DateChooser1.Year
  'Borramos el registro
  BasedeDatos.Borrar_seleccionado(Globales.Conexion, TableView1[TableView1.Row, 2].Text)
  'Actualizamos la lista de actividades
  BasedeDatos.MostrarActividades(Globales.Conexion, TableView1, Date(Anio, Mes, Dia, 0, 0, 0))
En este ejemplo no cambiamos los nombres predeterminados de los controles, pero se puede hacer editando la propiedad "name" de los mismos, lo que en programas más grandes será de utilidad evitado posibles confusiones al momento de programar

El código del formulario principal nos debe quedar así
PUBLIC SUB Form_Open()

  BasedeDatos.InicializaBase

END

PUBLIC SUB DateChooser1_Change()
  DIM Dia, Mes, Anio AS Integer
 
  Dia = DateChooser1.Day
  Mes = DateChooser1.Month
  Anio = DateChooser1.Year
  'Mostramos las actividades del dia seleccionado
  BasedeDatos.MostrarActividades(Globales.Conexion, TableView1, Date(Anio, Mes, Dia, 0, 0, 0))

END

PUBLIC SUB Button1_Click()
  DIM Dia, Mes, Anio AS Integer
 
  'Validamos que se completen los campos nesesarios
  IF TextArea1.Text <> "" THEN
    Dia = DateChooser1.Day
    Mes = DateChooser1.Month
    Anio = DateChooser1.Year
    'Guardamos la actividad ingresada en la tabla "Actividades" llamando al procedimiento AgregarActividad del modulo BasdeDatos
    BasedeDatos.AgregarActividad(Globales.Conexion, TextArea1.Text, Date(Anio, Mes, Dia, SpinBox1.Value, SpinBox2.Value, 0))
    'Borramos el campo de actividad
    TextArea1.Text = ""
    'Actualizamos la lista de actividades
    BasedeDatos.MostrarActividades(Globales.Conexion, TableView1, Date(Anio, Mes, Dia, 0, 0, 0))
  ELSE
    Message("Se debe completar el campo actividad", "Aceptar")
  ENDIF

END

PUBLIC SUB Button2_Click()
  DIM Dia, Mes, Anio AS Integer
 
  Dia = DateChooser1.Day
  Mes = DateChooser1.Month
  Anio = DateChooser1.Year
  'Borramos el registro
  BasedeDatos.Borrar_seleccionado(Globales.Conexion, TableView1[TableView1.Row, 2].Text)
  'Actualizamos la lista de actividades
  BasedeDatos.MostrarActividades(Globales.Conexion, TableView1, Date(Anio, Mes, Dia, 0, 0, 0))

END
Y aquí ya tenemos la primera versión del programa finalizada, luego continuaremos agregándole prestaciones y afinando el código.

También podremos generar un paquete instalable para las distribuciones de linux más conocidas.

Enlace de descarga del proyecto

No hay comentarios:

Publicar un comentario