Ir al contenido principal

[PB] Crear barra de botones de forma dinámica


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

Comentarios

Publicar un comentario

Si quieres comentar, criticar, aportar mas informacion o simplemente felicitar, inserta tu comentario a continuacion. Entre todos podemos hacer cosas grandes.

Entradas populares de este blog

[VB] - Generar GUID

Esta si es buena... Como se nota que VB es un lenguaje con "solera", es decir, con años pero con robustez. Pero le pasa como al abuelo Cebolleta, tiene experiencia pero para los nuevos tiempos... ains.. le falta algo. Hoy en dia no sabriamos hacer nada sin un buen GUID, sobre todo si lo que queremos es identificar de forma unica y constante algun registro, objeto u otro componente. Usando SQL podemos generar un GUID en un santiamen a traves de la instrucción NEWID() , podemos crear un nuevo GUID en .NET usando la clase GUID.. pero... como lo hacemos con Visual Basic 6? Para empezar, vamos a ver en que se compone un GUID ¿Que es un GUID? Su significado es Globally Unique Identifier, osea Identificador globalmente único. Y su misión es la de proporcionar un identificador, de forma que es practicamente imposible que existan dos iguales en el mundo. Se compone de una palabra de 4 bytes, 3 palabras de 2 bytes y una de 6 bytes. Originalmente fue una idea de Microsoft pa

[.NET] Convertir Latitud y Longitud en Grados - Minutos y segundos

Hola a todos. Esta es una función para convertir un número de posición geográfica en grados, minutos y segundos. Como algunos pocos recordarán,una posición geográfica esta definida por latitud (Norte / Sur) y longitud (Este / Oeste) teniendo como referencia para la longitud el meridiano de Greenwich (Meridiano 0) y para la latitud la linea del Ecuador (Paralelo 0). Por lo que siempre hablaremos de posición " Grados Norte ", o " Grados Este ". Ahora es cuando entra en juego las matemáticas y la trigonometría (he de admitir que me encantan :D ). El hemisferio norte o sur solo tendría 90° Norte o Sur. Por ejemplo, El polo norte está a 90° 0' 0'' N de latitud. La longitud podríamos considerar el 0° 0' 0'' (estamos en el polo norte, por lo que es un solo punto, no hay longitud). En cambio, si nos movemos alrededor de la tierra por la linea de Ecuador, la latitud será 0° 0' 0'' (ni al norte, ni al sur) pero de Este a Oeste nos m