Está en la página 1de 8

Especial Docking

Meter un formulario dentro de un control Picture

Para poder acoplarlo a otros controles de un formulario.


También se explica cómo meter otra aplicación "dentro" del Picture,
(en el ejemplo se usa el bloc de notas)

Publicado el 25/Ene/2004
Revisión del 26/May/2004

En este ejemplo te voy a mostrar cómo hacer que un formulario se pueda


"meter" en un control PictureBox, con idea de poder simular
acoplamiento de formularios con otros controles, es decir, tener un
formulario con varios controles, por ejemplo un ToolBar, StatusBar, un
TreeView, etc. y en otro de los controles tener un formulario.
De paso veremos cómo hacer que se pueda cambiar el tamaño de dos de
esos controles (los que están en el centro del formulario) mediante
una barra de división (Split). Aunque esto último está en otra
página/artículo, sigue este link para verlo.
Normalmente tendremos un formulario principal, el cual puede tener un
menú principal y también en la parte superior un ToolBar. Por otro
lado, en la parte inferior también tendremos un StatusBar. En el
centro, (en la parte principal del formulario), tendremos dos
"paneles", uno a la izquierda y otro a la derecha. En el panel
izquierdo podríamos insertar un control al estilo del Outlook con una
serie de botones de opciones, etc. y en el panel derecho podríamos
tener el contenido de otro formulario de nuestra aplicación.
Todo esto son "deseos", ya que en el ejemplo que te voy a mostrar,
todos estos "posibles" controles serán del tipo PictureBox, aunque
realmente el único que "debería" ser un PictureBox es el panel de la
derecha, el que contendrá el "otro" formulario. Pero, para no
complicar demasiado el ejemplo, he preferido dejarlos todos como
controles Picture. Sigue las "recomendaciones" de los comentarios del
ejemplo y verás que te resultará fácil usar otros controles.

Como te decía, el ejemplo tiene dos "trucos".


El primero es: incrustar (o meter) un formulario dentro de un control
de tipo Picture.
Para lograr esto, usaremos una (realmente varias) función del API de
Windows: SetParent.
De forma simple te diré los pasos que habría que seguir:
Tendremos dos funciones (procedimientos) que se encargarán de meter el
formulario dentro del control y otro que ajustará el tamaño del
formulario al que tenga dicho control.

Este es el código de esos dos procedimientos, los cuales estarán


declarados en el mismo formulario principal, el que hará de
contenedor:

' Mostrar el formulario indicado, dentro de picDock


Private Sub dockForm(ByVal formhWnd As Long, _

1
ByVal picDock As PictureBox, _
Optional ByVal ajustar As Boolean
= True)
' Hacer el formulario indicado, un hijo del
picDock
' Si Ajustar es True, se ajustará al tamaño del
contenedor,
' si Ajustar es False, se quedará con el tamaño
actual.
Call SetParent(formhWnd, picDock.hWnd)
posDockForm formhWnd, picDock, ajustar
Call ShowWindow(formhWnd, NORMAL_eSW)
End Sub

' Posicionar el formulario indicado dentro de picDock


Private Sub posDockForm(ByVal formhWnd As Long, _
ByVal picDock As PictureBox, _
Optional ByVal ajustar As
Boolean = True)
' Posicionar el formulario indicado en las
coordenadas del picDock
' Si Ajustar es True, se ajustará al tamaño del
contenedor,
' si Ajustar es False, se quedará con el tamaño
actual.
Dim nWidth As Long, nHeight As Long
Dim wndPl As WINDOWPLACEMENT
'
If ajustar Then
nWidth = picDock.ScaleWidth \
Screen.TwipsPerPixelX
nHeight = picDock.ScaleHeight \
Screen.TwipsPerPixelY
Else
' el tamaño del formulario que se va a
posicionar
Call GetWindowPlacement(formhWnd, wndPl)
With wndPl.rcNormalPosition
nWidth = .Right - .Left
nHeight = .Bottom - .Top
End With
End If

2
Call MoveWindow(formhWnd, 0, 0, nWidth, nHeight,
True)
End Sub

Para usar estos procedimientos necesitaremos unas declaraciones


de funciones del API de Windows, así como unos tipos definidos:

'-----------------------------------------------------
-------------------------
' APIS para incluir las ventanas en un PictureBox
'-----------------------------------------------------
-------------------------
'
' Para hacer ventanas hijas
Private Declare Function SetParent Lib "user32" _
(ByVal hWndChild As Long, ByVal hWndNewParent As
Long) As Long
'
' Para mostrar una ventana según el handle (hwnd)
' ShowWindow() Commands
Private Enum eShowWindow
HIDE_eSW = 0&
SHOWNORMAL_eSW = 1&
NORMAL_eSW = 1&
SHOWMINIMIZED_eSW = 2&
SHOWMAXIMIZED_eSW = 3&
MAXIMIZE_eSW = 3&
SHOWNOACTIVATE_eSW = 4&
SHOW_eSW = 5&
MINIMIZE_eSW = 6&
SHOWMINNOACTIVE_eSW = 7&
SHOWNA_eSW = 8&
RESTORE_eSW = 9&
SHOWDEFAULT_eSW = 10&
MAX_eSW = 10&
End Enum

Private Declare Function ShowWindow Lib "user32" _


(ByVal hWnd As Long, ByVal nCmdShow As
eShowWindow) As Long
'

3
' Para posicionar una ventana según su hWnd
Private Declare Function MoveWindow Lib "user32" _
(ByVal hWnd As Long, ByVal x As Long, ByVal y As
Long, _
ByVal nWidth As Long, ByVal nHeight As Long, ByVal
bRepaint As Long) As Long
'
' Para cambiar el tamaño de una ventana y asignar los
valores máximos y mínimos del tamaño
Private Type POINTAPI
x As Long
y As Long
End Type
Private Type RECTAPI
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type WINDOWPLACEMENT
Length As Long
Flags As Long
ShowCmd As Long
ptMinPosition As POINTAPI
ptMaxPosition As POINTAPI
rcNormalPosition As RECTAPI
End Type
Private Declare Function GetWindowPlacement Lib
"user32" _
(ByVal hWnd As Long, ByRef lpwndpl As
WINDOWPLACEMENT) As Long

Ahora, simplemente haremos que el formulario se "meta" en el


contenedor y que al cambiar el tamaño del formulario, también se
cambie el tamaño del formulario "incrustado".
En el siguiente código se supone que el formulario que queremos
mostrar se llama "Form2" y que el control que contendrá dicho
formulario se llama Picture1.
También tendremos un botón que se usará para mostrar dicho
formulario.
Para que se vea el "efecto", tendremos a la izquierda un segundo
control, en este ejemplo es otro PictureBox, pero, como te
comentaba antes, puede ser cualquier otro control que queramos
tener acoplado a la parte izquierda del formulario. En este caso
ese control se llama picIzq y haremos que se acople a la
izquierda, asignando a la propiedad Align el valor vbAlignLeft.

4
Private Sub cmdMostrarForm2_Click()
'
' Asignar el Tag del formulario para saber que
está incluido en el Picture
Form2.Tag = valorDock
'
dockForm Form2.hWnd, Picture1, True
End Sub

Private Sub Form_Resize()


' ajustar el tamaño del Picture al del formulario
' sólo si no está minimizado
If WindowState <> vbMinimized Then
' ajustar el Picture a todo el formulario
Picture1.Move picIzq.Width, 0, ScaleWidth -
picIzq.Width, ScaleHeight
End If
End Sub

Private Sub Picture1_Resize()


' sólo si no está minimizado
If WindowState <> vbMinimized Then
' posicionar el botón en el centro
With cmdMostrarForm2
.Left = (Picture1.ScaleWidth - .Width) \ 2
.Top = (Picture1.ScaleHeight - .Height) \
2
End With
'
Dim oForm As Form
'
For Each oForm In Forms
' El tag del formulario incluido en el
picture tendrá el Tag asignado
' con el valor "valorDock"
If CStr(oForm.Tag) = valorDock Then
posDockForm oForm.hWnd, Picture1
End If
Next
End If
End Sub

5
En la parte de declaraciones del formulario tendremos una
constante llamada valorDock que simplemente nos servirá para
saber si un formulario está o no incluido dentro del picture.
Cuando queramos "meter" un formulario en el picture, asignaremos
esa constante a la propiedad Tag y seguidamente llamaremos al
procedimiento dockForm indicándole el formulario que queremos
meter, además del control en el que queremos que se meta.

Cuando cambia el tamaño del formulario, el Picture1 se ajusta a


ese nuevo tamaño. En este código sólo tenemos en cuenta que hay
otro control a la izquierda, pero no arriba ni abajo, en caso de
que tengamos otros controles arriba y/o abajo, tendremos que
tener en cuenta esos controles a la hora de posicionar y dar
tamaño al Picture1.

En el evento Resize del Picture1 se centra el botón y


posteriormente recorremos todos los formularios que tenemos en
la aplicación para comprobar si hay alguno que tenga ese valor
"mágico" que indica que el formulario debe estar dentro del
Picture. En caso de que así sea, llamamos al procedimiento
posDockForm para que ajuste el tamaño y posición del formulario
"incrustado".

En las siguientes capturas, puedes ver el formulario principal


sin y con otro formulario dentro.

El formulario "normal"

6
El formulario con el otro formulario "incrustado"

Y eso es todo.

Para saber cómo agregar una barra que te permita cambiar el


tamaño de los dos paneles, échale un vistazo a este otro
ejemplo.

Nos vemos.
Guillermo

Pulsa aquí si quieres bajarte el código con el proyecto


completo: dockVB6.zip 3.74 KB

En el código de completo se muestra cómo posicionar el botón


Cerrar del segundo formulario en la parte inferior derecha.

Si quieres ver funcionando este ejemplo y el de cambiar el


tamaño de los paneles centrales, puedes bajarte el código
completo, en el que se incluye un ejemplo de cómo poner
cualquier ventana (de la que sabemos el caption o título) en un
picture: DockSplitVB6.zip 5.42 KB

Nota del 26/May/2004:


En el código de ejemplo tengo puesto como programa a incluir, el
bloc de notas, pero como mi sistema operativo está en inglés,
utilizo "Untitled - Notepad", así que tendrás que cambiar el
nombre al que corresponda en español, que me imagino que es:
"Sin título - Bloc de notas".
En el zip ya está incluido un comentario en el sitio que hay que
hacer el cambio.
Este "bug" (si es que se le puede llamar así), ya me lo
reportaron hace tiempo, pero ahora no recuerdo quién fue...
cuando encuentre el mensaje, lo pondré...
Gracias a los que reportáis los fallos que de vez en cuando
cometo... ¡que yo no soy perfecto!

7
El formulario con el Notepad dentro de un picture.