Página 1 de 1

Formulario tipo MS-Access

Publicado: 12 Ene 2012, 21:37
por jamaro
Hola:

En mi intención de ir convirtiendo las bases de datos que tengo en MS-Access a Autoit+SQLite voy averiguando cosas en este y otros foros para ver si abordo definitivamente el tema.

Ya he hecho consultas sobre el tema, y esta vez vengo a comentar sobre los formularios. En principio las tablas de SQLite es muy sencillo presentarlas en ListView, pero estoy buscando una manera sencilla de editar los datos directamente en el listado.

En los foros he visto que hay códigos para editar una "celda/item" haciendo doble clic sobre el mismo. Algunos son complejos.

Hay un editor de archivos CSV llamado CSV-Editor que tiene muy buen aspecto. Por lo que he visto en el código, para la edición de los datos de las "celdas/item" del listview, lo que hace es:
1. Crea un input oculto en el formulario
2. Al hacer doble click sobre una "celda/item" averigua la posición y rectángulo del mismo
3. Obtiene el valor del contenido de la "celda/item"
4. Ubica y redimensiona el input en la "celda/item" con su posición y tamaño y lo muestra, poniendo como contenido el valor obtenido antes.
5. Tras darle ENTER (hay un HotKeySet asignado) recoge el valor del contenido del input y reemplaza el valor original de la "celda/item" del listview

Pero he visto que hay también una UDF llamada GUIScrollBars_Ex (Autor Melba23) que permite poner barras de desplazamiento en un GUI.
Esta UDF y algunos ejemplos que figuran en su hilo del foro inglés, me han hecho pensar que quizás era posible hacer algo como en MS-Acces, con un subformulario dentro de un formulario, y los datos presentados en inputs (en lugar de listview, lo que en Access se llama "Formulario continuo"), e incluso controles combo para que muestre los datos relacionados de otra tabla,...

He hecho esta prueba que adjunto (por favor fijaos sólo en lo que se refiere a este hilo, es una prueba y no está muy trabajado :smt003 ) donde tenemos un GUI con un "subGUI" dentro en el que se muestra todos los datos de una tabla de la base de datos.
Además, al crear por orden los input, podemos desplazarnos por ellos con la tecla TAB.
Se puede probar cambiando el nombre de la tabla a utilizar (Cliente o Empresa).

Hasta ahí parece que está bien, pero:
1) ¿creéis que es un buen método para presentar y editar las bases de datos?
2) ¿cómo se os ocurre la manera más sencilla de editar los datos? ¿quizás un evento que al modificar el contenido de un input cambie ese valor en la matriz $aResult y al salir del formulario actualice la base de datos SQLite? ¿quizás directamente, con cada control que se modifique, actualizar la base de datos de SQLite?

Dejo abierto el debate :smt001

EDITO: Ahora el ZIP incluye el archivo GUIScrollBars_Ex.au3

Re: Formulario tipo MS-Access

Publicado: 13 Ene 2012, 09:55
por Ximorro
Por favor, ¿puedes incluir GUIScrollbars_Ex.au3 en la descarga?

Me gustaría ver el ejemplo pero te puedo comentar algo sobre las preguntas antes de verlo.
El caso es que en cuestiones de GUI siempre es mejor que sea intuitivo para el usuario, para que pueda manejarse con la aplicación sin demasiadas explicaciones. Así que tanto el formato tabla como el de inputboxes (quizás separados en diferentes tabs, si son muchos) son interesantes.
Depende más bien de la manera en que sea más interesante mostrar los datos: uno sólo registro cada vez (inputs) o todos a la vez (tabla).
Creo que técnicamente la tabla será más difícil de implementar (al menos la editable, para mostrar consultas de sólo lectura no será tanto problema).
Para las editables ese sistema de crear un input encima de la celda a modificar me parece una idea excelente.
Para el formato de inputs puede ser interesante montar un sistema similar al viejo DataControl de VB, eso que te permite ir pasando de registros y añadir nuevos. No sé cómo estará el tema de los "subformularios", tengo que ver el ejemplo, pero si no es un lío de manejar es otra herramienta a tener en cuenta.
O sea, que no es que no tenga opinión, sino que digo que todas las opciones son interesantes, y más bien son los datos lo que pueden guiar cuál es mejor. Hay cosas que es mejor verlas en una tabla por ejemplo para comparar valores de diferentes registros. Otras, por ejemplo tablas que se actualizan mucho, son más típicas en formato formulario con campos input, para que el operador rellene más cómodamente los campos del registro en que está interesado.

