Especial Docking Meter un formulario dentro de un control Picture Para poder acoplarlo a otros controles de un
formulario.
Publicado el 25/Ene/2004
Nota del 05/Nov/2015:
|
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, _ 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 Call MoveWindow(formhWnd, 0, 0, nWidth, nHeight, True) End SubPara 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 ' ' 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 LongAhora, 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.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 SubEn 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"
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.
GuillermoPulsa 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!
El formulario con el Notepad dentro de un picture.