
Hola de nuevo... hoy, Power Builder, esta vez en PB 10.5
La idea de tener una barra de botones de forma dinámica me hizo idear el siguiente código.
Podemos crear un objeto de forma dinámica directamente en nuestra window usando el comando OpenUserOject.
this.OpenUserObject(uo_boton)
Esta instrucción en la ventana, pondrá un objeto de usuario llamado uo_boton en la ventana, luego podemos invocar las propiedades para poner el botón en el sitio que queremos (X=23, Y=24, etc..)
Pero el problema era que lo que tenia era un objeto de usuario y quería poner esos botones dentro del objeto de usuario... grave problema.
La solución la dio nuestro amigo Microsoft, porque nos facilita las cosas usando los manejadores de los objetos.
Function ulong SetParent (ulong hWndChild, ulong hWndNewParent) Library "USER32.DLL"
Esta API cambia el manejador padre de un objeto dado, es decir, si tengo el Handle del objeto de usuario y el Handle del boton, puedo decirle al botón, que en lugar de tener como padre el Handle del Window, usa el Handle del objeto de usuario.
Y con todo esto, que puedo sacar de provecho?
Pues podemos crear una barra de botones de forma totalmente dinámica, pudiendo poner las opciones que queremos según el usuario, la ventana, etc... estando los parámetros en una base de datos, fichero XML, o cualquier otra forma.
Primero me he creado un objeto del tipo picturebutton, y lo he llamado uo_button, luego le pondremos código al mismo.
Luego he creado un objeto de usuario visible llamado uo_buttonbar, el cual lo voy a considerar el contenedor de botones.
Le añado las variables de instancia de valores por defecto de los botones, la ultima posición, el array de los botones y los manejadores de los mismos.
uo_button iPb_Button[]
Integer iIndex[], iLastIndex
window iw_win
Long iHandle[]
Integer iLastX = 4, iLastY = 4
Constant Integer HEIGHT_BUTTON = 88
Constant Integer WIDTH_BUTTON = 110
Al constructor, le indicaremos el handle del parent, osea, la ventana.
iw_win = Parent
y nuestro contenedor, tendrá un método para añadir el botón de forma dinámica.
//////////////////////////////////////////////////
// Objeto: uo_buttonbar
//
// Función: of_add
//
// Argumentos: value integer ai_id
// value string as_picture
// value string as_tag
// value boolean ab_initialstate
//
// Retorno: integer
//
// Descripción: Añade un botón en la barra y
// recalcula la siguiente posición
//
//////////////////////////////////////////////////
iLastIndex = UpperBound(ipb_button)
iLastIndex ++
ipb_button[iLastIndex] = Create uo_button
ipb_button[iLastIndex].visible = True
// Después de crear el PictureButton lo ponemos sobre la
// ventana donde esta el objeto visual de usuario.
iw_win.openUserObject(ipb_button[iLastIndex])
// Obtenemos el Handle del PictureButton.
iHandle[iLastIndex] = Handle(ipb_button[iLastIndex])
// Cambiamos el Padre del PictureButton asignandole ahora
// como tal al uo_barra_botoenes
SetParent( iHandle[iLastIndex], Handle(This))
// Aquí continuamos con el código normal... sin
// olvidarse de hacerlo visible.
ipb_button[iLastIndex].x = iLastX
ipb_button[iLastIndex].y = iLastY
ipb_button[iLastIndex].height = HEIGHT_BUTTON
ipb_button[iLastIndex].Width = WIDTH_BUTTON
ipb_button[iLastIndex].PictureName = as_picture
ipb_button[iLastIndex].visible = True
if as_tip <> "" then
ipb_button[iLastIndex].powertiptext = as_tip
end if
ipb_button[iLastIndex].enabled = ab_InitialState
iLastX = iLastX + HEIGHT_BUTTON
iIndex[iLastIndex] = ai_Id
Return 1
mmmmm, interesante código.. vamos a ver que hace...
Esto crea un array con los botones, y usando el SetParent, lo insertamos en el contenedor, porque el método, OpenUserObject lo inserta en la ventana (iw_win osea, el parent) pero lo movemos al contenedir (Handler(this)). Luego, lo posicionamos con respecto AL CONTENEDOR (x,y,heigh,width)
Luego calcula cual es la siguiente posición del próximo botón.
Pero, al ser un botón dinámico, como controlo cuando se ha pulsado el botón?
Para ello, vamos a controlar el handler del contenedor cuando creamos el botón.
Al objeto uo_boton, añadimos variable de instancia
ULong iul_Handle
Aquí, almacenaremos el handle del contenedor cuando lo estamos creando, creamos una función llamada sethandle (unsignedlong aul_handle)
iul_Handle = aul_Handle
y al evento click, le añadimos el siguiente código.
Send(iul_Handle, 1024, Handle(this), 0)
Esto hace que invoquemos al contenedor, llamando al evento 1024 haciendo referencia al manejador del botón...
Lo cualo????
El evento 1024 en el contenedor es el evento definido por el usuario en power builder, asi que el contenedor vamos a crear un nuevo evento llamado ue_buttonclick
lo definimos del tipo pbm_custom01
a que a veces te habías preguntado para que servían estos Event ID, pues el 1024 para custom01, el 1025 para custom02, etc...
En nuestro caso, vamos a recorrer el array de handler, y cuando coincida con nuestro botón, recogemos el ID que hemos añadido antes.
Recordad, en el código de of_Add, hay que añadir el código para indicarle al botón cual es el handler del contenedor.
// Obtenemos el Handle del PictureButton.
iHandle[iLastIndex] = Handle(ipb_button[iLastIndex])
ipb_button[iLastIndex].SetHandle(Handle(This))
y nuestro evento ue_buttonclick, el código para controlar el evento click de los botones.
Integer li_For, li_Ret, li_Total
Long lHandle
// Buscamos quien tiene el Handle
li_Total = UpperBound(iHandle)
For li_For = 1 TO li_Total
if wparam = iHandle[li_for] then
Messagebox("Pulsado", "Ha pulsado el botón con el ID = " + String(iIndex[li_for]) )
Return 1
Exit
End if
Next
Return 0
Interesante, no te parece?
Ya sabes, el código de ejemplo lo tienes en el siguiente enlace. El código está en Power Builder 10.5, si tienes una versión anterior, puedes usar el segundo enlace que tiene los componentes exportados.
ButtonBar.zip (Librearia PBL, PBT y PBW)
ButtonBar_source.zip (Ficheros sru, sra y srw)
Si te ha gustado este truco me gustaría saberlo. :D
Amigo excelente material.
ResponderEliminar