Capturar index item de ListView

Pregunta Sin Miedo no te cortes cualquier cosa para empezar - Autoit se comienza facilmente.Para Ordenes o Comandos sueltos. Ver nota como preguntar.
Responder
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Capturar index item de ListView

Mensaje por avechuche »

Bueno que tal vengo con una duda, la cual tenia resuelto (en otro programa) pero no lo puedo adaptar a un programa nuevo.
Necesito capturar el index de un elemento para poder editarlo. Este es el code que tengo

Código: Seleccionar todo

Func _WM_NOTIFY($hWndGUI, $MsgID, $wParam, $lParam)
	#forceref $hWndGUI, $MsgID, $wParam

	$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	$hwndFrom = DllStructGetData($tNMHDR, "hWndFrom")
	$idFrom = DllStructGetData($tNMHDR, "IDFrom")
	$code = DllStructGetData($tNMHDR, "Code")

	If Not IsHWnd($ListView) Then $hWndListView = GUICtrlGetHandle($ListView)

	Switch $hwndFrom

		Case $hWndListView
			Switch $code
				Case $NM_DBLCLK
					$ID = ControlListView($GUI, "", "SysListView321", "GetSelected", "")
					MsgBox(0, "", $ID)
			EndSwitch
		EndSwitch

	Return $GUI_RUNDEFMSG

EndFunc   ;==>_WM_NOTIFY
Este code no lo hice yo, le lo pasaron, es mas completo, pero la otra parte no me sirve porque habia otro Case que comprobaba si yo habia clic en una ToolBar que ahora no tengo, por eso lo borre, quedando solo "Case $hWndListView". En el otro programa probe documentando la parte que pertenece a la toolbar y sigue funcionando, asi que no es problema de nada q alla borrado ...
El MsgBox, me devuelve vacio.

Me asegure de que este todo bien. $GUI, es mi GUI principal y $ListView es el listview que quiero editar los items.
A esta funcion la llamo mediante, GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY") inmediatamente despues de crear el $GUI.
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Capturar index item de ListView

Mensaje por Ximorro »

Por favor, ¿nos pasas un GUI simple (por ejemplo sólo con el ListView) donde usas la función)?
Me ha tocado hacerlo a mí, y si te digo que me ha funcionado a la primera igual no te ayuda mucho ¿verdad? :smt002
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Capturar index item de ListView

Mensaje por avechuche »

Ximorro escribió:Por favor, ¿nos pasas un GUI simple (por ejemplo sólo con el ListView) donde usas la función)?
Me ha tocado hacerlo a mí, y si te digo que me ha funcionado a la primera igual no te ayuda mucho ¿verdad? :smt002
Aca te dejo parte del code, lo otro no es importante ...

Código: Seleccionar todo

#include <IE.au3>
#include <String.au3>
#include <Array.au3>
#include <GuiRichEdit.au3>
#include <GDIPlus.au3>
#include <GuiConstantsEx.au3>
#include <File.au3>
#include <ListviewConstants.au3>
#include <GuiListView.au3>
#include <GUIConstantsEx.au3>
#include <GuiTab.au3>
#include <WindowsConstants.au3>

Global $GUI, $Listview, $Dir_TXT = @ScriptDir & "\Archivo.txt"

_GUI()

Func _Crear_ListView()

	$Styles = $LVS_SINGLESEL
	$exStyles = $LVS_EX_CHECKBOXES + $LVS_EX_FULLROWSELECT + $LVS_EX_GRIDLINES

	; ====== Agregar ====== ;
	$Listview = GUICtrlCreateListView("Columna 1|Columna 2|Columna 3|Columna 4|Columna 5", 25, 280, 310, 225, -1, $exStyles)
	_GUICtrlListView_JustifyColumn($Listview, 0, 2)
	_GUICtrlListView_JustifyColumn($Listview, 1, 2)
	_GUICtrlListView_JustifyColumn($Listview, 2, 2)
	_GUICtrlListView_JustifyColumn($Listview, 3, 2)
	_GUICtrlListView_JustifyColumn($Listview, 4, 2)
	; ====== ;

	; ====== ;
	$Listview_Pueblos = GUICtrlCreateListView("Columna 1|Columna 2|Columna 3|Columna 4|Columna 5|Columna 6", 25, 45, 310, 225, -1, $LVS_EX_FULLROWSELECT + $LVS_EX_GRIDLINES)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 0, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 1, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 2, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 3, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 4, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 5, 2)
	; ====== ;

EndFunc   ;==>_Crear_ListView

