https://foro.gambas-es.org/viewtopic.php?f=4&t=7994
-----------------------------------
Harpo
Domingo, 26 Abril 2020, 13:30

Problema Con Control De Errores Y Return En Una Función
-----------------------------------
Saludos al foro, aprovechando la cuarentena he retomado Gambas y me he encontrado con un problema al que no encuentro una solución elegante.

Me explico, una función que realiza la carga de un componente (treeview, gridview, columnview) a partir de los datos de una base de datos. En el caso de que todo sea correcto retorna TRUE y sino FALSE.
Para controlar errores de programación utilizo Finally-Catch y además una variable boolean para controlar lógica de programa.

La función sería algo parecido a esto:

[code linenumbers=false syntax=gambas]

Private Function CargaTreeView() As Boolean
   'Realiza la carga del TreeView

   Dim hResult As Result
   Dim sSql As String
   Dim bControl As Boolean = True

   'Abrimos base de datos.
   If Not hConn.Opened Then hConn.Open()
   'Sentencia SQL
   sSql = "SELECT * FROM Tabla "
   hResult = hConn.Exec(sSql)

   'Cargamos resultado
   If hResult Then

      'Proceso de carga del control

   Else

      'Si no hay datos no hay carga
      bControl = False

   Endif

Finally
   hConn.Close()
   hResult = Null

   If Error.Code <= 0 Then Return bControl

Catch
   'Control de errores
   Message.Error("Error: " & Error.Text & gb.CrLf & "Módulo: " & Error.Where)
   Return False

End

[/code]

El problema está en que, aunque no haya ningún error de programación dentro de la función, cuando llega a la linea: "If Error.Code <= 0 Then Return bControl" si existe un error heredado. 
Viene de un "Try" del control TreeView, con debug obtengo:
     Error: 13: Null object
     Módulo: _TreeView_Item._AddChild.136

No se me ocurre más alternativa que, o bien incluir justo antes del "Finally" un Error.Clear(). Asumiendo que si llega hasta ahí la ejecución no hay error de programación. O parchear el código de los controles para limpiar los errores generados por "Try" y volver a construirlos. Ninguna de las dos me convence al 100%.

Subo una pequeña aplicación donde se ve el problema, tiene un control TreeView a la izquierda donde carga Autonomías-Provincias de España desde una base de datos SQLite. Cuando se selecciona una provincia carga un ColumnView con Poblaciones-Codigos postales-Direcciones. La función de carga del TreeView limpia el error del control antes del "Finally", la función de carga del ColumnView no, por tanto el "return" por defecto es False.

Estoy usando Gambas 3.14.3. Cualquier sugerencia es bienvenida y gracias de antemano.
Un saludo. H.

 [img]https://foro.gambas-es.org/files/images/2435/captura_de_pantalla_2020_04_26_13_20_26.png[/img]

Programa ejemplo:


-----------------------------------
v3ctor
Domingo, 26 Abril 2020, 13:35

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
podrías hacer un video con el error y subirlo?


-----------------------------------
v3ctor
Domingo, 26 Abril 2020, 13:43

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
a ti te sale esta ventana en el error?


 [img]https://foro.gambas-es.org/files/images/2261/no_hay_datos_para_la_provincia_04.png[/img]

el error lo tira en esta zona:

[code linenumbers=false syntax=gambas]FMain.CargaColumnView.232: 13: Null object
FMain.CargaColumnView.233: _TreeView_Item._AddChild.136[/code]


-----------------------------------
v3ctor
Domingo, 26 Abril 2020, 13:51

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
comenta todo el código de finality, y purga el error que hay primero


-----------------------------------
v3ctor
Domingo, 26 Abril 2020, 13:56

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
comente todas las lineas de finality y tira error: null key

 [img]https://foro.gambas-es.org/files/images/2261/null_key.png[/img] 

arregla eso primero


-----------------------------------
Harpo
Domingo, 26 Abril 2020, 15:22

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
[quote user="v3ctor" post="48067"]a ti te sale esta ventana en el error?


 [img]https://foro.gambas-es.org/files/images/2261/no_hay_datos_para_la_provincia_04.png[/img]