Y sí, es típico que nada más salir del control se guarde el dato en la base de datos, así que puedes hacer eso. Aunque no es estrictamente necesario siempre que quede claro al usuario lo que está ocurriendo, por ejemplo puedes poner un botón bien grande "GUARDAR MODIFICACIONES" que se habilite cuando se haya cambiado algún input, así el usuario sabe que hasta que no presione ese botón los cambios que está haciendo no están yendo a la base de datos.
También se puede dar un aviso en el cambio de registro (o salir del formulario) por si no hay datos guardados.

No sé si es el tipo de respuesta que esperabas... :smt017

Re: Formulario tipo MS-Access

Publicado: 13 Ene 2012, 10:04
por jamaro
Ximorro escribió:Por favor, ¿puedes incluir GUIScrollbars_Ex.au3 en la descarga?
Perdón, se me olvidó incluirlo :smt015 . Ya está ahora metido en el zip.

Re: Formulario tipo MS-Access

Publicado: 13 Ene 2012, 10:39
por Ximorro
¡Ya he visto la solución con la tabla a base de inputs!
¡Está muy bien!
Te ha quedado genial, encima con la cabecera en el GUI principal, con lo que se hace el scroll sólo de los datos. Muy currado.
Si tu duda es si usar esto o el listview en principio creo que simplemente es cosa de usar aquéllo con lo que te sientas más cómodo.
Probablemente es más fácil usar los input que el listview. Es megacomplicado lo de poner los scrollbar, no me esperaba que fuera tan chungo, pero con la udf es directo ¡¡Melba es un GENIOOOOO!!

Creo que sólo te verás obligado a usar un listview con tablas muy grandes, pues con los inputs se consumirán muchos recursos gráficos. Un listview es un control muy complejo pero consumirá menos recursos que tanto input.

Un programa AutoIt puede manejar más de 65000 controles (ya no sé si es por GUI o por proceso autoit3.exe) que es bastante, pero de todas maneras cuando haya muchos habrá problemas, por ejemplo a la hora de manejar los eventos...

Y bueno, para grandes tablas lo normal no es mostrarla toda, sino un subconjunto de registros, por ejemplo de 100 en 100, y en ese caso pues igual da lo mismo usar el listview o los inputs, aunque el sistema de mostrado de registros será notablemente más complicado...

Re: Formulario tipo MS-Access

Publicado: 13 Ene 2012, 23:08
por jamaro
¡Efectivamente Melba es un crack!

He seguido probando con los input y he visto que es mucho más sencillo de lo que pensaba.

Con GUIRegisterMsg($WM_COMMAND, "_WM_COMMAND") he probado primero en el caso de que el control cambiara $EN_CHANGE, pero esa opción modificaba la Base de Datos con cada pequeño cambio del contenido del control (cada vez que se introducía/eliminaba una letra), así que he probado con $EN_KILLFOCUS y creo que es la solución óptima.

Utilizando la base de datos y el UDF del include del ZIP adjunto, el código ahora es:

Código: Seleccionar todo

; ------ Includes ------
	; Para manejar base de datos SQLite
	#include <sqlite.au3>
	#include <sqlite.dll.au3>

	; Constantes de controles
	#include <EditConstants.au3>
	#include <GUIConstantsEx.au3>
	#include <StaticConstants.au3>

	; Matrices
	#include <Array.au3>

	; Para crear barras de desplazamiento en el GUI
	;GUIScrollBars_Ex - Author(s) .....: Melba23
	#include "includes\GUIScrollbars_Ex.au3"


; ------ Opciones ------
Opt("MustDeclareVars",1)

Global $NombreBD=@ScriptDir&"\"&'Prueba_inputs.db3'
AbreBD($NombreBD)

Global $aResult, $iRows, $iColumns
Global $sCommand
Global $Tabla="Empresa"	; <<<<<<<<<<<<<<< En la BD de ejemplo están las tablas "Empresa" y "Cliente"
;~ Global $Tabla="Cliente"	; <<<<<<<<<<<<<<< En la BD de ejemplo están las tablas "Empresa" y "Cliente"
Global $Orden="Telefono"

if $Orden<>"" Then
	$sCommand="SELECT * FROM " & $Tabla & " ORDER BY "&$Orden&";"
Else
	$sCommand="SELECT * FROM " & $Tabla &";"
EndIf