Func _GUI()

	$Ancho_GUI = 800
	$Alto_GUI = 600

	$GUI = GUICreate("Probando ...", $Ancho_GUI, $Alto_GUI)
	GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")

	$Tab = GUICtrlCreateTab(10, 10, $Ancho_GUI - 20, $Alto_GUI - 80)
	GUICtrlCreateTabItem("Web")
	_GUICtrlTab_SetBkColor($GUI, $Tab, 0xc3d7fb)
	$oIE = _IECreateEmbedded()
	$GUIActiveX = GUICtrlCreateObj($oIE, 20, 40, $Ancho_GUI - 40, $Alto_GUI - 120)

	$Tab_AP = GUICtrlCreateTabItem("Agregar")
	_Crear_ListView()

	GUICtrlCreateTabItem("")

	_Cargar()

	GUISetState()

	While 1

		Sleep(10)

		Switch GUIGetMsg()

			Case -3

				Exit

		EndSwitch

	WEnd

EndFunc   ;==>_GUI

Func _GUICtrlTab_SetBkColor($hWnd, $hSysTab32, $sBkColor)

	Local $aTabPos = ControlGetPos($hWnd, "", $hSysTab32)
	Local $aTab_Rect = _GUICtrlTab_GetItemRect($hSysTab32, -1)

	GUICtrlCreateLabel("", $aTabPos[0] + 2, $aTabPos[1] + $aTab_Rect[3] + 4, $aTabPos[2] - 6, $aTabPos[3] - $aTab_Rect[3] - 7)
	GUICtrlSetBkColor(-1, $sBkColor)
	GUICtrlSetState(-1, $GUI_DISABLE)

EndFunc   ;==>_GUICtrlTab_SetBkColor

Func _WM_NOTIFY($hWndGUI, $MsgID, $wParam, $lParam)
	#forceref $hWndGUI, $MsgID, $wParam

	$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	$hwndFrom = DllStructGetData($tNMHDR, "hWndFrom")
	$idFrom = DllStructGetData($tNMHDR, "IDFrom")
	$code = DllStructGetData($tNMHDR, "Code")

	If Not IsHWnd($Listview) Then $hWndListView = GUICtrlGetHandle($Listview)

	Switch $hwndFrom

		Case $hWndListView

			Switch $code

				Case $NM_DBLCLK

					$ID = ControlListView($GUI, "", "SysListView321", "GetSelected", "")
					MsgBox(0, "", $ID)

			EndSwitch

	EndSwitch

	Return $GUI_RUNDEFMSG

EndFunc   ;==>_WM_NOTIFY

Func _Cargar()

	; El Archivo de texto que abre aca tiene en cada linea ciertos datos, separados por la barra "|"

	_GUICtrlListView_DeleteAllItems($Listview)
	$Cantidad_lineas = _FileCountLines($Dir_TXT)

	$TXT = FileOpen($Dir_TXT)

	For $a = 1 To $Cantidad_lineas

		$Linea = FileReadLine($TXT)
		GUICtrlCreateListViewItem($a & "|" & $Linea, $Listview)

	Next

	FileClose($TXT)

	_GUICtrlListView_SetColumnWidth($Listview, 0, $LVSCW_AUTOSIZE_USEHEADER)
	_GUICtrlListView_SetColumnWidth($Listview, 1, $LVSCW_AUTOSIZE_USEHEADER)
	_GUICtrlListView_SetColumnWidth($Listview, 2, $LVSCW_AUTOSIZE_USEHEADER)
	_GUICtrlListView_SetColumnWidth($Listview, 3, $LVSCW_AUTOSIZE_USEHEADER)
	_GUICtrlListView_SetColumnWidth($Listview, 4, $LVSCW_AUTOSIZE_USEHEADER)

EndFunc   ;==>_Cargar
Por ahora lo solucione con asi $ID = _GUICtrlListView_GetNextItem($Listview), esa funcion me devuelve el index, sirve, pero quisiera saber porque a mi no me anda de la otra forma.
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Capturar index item de ListView

Mensaje por Ximorro »

Bueno, ejem, no es un código tan simplificado pero se agradece. Y digamos que es un poco difícil de probar porque depende de un archivo de texto que no proporcionas.
Bueno, intentaré analizarlo aunque no lo pueda ejecutar y te diré algo...