el error lo tira en esta zona:

[code linenumbers=false syntax=gambas]FMain.CargaColumnView.232: 13: Null object
FMain.CargaColumnView.233: _TreeView_Item._AddChild.136[/code][/quote]

Gracias por tu interés Victor, esa ventana se produce al no devolver nada la función y por tanto toma valor por defecto: False. El mensaje lo lanza el evento Select del Treeview. El error "13: Null object" se produce internamente en el ColumnView, no en el programa ejemplo. Es el problema que señalo, un error que se produce internamente en un control y que "hereda" la aplicación que lo usa.


-----------------------------------
Harpo
Domingo, 26 Abril 2020, 15:33

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
[quote user="v3ctor" post="48069"]comente todas las lineas de finality y tira error: null key

 [img]https://foro.gambas-es.org/files/images/2261/null_key.png[/img] 

arregla eso primero[/quote]

Mis disculpas, hice todas las pruebas con una base de datos completa, para subir el programa tuve que eliminar muchos datos.
Para subsanar el error basta cambiar la linea 144: If hResult then
por:    If hResult.Available Then

Gracias por tu interés!


-----------------------------------
tincho
Domingo, 26 Abril 2020, 15:50

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
Hola Harpo.
El error sucede porque se levanta el evento treeview1_select() antes que el treeview tenga elementos, de ahi el null.
La solución es usar unas banderas, por ejemplo cargado = true una vez que cargaste el treeview y en el evento treeview_select pones un condicional
 IF cargado = true then

Saludos.


-----------------------------------
Harpo
Domingo, 26 Abril 2020, 17:16

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
[quote user="tincho" post="48077"]Hola Harpo.
El error sucede porque se levanta el evento treeview1_select() antes que el treeview tenga elementos, de ahi el null.
La solución es usar unas banderas, por ejemplo cargado = true una vez que cargaste el treeview y en el evento treeview_select pones un condicional
 IF cargado = true then

Saludos.[/quote]

Hola y gracias por la respuesta.
No veo lo que comentas. El evento TreeView1_Select() se dispara por primera vez al asignar: Key = "*" en el proceso de carga, y en el evento se controla que si TreeView.count = 1 no continue.
He probado a poner una bandera (bCargando = True) y no afecta

Por otro lado el error que existe al final del proceso de carga es: 13 - Null Object. en _TreeView_Item._AddChild.136
En el código fuente del control TreeView:

[code linenumbers=false syntax=gambas]
Public Sub _AddChild(sKey As String)

  If Not $aChildren Then $aChildren = New String[]
  $aChildren.Add(sKey)

  If $aChildren.Count = 1 Then
    Try Inc GetTree()._GetParentItem(Me)._GrandChildren
  Endif

End
[/code]

El error que aparece en mi programa ejemplo viene del "Try" del código fuente anterior en el control TreeView. Probé a depurar el ejemplo que viene el código fuente de Gambas y efectivamente da error "Null Object", intenta incrementar el contador de nodos hijos (_GrandChildren) del nodo padre del que estamos insertando (_GetParentItem(Me)) en el TreeView (GetTree()). Y lo hace solo para el primer nodo ($aChildren.Count = 1) que es el nodo Root y no tiene padre. De ahí el nulo. Si se comenta la linea del "Try" el control TreeView funciona perfectamente.

Quizá en este ejemplo se vea más claro que error es del control TreeView.


-----------------------------------
tincho
Domingo, 26 Abril 2020, 17:27

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
Hay que comprobar si hay error (si no es null) antes de poder ver si es > 0.
[code linenumbers=false syntax=gambas]
Public Sub btCargar_Click()

  With TreeView1
    .Add("*", "Nodo Root")
    .Add("Child1", "Hijo 1",, "*")
    .Add("Child1-1", "Sub Hijo 1-1",, "Child1")
    .Add("Child1-2", "Sub Hijo 1-2",, "Child1")
    .Add("Child1-3", "Sub Hijo 1-3",, "Child1")
    .Add("Child1-4", "Sub Hijo 1-4",, "Child1")

    .Add("Child2", "Hijo 2",, "*")
    .Add("Child2-1", "Sub Hijo 2-1",, "Child2")
    .Add("Child2-2", "Sub Hijo 2-2",, "Child2")
    .Add("Child2-3", "Sub Hijo 2-3",, "Child2")
    .Add("Child2-4", "Sub Hijo 2-4",, "Child2")
  End With