If _SQLite_GetTable2d(-1,$sCommand,$aResult,$iRows,$iColumns) <> $SQLite_OK Then	; no puede hacer la consulta - puede estar encriptada o no ser una base de datos SQLite
	MsgBox(16,"Error","Este archivo no parece ser una base de datos SQLite válida.")
	Exit
EndIf

ConsoleWrite("Filas="& $iRows & " Columnas=" & $iColumns & @CRLF)

;_ArrayDisplay($aResult)


; GUI Principal
Global $hGUIppal=GUICreate("Principal", 100*$iColumns+130, 550)
GUISetBkColor(0x88AABB, $hGUIppal)

Global $anchoControl=100-(18/$iColumns)
	For $j = 0 To $iColumns-1
		GUICtrlCreateLabel($aResult[0][$j] , ($anchoControl * $j)+30, 10 , $anchoControl, 20) ; El ancho está en función del Scroll
		GUICtrlSetBkColor (-1,0xCCCCCC)
		GUICtrlSetState(-1,$ES_READONLY)
    Next

; GUI (subform)
Global $hGUI = GUICreate("Listado", 100*$iColumns, 500,30,30, $WS_POPUP, $WS_EX_MDICHILD, $hGUIppal)
GUISetBkColor(0xAABBAA, $hGUI)


Global $input[$iRows][$iColumns]

; Añade los Inputs
	For $i = 1 To $iRows	; La fila 0 contiene los títulos de las columnas
		For $j = 0 To $iColumns-1
			$input[$i-1][$j]=GUICtrlCreateInput($aResult[$i][$j] , (100 * $j), (20 * ($i-1)) , 100, 20)
			If Mod($i, 2) = 0 Then
				GUICtrlSetBkColor (-1,0xAAFFAA)
			Else
				GUICtrlSetBkColor (-1,0xFFFFFF)
			EndIf
		Next
	Next

; Generate scrollbars - yes, this all you have to do!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
_GUIScrollbars_Generate($hGUI, 100*$iColumns, 20*$iRows)


	; Activa los GUI
    GUISetState()
    GUISwitch($hGUIppal)
    GUISetState()

GUIRegisterMsg($WM_COMMAND, "_WM_COMMAND")

While 1
    Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			CierraBD($NombreBD)
            Exit
    EndSwitch
WEnd



Func _WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
    #forceref $hWnd, $Msg, $lParam
    Local $cId

    $cId = BitAND($wParam, 0xFFFF)   ;ControlId

    Switch BitShift($wParam, 16)   ;Notification code
	#cs
;~         Case  0x300  ; $EN_CHANGE
		Case  $EN_CHANGE					; Al cambiar: Cada cambio que haga el control (cada letra que se añada o elimine se detecta como cambio, por lo que hace excesivos cambios en la BD)
            For $i = 1 To $iRows
				For $j = 0 To $iColumns-1
					If $cID = $input[$i-1][$j] Then
						ConsoleWrite("El Input [" & $i-1 & "]["&$j&"] ha cambiado" & @CRLF)
						ConsoleWrite("El Id de la fila modificada es: " & Guictrlread($input[$i-1][0]) & @CRLF)
						$sCommand="UPDATE " & $Tabla & " SET " & $aResult[0][$j] & "='" & Guictrlread($input[$i-1][$j]) & "' WHERE " & $aResult[0][0] & "='" & Guictrlread($input[$i-1][0]) & "';"
						ConsoleWrite($sCommand)
						_SQLite_Exec(-1,$sCommand)
						Return
					EndIf
				Next
            Next
		#ce

		Case $EN_KILLFOCUS 					; AL PERDER EL FOCO: Sólo se actualiza la BD si al salir del control su contenido ha cambiado
			; Compara si el valor del control es igual al valor de la matriz que se leyó de la base de datos
			For $i = 1 To $iRows
				For $j = 0 To $iColumns-1
					If $cID = $input[$i-1][$j] Then
						ConsoleWrite("El Input [" & $i-1 & "]["&$j&"] ha perdido el foco" & @CRLF)
						ConsoleWrite("El Id de la fila que ha perdido el foco es: " & Guictrlread($input[$i-1][0]) & @CRLF)
						ConsoleWrite("Valores comparados: " & Guictrlread($input[$i-1][$j]) & " --- " & $aResult[$i][$j] & @CRLF)
						if Guictrlread($input[$i-1][$j])<>$aResult[$i][$j] Then		; Si el valor del control es distinto al de la matriz de la BD
							$sCommand="UPDATE " & $Tabla & " SET " & $aResult[0][$j] & "='" & Guictrlread($input[$i-1][$j]) & "' WHERE " & $aResult[0][0] & "='" & Guictrlread($input[$i-1][0]) & "';"
							ConsoleWrite($sCommand & @CRLF)
							_SQLite_Exec(-1,$sCommand)						; Ejecuta la sentencia SQL
							$aResult[$i][$j]=Guictrlread($input[$i-1][$j])	; Actualiza la matriz con el valor modificado del control
							Return
						Else
							Return
						EndIf
					EndIf
				Next
            Next

    EndSwitch
EndFunc



Func AbreBD($NombreBD)
; Apertura de BD
	Local $hQuery, $aRow, $sMsg
	_SQLite_Startup()
	ConsoleWrite("_SQLite_LibVersion=" &_SQLite_LibVersion() & @CR)
	;_SQLite_Open()
	_sqlite_open($NombreBD)
EndFunc

Func CierraBD($NombreBD)
	_SQLite_Close($NombreBD)
	_SQLite_Shutdown()
EndFunc
He hecho una prueba con una base de datos de unas 11.700 filas y ha tardado un poquito en cargarlas con _SQLite_GetTable2d hasta que se ha mostrado el mensaje ConsoleWrite("Filas="& $iRows & " Columnas=" & $iColumns & @CRLF).
Y luego ha tardado un poco más en generar el GUI con todos los inputs pero además ¡sorpresa! sólo me ha mostrado unas 1650 filas que por 5 columnas que tiene la tabla que he utilizado son unos 8.250 controles input :smt003
El resto ¿dónde están? ¿Es probable que haya llegado a un límite de controles?

Un programa AutoIt puede manejar más de 65000 controles (ya no sé si es por GUI o por proceso autoit3.exe) que es bastante, pero de todas maneras cuando haya muchos habrá problemas, por ejemplo a la hora de manejar los eventos...
Viendo esto creo que será 65000 controles/programa, porque en el GUI no ha querido hacer más, aunque no se ha roto el programa y me ha mostrado los que sí ha puesto.

La verdad es que por un lado, muy contento, porque para BD de menos registros es factible esta solución de subformulario con scroll e inputs dentro, y sino, siempre se puede hacer (pensándolo, claro) que muestre los datos de 100 en 100, como decías Ximorro .

Re: Formulario tipo MS-Access

Publicado: 16 Ene 2012, 10:35
por Ximorro
A ver si el límite de los 8000 controles es por los scrolls, que Melba es un genio pero igual no ha pensado en formularios tan largos y quizás ha limitado el tamaño de la zona "scrolable".
Podría ser tanto por tamaño de subformulario como por número de controles dentro del mismo...
Mala suerte, si te da para más de 1000 filas no está mal, pero sí me temo que te tocará inventar algo para cargar la tabla por tramos...

Re: Formulario tipo MS-Access

Publicado: 16 Ene 2012, 11:00
por jamaro
Ximorro el cuadro "scrollable" creo que es correcto. De hecho, en la parte inferior de los controles input que se muestran, aparece un gran espacio en blanco (sin controles) que se puede desplazar con la barra lateral, como sí tuviera en cuenta los cálculos que he hecho para mostrar los inputs (dentro del For Next, dando la posición en función de $i y $j)

De todos modos, por "operatividad", si opto por el método de los input, parece que será más práctico mostrar los datos en bloques; así se ganará tiempo, incluso el paso de SQLite al Array.

Saludos.

Re: Formulario tipo MS-Access

Publicado: 17 Ene 2012, 02:06
por BasicOs
Te quedó muy guapo el form, solo algún comentario.
1.- si puedes actualizar el zip con la versión nueva que incluye la grabación en la base de datos de los cambios (update)
2.- si puedes hacer una función en vez de un programa algo como:

Código: Seleccionar todo

NavegaDbSqulite("midb")

Func NavegaDbSqlite($midb)
...
..
..
3.- Si deseas añadir un tópico para ponerlo en Scripts como programa hecho.
Salu22:)

Re: Formulario tipo MS-Access

Publicado: 19 Ene 2012, 02:09
por BasicOs
@jamaro
Ximorro escribió: Es megacomplicado lo de poner los scrollbar, no me esperaba que fuera tan chungo, pero con la udf es directo ¡¡Melba es un GENIOOOOO!!
Vaya en el foro inglés le hacen la ola a Melba23 porque según rich2323, es de los Moderadores del foro inglés que tiene paciencia suficiente para hacerte crecer y no llegar a conclusiones muy rápido, sin juzgar, de manera que no se llega a la solución si no con una curva de aprendizaje pasito a pasito.

http://www.autoitscript.com/forum/topic/136604-melba23/

En su firma vienen algunos scripts curiosos como
ExtMsgBox - A user customisable replacement for MsgBox
RecFileListToArray An alternative to _FileListToArray with user-defined include/exclude masks, maximum recursion level, sorting and displayed path options
Notify - Small notifications on the edge of the display

http://www.autoitscript.com/forum/topic ... _p__954990
Salu22:)

Re: Formulario tipo MS-Access

Publicado: 26 Ene 2012, 17:02
por Chefito
Bueno bueno, este post es muy interesante. Está bien el código de Melba. Yo os voy a dar otra solución. Creía que iba a ser efectiva pero me he encontrado con un par de problemas (sobre todo uno) que no me han gustado.

Hace tiempo me bajé una udf de rasim (ayudado por arcker y MrCreatoR). Se trata de una udf que inserta objetos progress en los items de los listview. Logicamente tiene funciones para tratar estos progress. La dirección es: http://www.autoitscript.com/forum/topic ... w_progress

Bueno, vamos a lo que nos interesa en este post. La forma en la que hace esto es, a groso modo, utilizando el listview con objeto padre, y a los objetos progress como hijos (api de win, mirar el código). Una vez que están insertados, los posiciona y los redimensiona tratando los mensajes de windows $wm_notify y $wm_size que afectan al listview.
Igual que puedes insertar un progress, puedes insertar cualquier objeto (edit, button, combo, etc). En este caso nos interesa insertar edits en cada item/subitem.

Pues variando algo el código de alguna de sus funciones, decidí ver que pasaba si intentaba insertar un edit en cada item. El código es este (está algo chapucerillo :smt005 ):

Código: Seleccionar todo

; ------ Includes ------
; Para manejar base de datos SQLite
#include <sqlite.au3>
#include <sqlite.dll.au3>

; Constantes de controles
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <winapi.au3>
#include <GuiListView.au3>
#include <WindowsConstants.au3>
#include <Constants.au3>
#include <GuiEdit.au3>
; Matrices
#include <Array.au3>


; ------ Opciones ------
;~ Opt("MustDeclareVars",1)
Global $aProgress[1][4]
Global Const $SW_HIDE = 0
Global Const $SW_SHOW = 5

Global $NombreBD=@ScriptDir&"\"&'Prueba_inputs.db3'
AbreBD($NombreBD)

Global $aResult, $iRows, $iColumns
Global $sCommand
Global $Tabla="Empresa"   ; <<<<<<<<<<<<<<< En la BD de ejemplo están las tablas "Empresa" y "Cliente"
;~ Global $Tabla="Cliente"   ; <<<<<<<<<<<<<<< En la BD de ejemplo están las tablas "Empresa" y "Cliente"
Global $Orden="Telefono"

if $Orden<>"" Then
   $sCommand="SELECT * FROM " & $Tabla & " ORDER BY "&$Orden&";"
Else
   $sCommand="SELECT * FROM " & $Tabla &";"
EndIf

If _SQLite_GetTable2d(-1,$sCommand,$aResult,$iRows,$iColumns) <> $SQLite_OK Then   ; no puede hacer la consulta - puede estar encriptada o no ser una base de datos SQLite
   MsgBox(16,"Error","Este archivo no parece ser una base de datos SQLite válida.")
   Exit
EndIf

ConsoleWrite("Filas="& $iRows & " Columnas=" & $iColumns & @CRLF)

;_ArrayDisplay($aResult)


; GUI Principal
Global $hGUIppal=GUICreate("Principal", 100*$iColumns+130, 550)

GUISetBkColor(0x88AABB, $hGUIppal)
$hListView = GUICtrlCreateListView("", 10, 10, 400, 180, BitOR($LVS_REPORT, $WS_BORDER),$LVS_EX_GRIDLINES)

For $n=0 to $iColumns-1
   $item1 = _GUICtrlListView_AddColumn($hlistview,$aResult[0][$n],70)
Next
For $n=0 to $iRows-1
   $item1 = _GUICtrlListView_AddItem($hlistview,"")
Next