Vale, ya estoy de vuelta...
A ver, el principal problema es que tienes dos ListView y no lo has contemplado.
Por cierto, ten cuidado porque hay variables que no has declarado, precisamente ese $Listview_Pueblos no está claro si es global o local.
En cualquier caso existe en el GUI, y lo que está pasando es que en la función de gestión de mensaje sí especificas que trabaje sólo con $ListView, pero luego a la hora de mirar la línea seleccionada lo haces con:
$ID = ControlListView($GUI, "", "SysListView321", "GetSelected", "")
Y resulta que "SysListView321" es a piñón fijo el primer Listview del GUI, pero resulta que ese es $Listview_Pueblos, que no tiene nada seleccionado, así que te sacará una cadena vacía.

Una solución sería usar "SysListView322", que es probable que sea el nombre del segundo ListView del GUI, pero no es una solución muy flexible. Lo mejor es, ya que tomas el handle del Listview en $hWndListView, usarlo para identificar el control:
$ID = ControlListView($GUI, "", $hWndListView, "GetSelected", "")
Así ya debería funcionar, ya me dices.

Suerteeeee
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Capturar index item de ListView

Mensaje por avechuche »

Muchas gracias Ximo, para mi pregunta anda perfecto, pero ahora tengo un efecto no deseado ^^. Vamos por parte.

Cito:

Código: Seleccionar todo

Y resulta que "SysListView321" es a piñón fijo el primer Listview del GUI, pero resulta que ese es $Listview_Pueblos, que no tiene nada seleccionado, así que te sacará una cadena vacía
1) Con respecto a esto, ¿Como me iba a imaginar q "SysListView321" es el primer listview?
2) Me decis que q esto "SysListView321" corresponde al primer listview del GUI, ¿primer listview que se crea o el primero de arriba para abajo? Porque "$Listview_Pueblos" se crea ultimo, pero es el primero de los dos.

Ahora resulta que tengo un problema, te paso el code de nuevo.
Fijate lo q pasa con el _Arraydisplay desp que hago 2 clic en un item del listview.

Código: Seleccionar todo

#include <IE.au3>
#include <String.au3>
#include <Array.au3>
#include <GuiRichEdit.au3>
#include <GDIPlus.au3>
#include <GuiConstantsEx.au3>
#include <File.au3>
#include <ListviewConstants.au3>
#include <GuiListView.au3>
#include <GUIConstantsEx.au3>
#include <GuiTab.au3>
#include <WindowsConstants.au3>

Global $GUI, $Listview, $Dir_TXT = @ScriptDir & "\Archivo.txt"

_GUI()

Func _Crear_ListView()

	$Styles = $LVS_SINGLESEL
	$exStyles = $LVS_EX_CHECKBOXES + $LVS_EX_FULLROWSELECT + $LVS_EX_GRIDLINES

	; ====== Agregar ====== ;
	$Listview = GUICtrlCreateListView("Columna 1|Columna 2|Columna 3|Columna 4|Columna 5", 25, 280, 310, 225, -1, $exStyles)
	_GUICtrlListView_JustifyColumn($Listview, 0, 2)
	_GUICtrlListView_JustifyColumn($Listview, 1, 2)
	_GUICtrlListView_JustifyColumn($Listview, 2, 2)
	_GUICtrlListView_JustifyColumn($Listview, 3, 2)
	_GUICtrlListView_JustifyColumn($Listview, 4, 2)
	; ====== ;

	; ====== ;
	$Listview_Pueblos = GUICtrlCreateListView("Columna 1|Columna 2|Columna 3|Columna 4|Columna 5|Columna 6", 25, 45, 310, 225, -1, $LVS_EX_FULLROWSELECT + $LVS_EX_GRIDLINES)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 0, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 1, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 2, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 3, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 4, 2)
	_GUICtrlListView_JustifyColumn($Listview_Pueblos, 5, 2)
	; ====== ;

EndFunc   ;==>_Crear_ListView

Func _GUI()

	$Ancho_GUI = 800
	$Alto_GUI = 600

	$GUI = GUICreate("Probando ...", $Ancho_GUI, $Alto_GUI)
	GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")

	$Tab = GUICtrlCreateTab(10, 10, $Ancho_GUI - 20, $Alto_GUI - 80)
	GUICtrlCreateTabItem("Web")
	_GUICtrlTab_SetBkColor($GUI, $Tab, 0xc3d7fb)
	$oIE = _IECreateEmbedded()
	$GUIActiveX = GUICtrlCreateObj($oIE, 20, 40, $Ancho_GUI - 40, $Alto_GUI - 120)

	$Tab_AP = GUICtrlCreateTabItem("Agregar")
	_Crear_ListView()

	GUICtrlCreateTabItem("")

	_Cargar()

	GUISetState()

	While 1

		Sleep(10)

		Switch GUIGetMsg()

			Case -3

				Exit

		EndSwitch

	WEnd