Finally
  If Error Then ' Agregue esto a tu código
    If Error.Code > 0 Then
      Message.Info("Error: " & Error.Text & gb.CrLf & "Módulo: " & Error.Where)
    Endif
  Endif ' Agregue esto a tu código

Catch
  Message.Error("Errorx: " & Error.Text & gb.CrLf & "Módulo: " & Error.Where)

End

Public Sub btSalir_Click()

  Me.Close()

End
[/code]
Saludos.


-----------------------------------
Harpo
Domingo, 26 Abril 2020, 18:15

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
[quote user="tincho" post="48079"]Hay que comprobar si hay error (si no es null) antes de poder ver si es > 0.
[code linenumbers=false syntax=gambas]
Public Sub btCargar_Click()

  With TreeView1
    .Add("*", "Nodo Root")
    .Add("Child1", "Hijo 1",, "*")
    .Add("Child1-1", "Sub Hijo 1-1",, "Child1")
    .Add("Child1-2", "Sub Hijo 1-2",, "Child1")
    .Add("Child1-3", "Sub Hijo 1-3",, "Child1")
    .Add("Child1-4", "Sub Hijo 1-4",, "Child1")

    .Add("Child2", "Hijo 2",, "*")
    .Add("Child2-1", "Sub Hijo 2-1",, "Child2")
    .Add("Child2-2", "Sub Hijo 2-2",, "Child2")
    .Add("Child2-3", "Sub Hijo 2-3",, "Child2")
    .Add("Child2-4", "Sub Hijo 2-4",, "Child2")
  End With

Finally
  If Error Then ' Agregue esto a tu código
    If Error.Code > 0 Then
      Message.Info("Error: " & Error.Text & gb.CrLf & "Módulo: " & Error.Where)
    Endif
  Endif ' Agregue esto a tu código

Catch
  Message.Error("Errorx: " & Error.Text & gb.CrLf & "Módulo: " & Error.Where)

End

Public Sub btSalir_Click()

  Me.Close()

End
[/code]
Saludos.[/quote]

Gracias por el apunte.
Lo que intento es encontrar una manera de evitar que errores internos gestionados con "Try" en el control TreeView, y pasa lo mismo con ColumnView y GridView, afecten a funciones de carga de datos que funcionan correctamente en nuestros programas. 
La cláusula Finally se ejecuta antes que Catch en caso de error, si hay un Return en Finally no se ejecuta Catch y no muestra el error, por eso la idea de usar la sentencia: If Error.Code <= 0 Then Return True. 
En caso de error de programación dentro de la función de carga no ejecutaría el Return y continuaría con Catch mostrando el error.
El problema es que Error.Code es mayor que 0 por el funcionamiento interno del TreeView, no por error de la función de carga, y me lo descoloca todo. 

Y yo solo veo dos alternativas:
- Parchear los controles estándar (no me gusta).
- Justo antes de la cláusula Finally poner una sentencia Error.Clear() asumiendo que si ha llegado hasta ahí la ejecución no ha habido ningún error propio.

Creo que no me explico correctamente  :cry:


-----------------------------------
jguardon
Domingo, 26 Abril 2020, 19:37

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
Hola

Una aclaración: la cláusula [i]Finally[/i] se ejecuta siempre. Da igual que haya error o no, pero siempre se ejecuta lo que contenga Finally. De manera que, aunque en otros lenguajes el flujo es [i]Try...Catch...Finally,[/i] en gambas no se usa [i]Try[/i] junto con [i]Catch[/i] y/o [i]Finally[/i]. Cuando se usa Try, se "oculta" el error que puede ser gestionado mediante la sentencia [i]If error then[/i]...