Global $input[$iRows][$iColumns]

; Añade los Inputs
   For $i = 0 To $iRows-1   ; La fila 0 contiene los títulos de las columnas
      For $j = 0 To $iColumns-1
         $input[$i][$j]=_ListView_InsertProgressBar($hListView, $i, $j)
		 _GUICtrlEdit_SetText($input[$i][$j],$aResult[$i+1][$j])
;~          If Mod($i, 2) = 0 Then
;~             GUICtrlSetBkColor (-1,0xAAFFAA)
;~          Else
;~             GUICtrlSetBkColor (-1,0xFFFFFF)
;~          EndIf
      Next
   Next


    GUISetState()

GUIRegisterMsg($WM_NOTIFY, "_ListView_Notify")
GUIRegisterMsg($WM_SIZE, "_ListView_Notify")

While 1
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
         CierraBD($NombreBD)
            Exit
    EndSwitch
WEnd

Func AbreBD($NombreBD)
; Apertura de BD
   Local $hQuery, $aRow, $sMsg
   _SQLite_Startup()
   ConsoleWrite("_SQLite_LibVersion=" &_SQLite_LibVersion() & @CR)
   ;_SQLite_Open()
   _sqlite_open($NombreBD)
EndFunc

Func CierraBD($NombreBD)
   _SQLite_Close($NombreBD)
   _SQLite_Shutdown()
EndFunc

Func _ListView_InsertProgressBar($sHwnd, $sItemIndex, $sSubItemIndex = 0)
    If Not IsHWnd($sHwnd) Then $sHwnd = GUICtrlGetHandle($sHwnd)

    Local $iStyle = _WinAPI_GetWindowLong($sHwnd, $GWL_STYLE)

	If BitAND($iStyle, $WS_CLIPCHILDREN) <> $WS_CLIPCHILDREN Then
		_WinAPI_SetWindowLong($sHwnd, $GWL_STYLE, BitOR($iStyle, $WS_CLIPCHILDREN))
	EndIf

	Local $aRect

	If $sSubItemIndex = 0 Then
		$aRect = _GUICtrlListView_GetItemRect($sHwnd, $sItemIndex, 2)
	Else
		$aRect = _GUICtrlListView_GetSubItemRect($sHwnd, $sItemIndex, $sSubItemIndex)
	EndIf

    $aProgress[0][0] += 1
    ReDim $aProgress[$aProgress[0][0] + 1][4]
    $aProgress[$aProgress[0][0]][0] = _Progress_Create($sHwnd, $aRect[0]+1, $aRect[1]+1, $aRect[2] - $aRect[0]-2, $aRect[3] - $aRect[1]-2)

    $aProgress[$aProgress[0][0]][1] = $sItemIndex
    $aProgress[$aProgress[0][0]][2] = $sSubItemIndex
    $aProgress[$aProgress[0][0]][3] = $sHwnd

    Return $aProgress[$aProgress[0][0]][0]
EndFunc   ;==>_ListView_InsertProgressBar

Func _Progress_Create($hWnd, $iX, $iY, $iWidth = -1, $iHeight = -1, $iStyle = 0, $iExStyle = 0)
	$iStyle = BitOR($iStyle, $WS_CHILD, $WS_VISIBLE)
	Return _WinAPI_CreateWindowEx($iExStyle, "edit", "", $iStyle, $iX, $iY, $iWidth, $iHeight, $hWnd)
EndFunc   ;==>_Progress_Create

Func _ListView_Notify($hWnd, $Msg, $wParam, $lParam)
	If $Msg = $WM_SIZE Then
		_WinAPI_InvalidateRect($hWnd)
		Return $GUI_RUNDEFMSG
	EndIf

    Local $tNMHEADER, $hWndFrom, $iCode, $i

    $tNMHEADER = DllStructCreate($tagNMHEADER, $lParam)
    $hWndFrom = DllStructGetData($tNMHEADER, "hwndFrom")
	$iCode = DllStructGetData($tNMHEADER, "Code")

	Switch $iCode
		Case $HDN_ITEMCHANGED, $HDN_ITEMCHANGEDW, $LVN_ENDSCROLL
			If $iCode <> $LVN_ENDSCROLL Then $hWndFrom = _WinAPI_GetParent($hWndFrom)

			For $i = 1 To $aProgress[0][0]
				If $aProgress[$i][3] = $hWndFrom Then _
				_MoveProgress($hWndFrom, $aProgress[$i][0], $aProgress[$i][1], $aProgress[$i][2])
			Next

			_WinAPI_InvalidateRect($hWndFrom)
	EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>_ListView_Notify

Func _MoveProgress($hListView, $hProgress, $sItemIndex, $sSubItemIndex)
	Local $aRect

	If $sSubItemIndex = 0 Then
		$aRect = _GUICtrlListView_GetItemRect($hListView, $sItemIndex, 2)
	Else
		$aRect = _GUICtrlListView_GetSubItemRect($hListView, $sItemIndex, $sSubItemIndex)
	EndIf

	If $aRect[1] < 10 Then
        _WinAPI_ShowWindow($hProgress, $SW_HIDE)
    ElseIf $aRect[1] >= 10 Then
        _WinAPI_ShowWindow($hProgress, $SW_SHOW)
    EndIf

    _WinAPI_MoveWindow($hProgress, $aRect[0]+1, $aRect[1]+1, $aRect[2] - $aRect[0]-2, $aRect[3] - $aRect[1]-2, True)
EndFunc   ;==>_MoveProgress
He cambiado en un pixel la posición y redimensión de los controles para que se viesen las líneas de la tabla. Recordad que se necesita en el mismo lugar donde esté este código, la bbdd del que nos proporcionó jamaro. Dejo un archivo zip con el código y la base de datos.

Los dos problemas que me encontré: Primero y más importante, algo de lentitud a la hora de manejar el listview (scroll). Segundo, me fijé que algunas veces, al cambiar el tamaño de las columnas, la información de los edits no se redibujaba bien y aparecía cortada. Solución a esto último, redibujar el listview en los debidos momentos. Lo dejo dicho por si alguien lo quiere hacer :smt024 .

Conclusión: Eso de que se relentize un poco el scroll no me hace mucha gracia. Y ya no os quiero ni contar si le metemos muchos más items e inputs :smt012 .
En definitiva, es una bonita opción ya que se puede meter cualquier objeto, pero con un número determinado de éstos. Autoit no está preparado para hacer este tipo de cosas. Se necesitaría un lenguaje mucho más potente y rápido.

Siempre te queda la posibilidad de intentar encontrar un control grid gratuíto que tenga esta propiedad y se lleve bien con AutoIt . Si buscas y encuentras alguno dinoslo.

Ahora jamaro te voy a decir lo que yo haría (más bien lo que he hecho varias veces en vb6 cuando manejaba bbdd :smt002 ).
Fíjate, con todos los grid que tenía en vb6, yo solía hacer esto. Te pongo un gui hecho con koda para que lo entiendas mejor:

Código: Seleccionar todo

#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 625, 443, 192, 124)
$Group1 = GUICtrlCreateGroup("Group1", 8, 320, 609, 113)
$Input1 = GUICtrlCreateInput("Input1", 24, 368, 97, 21)
$Input2 = GUICtrlCreateInput("Input2", 144, 368, 97, 21)
$Input3 = GUICtrlCreateInput("Input3", 264, 368, 97, 21)
$Input4 = GUICtrlCreateInput("Input4", 384, 368, 97, 21)
$Input5 = GUICtrlCreateInput("Input5", 504, 368, 97, 21)
$Label1 = GUICtrlCreateLabel("Label1", 24, 344, 36, 17)
$Label2 = GUICtrlCreateLabel("Label2", 144, 344, 36, 17)
$Label3 = GUICtrlCreateLabel("Label3", 264, 344, 36, 17)
$Label4 = GUICtrlCreateLabel("Label4", 384, 344, 36, 17)
$Label5 = GUICtrlCreateLabel("Label5", 504, 344, 36, 17)
$Label6 = GUICtrlCreateLabel("1", 264, 405, 100, 17, $SS_CENTER)
$Button1 = GUICtrlCreateButton("<", 232, 400, 33, 25, $WS_GROUP)
$Button2 = GUICtrlCreateButton(">", 364, 400, 33, 25, $WS_GROUP)
$Button3 = GUICtrlCreateButton("Guardar", 504, 400, 81, 25, $WS_GROUP)
$Button4 = GUICtrlCreateButton("Borrar", 48, 400, 75, 25, $WS_GROUP)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$ListView1 = GUICtrlCreateListView("1 columna|2 columna|3 columna|4 columna|5 columan", 8, 16, 609, 297)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 0, 100)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 1, 100)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 2, 100)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 3, 100)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 4, 100)
$ListView1_0 = GUICtrlCreateListViewItem("1 item", $ListView1)
$ListView1_1 = GUICtrlCreateListViewItem("2 item", $ListView1)
$ListView1_2 = GUICtrlCreateListViewItem("3 item", $ListView1)
$ListView1_3 = GUICtrlCreateListViewItem("4 item", $ListView1)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

	EndSwitch
WEnd
Como puedes observar arriba pongo un listview normal con los registros de la bbdd.
Abajo pongo un marco con tantos inputs como campos editables tenga la bbdd (también, en vez ponerlos en la misma ventana, puedes hacer que se abra otra ventana con todos estos controles). En estos inputs deben aparecer los datos del item (registro) que esté seleccionado en la listview. También te he puesto unos botones. Puedes poner tantos como funciones necesites (guardar/actualizar registro/bbdd, limpiar contenido de los inputs, borrar registro, etc). Yo me voy a centrar en el de editar el registro. Este botón al pulsarse debe cambiar el registro de la bbdd y la listview con los nuevos datos. Te recomiendo que cambies el item de la listview directamente, y no recargando la bbdd con el nuevo registro, ya que sería más lento.

Ahora voy a hablar de los controles opcionales que he puesto abajo del todo. Digo opcionales porque no los veo necesarios para hacer lo anterior. Sería rizar el rizo :smt005 . Se trata de un label y 4 botones (sí, 4, se me olvidaron poner dos a cada lado de los que ya hay puestos :smt005 ).
El label debe reflejar el número de registro (item) actual de la lista, que será el mismo que el registro de la bbdd. También puedes hacer como yo hacía, y era poner número registro actual/total registros (Ejemplo "4/245"). Para hacer esto, cada vez que cambies a un item distinto de la lista, se debe actualizar.
Ahora los 4 botones. Los botones "<" y ">" nos mueven para alante y atrás un registro cada vez que se pulsan. Tienen que estar coordinados con el listview y el label, para poder actualizarlos. Los otros dos botones que se me han olvidado serían "<<" y ">>", que nos trasladarían al registro inicial y final respectivamente.
También tienes que controlar cuando llegan al primer y último registro.

Puede que cueste algo programarlos (más tiempo que dificultad) y no te merezca la pena. Como he dicho antes, esto no es necesario.

Menudo rollo te he metido. Espero que por lo menos te haya dado alguna idea.

Saludos.

Re: Formulario tipo MS-Access

Publicado: 27 Ene 2012, 09:58
por Ximorro
Vaya Chefito ahora escribes poco pero cuando te pones...

Muy interesante el primero, bastante complejo de entender la programación pero el concepto este de meter controles dentro de otros puede ser muy interesante. En este caso pues sí va un poco lento pero me parece que se está forzando la máquina con tanto recurso gráfico, demasiados controles en una ventana...
En el segundo has hecho un datacontrol, je, je. También es una buena posibilidad eso de hacer un híbrido tabla-línea de inputs, eso sí será eficiente y la verdad, aunque hay que programar lo del cambio de registros creo que dará menos quebraderos de cabeza.

Se me ocurre una solución intermedia, usando a la vez los dos sistemas de Chefito:
Se puede poner la tabla con los inputs incrustados como en el primer ejemplo, pero que no se haga scroll, simplemente se muestra un número limitado y fijo de registros.
Debajo se pone el "datacontrol", sería lo mismo de mover registros pero en vez de mover uno pasaría a otro bloque, por ejemplo si mostramos 15 líneas, primero se ven del registro 1 al 15, si clicamos "siguiente" en el data control nos mostrará los registros del 16 al 30.
En este caso no estaría la línea de inputs de edición, pues para eso ya están los inputs en el listview. Y como se muestra cada vez un número limitado de filas (algo que habrá que hacer de todas maneras en tablas realmente grandes) no habrá problemas de scroll lento.

Re: Formulario tipo MS-Access

Publicado: 27 Ene 2012, 10:54
por jamaro
Gracias Chefito, la verdad es que al final opté por la presentación con ListView, y algo similar a lo que propones. En un control Edit, muestro el dato de un campo de la fila del ListView que está marcada. Si modifico el contenido del Edit y deseo guardar los cambios, pulso un botón Actualizar y, como tú apuntas en el mensaje anterior, modifico la bbdd con SQLite (sólo el registro que se modifica) y el texto del ListView (sólo el item que se modifica) y NO recargo de nuevo la bbdd.

¡Saludos!