EndFunc   ;==>_GUI

Func _GUICtrlTab_SetBkColor($hWnd, $hSysTab32, $sBkColor)

	Local $aTabPos = ControlGetPos($hWnd, "", $hSysTab32)
	Local $aTab_Rect = _GUICtrlTab_GetItemRect($hSysTab32, -1)

	GUICtrlCreateLabel("", $aTabPos[0] + 2, $aTabPos[1] + $aTab_Rect[3] + 4, $aTabPos[2] - 6, $aTabPos[3] - $aTab_Rect[3] - 7)
	GUICtrlSetBkColor(-1, $sBkColor)
	GUICtrlSetState(-1, $GUI_DISABLE)

EndFunc   ;==>_GUICtrlTab_SetBkColor

Func _WM_NOTIFY($hWndGUI, $MsgID, $wParam, $lParam)
	#forceref $hWndGUI, $MsgID, $wParam

	$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	$hwndFrom = DllStructGetData($tNMHDR, "hWndFrom")
	$idFrom = DllStructGetData($tNMHDR, "IDFrom")
	$code = DllStructGetData($tNMHDR, "Code")

	If Not IsHWnd($Listview) Then $hWndListView = GUICtrlGetHandle($Listview)

	Switch $hwndFrom

		Case $hWndListView

			Switch $code

				Case $NM_DBLCLK

;~ 					$ID = ControlListView($GUI, "", $hWndListView, "GetSelected", "")
					$ID = _GUICtrlListView_GetNextItem($Listview)
;~ 					$ID = ControlListView($GUI, "", $hWndListView, "GetSelected", "")
					$Item = _GUICtrlListView_GetItemTextString($Listview, $ID)
					$Item = StringSplit($Item, "|", 2)
					_ArrayDisplay($Item)

			EndSwitch

	EndSwitch

	Return $GUI_RUNDEFMSG

EndFunc   ;==>_WM_NOTIFY

Func _Cargar()

	; El Archivo de texto que abre aca tiene en cada linea ciertos datos, separados por la barra "|"

	_GUICtrlListView_DeleteAllItems($Listview)
	$Cantidad_lineas = _FileCountLines($Dir_TXT)

	$TXT = FileOpen($Dir_TXT)

	For $a = 1 To $Cantidad_lineas

		$Linea = FileReadLine($TXT)
		GUICtrlCreateListViewItem($a & "|" & $Linea, $Listview)

	Next

	FileClose($TXT)

	_GUICtrlListView_SetColumnWidth($Listview, 0, $LVSCW_AUTOSIZE_USEHEADER)
	_GUICtrlListView_SetColumnWidth($Listview, 1, $LVSCW_AUTOSIZE_USEHEADER)
	_GUICtrlListView_SetColumnWidth($Listview, 2, $LVSCW_AUTOSIZE_USEHEADER)
	_GUICtrlListView_SetColumnWidth($Listview, 3, $LVSCW_AUTOSIZE_USEHEADER)
	_GUICtrlListView_SetColumnWidth($Listview, 4, $LVSCW_AUTOSIZE_USEHEADER)

EndFunc   ;==>_Cargar
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Capturar index item de ListView

Mensaje por Ximorro »

1) Con respecto a esto, ¿Como me iba a imaginar q "SysListView321" es el primer listview?

Es que no debes usar eso, ahí le estás diciendo que ese control es de clase "SysListView32" y que es la primera instancia "1" de esa clase que hay en el formulario.
Es lo que ves cuando identificas el control con Au3Info, por ejemplo. Eso es equivalente a usar [CLASS:SysListView32; INSTANCE:1].
La clase del control siempre será esa, ¿pero qué instancia le corresponderá? ¡no se sabe! Eso lo sabes una vez el programa está compilado, si lo modificas y recompilas puede que el GUI se cree de otra manera y le toque otro valor.

Por eso lo mejor es tomar su handle, que también lo identifica, desde dentro de AutoIT como tienes una referencia al control puedes usar la función GUICtrlGetHandle, por eso he usado eso en _WM_NOTIFY.

NOTA: El handle es variable en CADA ejecución, así que NO debes usar para identificar controles externos el valor de handle que te da Au3Info. Pero desde dentro de tu programa puedes consultar el handle que el control tiene en ese momento con la función GUICtrlGetHandle, así que ahí no es problema.

Respecto a la pregunta (2) es por lo mismo. Sólo tienes que usar esa manera de identificar controles (clase + instancia) cuando manipules ventanas que no son de tu programa, esas que analizas con Au3Info. En tus GUIs usa las variables que referencian a los controles (a veces directamente, y a veces tomando el handle, según requiera la función).


En lo del programa lo que te decía antes, no puedo fijarme en lo que pasa con _ArrayDisplay porque no puedo ejecutarlo, si acaso pásame el txt para que pueda probar el programa.
Pero te diré una cosa, las funciones que tratan mensajes (y también las de eventos) deben ser despachadas lo más rápidamente posible. El tratamiento incorrecto de un mensaje puede ser bloqueante para el programa o incluso el sistema. Los eventos y mensajes son tratados en colas de trabajo del S.O., y si bloqueas uno puede que los que esperan en la cola se retrasen cada vez más, y eso no es nada bueno.

O sea, es muy mala idea tener _ArrayDisplay de dentro de _WM_NOTIFY, porque esa función saca un GUI bloqueante. Para hacer pruebas podrías sacar los datos por la consola o se me ocurren otras cosas más complicadas con las funciones Adlib y tal...
Eso no solucionará el problema que tienes, pero ten eso en cuenta: Mensajes y eventos deben ser ejecutados rápidamente.
(En AutoIt los eventos que hay que tratar rápido son los de modo OnEvent, en bucle de mensajes el evento real de Windows lo ha tratado GuiGetMsg y ahí no es tan crítico)
Si no te fías de mí resulta que lo pone en la ayuda de GUIRegisterMsg:
"Advertencia: el bloqueo de funciones de usuario que ejecutan mensajes de Windows con comandos como "Msgbox()" puede dar un comportamiento inesperado, el retorno del sistema debe ser lo más rápido posible!!!"

Dicho eso no puedo ver lo que le pasa ¿has mirado qué vale $Item?, ¿lo estás montando bien?
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Capturar index item de ListView

Mensaje por avechuche »

Mejor explicado imposible. Muchisimas gracias multiplicadas por muchisimas gracias.
Con respecto a lo del _Arraydisplay(), es algo obvio, ahora q me lo decis es claro, con _Arraydisplay() se tilda el programa, pero si pongo un MsgBox(), NO SE TILDA PARA NADA, LE DOY EN ACEPTAR EL PROGRAMA SIGUE LO MAS BIEN. Lo de _Arraydisplay() lo puse para probar, pero no lo necesito para nada, lo pregunte, solo por el echo que se me tildaba todo.
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Capturar index item de ListView

Mensaje por Ximorro »

Gracias por las gracias, es reconfortante saber que el esfuerzo tiene su utilidad.

Ojo, ¡¡MsgBox es tan malo como _ArrayDisplay!!. Vuelve a leer lo que te pongo de la ayuda de GUIRegisterMsg, ellos como ejemplo ponen precisamente MsgBox, ¡así que tampoco!, ¡no vale ninguna función o comando bloqueante!.
Te están diciendo que el comportamiento es indefinido y puede llevar a problemas inesperados, a veces irá y a veces no.
Hombre, si te parece obvio que falle con _ArrayDisplay también debería saltarte la alarma con MsgBox, ¡es justo lo que usan como ejemplo para advertirte! :smt005

Como mucho para hacer pruebas usa ConsoleWrite para escribir en la consola.
Si en producción tienes que sacar eso al usuario y no vale la consola o sacar los datos a un archivo tienes un problema... por ahora se me ocurre hacer una ejecución diferida usando una función Adlib. Se ejecuta por ejemplo 200ms después y así la función del mensaje ya habrá finalizado.
Si a alguien se le ocurre una manera más elegante que lo diga...
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
avechuche
Hacker del Foro
Mensajes: 188
Registrado: 13 Ago 2009, 09:53

Re: Capturar index item de ListView

Mensaje por avechuche »

Mas gracias todavia (Esperame que estoy con el otro code de la otra pregunta :smt021 :smt021 :smt021 :smt021 :smt021 :smt021 )

Si vi en la ayuda dice lo mismo, pero hasta ahora con MsgBox anda, no lo necesito, lo puse para (en realidad no me acuerdo para que lo puse) pero cuando ejecute el code con arraydisplay se fue todo al carajo, esto me paso en otro programa q tengo, ahora si el porque me pasaba que se me tildaba el programa :) Gracias de nuevo!
Responder