Por lógica, en el caso de Catch y Finally, éste último contendrá el código que deba ejecutarse haya o no un error. [i]Catch[/i] ejecutará el código para manejar el eventual error si se produce.

Dicho esto, creo que si el control Treeview al que le pasas un objeto Result inválido genera un error, es completamente normal. Lo que en mi opinión habría que hacer es [u]comprobar dicho objeto Result antes de pasarlo al control[/u] (por ejemplo comprobando si tiene registros o son válidos esos registros).

El control Treeview tiene ciertas particularidades que lo hacen bastante engorroso de manejar, pero al igual que el resto de controles para datos, sólo pueden mostrar datos que les lleguen de la forma adecuada, de manera que insisto en que ahí radica el problema y no en el control.

Saludos


-----------------------------------
Harpo
Domingo, 26 Abril 2020, 20:28

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
[quote user="jguardon" post="48082"]Hola

Una aclaración: la cláusula [i]Finally[/i] se ejecuta siempre. Da igual que haya error o no, pero siempre se ejecuta lo que contenga Finally. De manera que, aunque en otros lenguajes el flujo es [i]Try...Catch...Finally,[/i] en gambas no se usa [i]Try[/i] junto con [i]Catch[/i] y/o [i]Finally[/i]. Cuando se usa Try, se "oculta" el error que puede ser gestionado mediante la sentencia [i]If error then[/i]...

Por lógica, en el caso de Catch y Finally, éste último contendrá el código que deba ejecutarse haya o no un error. [i]Catch[/i] ejecutará el código para manejar el eventual error si se produce.

[/quote]

Gracias por la información. Totalmente de acuerdo, [i]Finally[/i] se ejecuta siempre, por eso creo que es el sitio adecuado para realizar acciones como cerrar conexiones de base de datos y liberar objetos. Pero si dentro de [i]Finally[/i] se incluye un [i]Return[/i] ya no ejecuta [i]Catch[/i]. De ahí la idea de que si incluyo un [i]Return[/i] esté condicionado a que [i]Error.Code[/i] sea cero y el error esté controlado.

[quote user="jguardon" post="48082"]Hola

Dicho esto, creo que si el control Treeview al que le pasas un objeto Result inválido genera un error, es completamente normal. Lo que en mi opinión habría que hacer es [u]comprobar dicho objeto Result antes de pasarlo al control[/u] (por ejemplo comprobando si tiene registros o son válidos esos registros).

El control Treeview tiene ciertas particularidades que lo hacen bastante engorroso de manejar, pero al igual que el resto de controles para datos, sólo pueden mostrar datos que les lleguen de la forma adecuada, de manera que insisto en que ahí radica el problema y no en el control.

[/quote]

En este punto, con su permiso, discrepo. En el segundo ejemplo que he subido se hace una carga simple y directa mediante [i]TreeView.Add()[/i] de forma adecuada y aun así cuando en [i]Finally[/i] se hace un [i]Debug Error.Code[/i] el resultado no es cero. Hay un [i]Try[/i] interno en el control que provoca un error que se "hereda". No tiene mayor transcendencia, es el funcionamiento estándar del control, tendrá su razón de ser, pero [i]Error.Code[/i] ya no es cero.
Y me tira por tierra mi planteamiento...  :|


-----------------------------------
jguardon
Lunes, 27 Abril 2020, 18:22

Re: Problema Con Control De Errores Y Return En Una Función
-----------------------------------
Pues tienes toda la razón. Debería haber empezado por probar tu ejemplo, que evidentemente arroja los resultados que mencionas.

La idea de filtrar por el código de error no es del todo mala, siendo un número positivo alto (13). Cualquier otro error de programación te va a dar un número inferior a 0, generalmente un -1, con lo cual la expresión If Error.Code < 0 debería bastar, aunque no es equiparable a True o False, siempre sería True porque nunca vas a obtener 0 en la salida.

No veo otra solución a menos que se modifique el código fuente del control. También puedes abrir un reporte de error en el bugtracker de gambas ( https://gambaswiki.org/bugtracker ).

Saludos y disculpa por hablar sin probar  :oops:  :oops:


