Ir al índice de .NET Cómo... en .NET

Poner una ventana siempre encima del resto

Usando la función del API SetWindowPos

 
Publicado el 05/Dic/2006
Actualizado el 05/Dic/2006
Autor: Guillermo 'guille' Som

En este artículo te explico cómo posicionar una ventana siempre encima del resto. Para conseguirlo usaremos la función SetWindowPos del API de Windows. Y como de costumbre, con código para VB como para C#.


Introducción:

El siguiente código te permitirá posicionar una ventana siempre encima del resto.
Para conseguirlo usaremos la función SetWindowPos del API de Windows.

Seguramente pensarás que no hace falta usar ninguna función del API ya que en .NET se puede conseguir "casi" lo mismo usando el método BringToFront, pero debo decirte que ese método sirve para el resto de ventanas de la aplicación e incluso de Windows, pero en cuanto pulsas en otra venta, la nuestra se quedará por detrás, mientras que usando la función del API SetWindowPos, lograremos que siempre esté encima de las demás ventanas incluso si nuestra aplicación no es la que tiene el foco actualmente.

Advertencia y recomendación:
Decirte que... NO es buena práctica hacer que nuestra ventana esté siempre encima, salvo que en casos muy concretos necesitemos esa peculiaridad.

 

Para conseguir lo que necesitamos además de la declaración de la función del API, debemos usar una serie de constantes para que le indiquen a dicha función de que es lo que queremos hacer.

En el código de ejemplo (más abajo está para Visual Basic y para C#) lo que he hecho es crear dos métodos, uno de ellos pondrá la ventana encima del resto y la otra la posicionará debajo, o lo que es lo mismo, conseguiremos que ya no esté siempre encima.

 

La aplicación de ejemplo

En la figura 1 tienes una captura del formulario principal, el segundo formulario puede contener lo que quieras, solo es necesario que se llame Form2 que es como lo llamo en el ejemplo... si le cambias el nombre, acuérdate de cambiarlo en el resto del código... sí, ya sé que lo sabes, pero... por si acaso...

Figura 1. El formulario principal en modo diseño
Figura 1. El formulario principal en modo diseño

En la aplicación de ejemplo tendremos dos formularios, al pulsar en el botón "Siempre encima" conseguiremos que el segundo formulario siempre esté encima, incluso si nos cambiamos a otra aplicación.
Cuando pulsamos en el botón "No poner siempre encima" dejaremos el formulario como suelen estar, es decir, en cuanto pulsemos en otra ventana (de la misma o de otra aplicación) ésta se pondrá encima del formulario (si es que la posición permite que se pueda, claro).

En la figura 2 puedes ver como quedaría el segundo formulario encima del primero aunque el principal sea el que tiene el foco. Por supuesto, cualquier otra ventana de cualquier otra aplicación quedará por detrás del formulario Form2.

Figura 2. El programa en ejecución (en un Windows Vista)
Figura 2. El programa en ejecución (en un Windows Vista)

 

Para crear la aplicación de ejemplo, crea un proyecto, en el formulario que se añade de forma predeterminada, añade los controles para que tenga el aspecto de la figura 1, añade otro formulario (déjale el mismo nombre: Form2) y añade una clase.
Añade el código que te muestro según el lenguaje y a probarlo...
En el caso de C# debes asociar el código con los correspondientes eventos.

 

Espero que te sea de utilidad.

Nos vemos.
Guillermo

 


Código para Visual Basic.NET (VB.NET)El código para VB .NET (cualquier versión)

 

La clase con las funciones del API

Imports Microsoft.VisualBasic
Imports System

' Para DllImport
Imports System.Runtime.InteropServices

Namespace elGuille.Util

    Public Class WinAPI
        ' Constantes para SetWindowsPos
        '   Valores de wFlags
        Const SWP_NOSIZE As Integer = &H1
        Const SWP_NOMOVE As Integer = &H2
        Const SWP_NOACTIVATE As Integer = &H10
        Const wFlags As Integer = SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE
        '   Valores de hwndInsertAfter
        Const HWND_TOPMOST As Integer = -1
        Const HWND_NOTOPMOST As Integer = -2
        '
        ''' <summary>
        ''' Para mantener la ventana siempre visible
        ''' </summary>
        ''' <remarks>No utilizamos el valor devuelto</remarks>
        <DllImport("user32.DLL")> _
        Private Shared Sub SetWindowPos( _
            ByVal hWnd As Integer, ByVal hWndInsertAfter As Integer, _
            ByVal X As Integer, ByVal Y As Integer, _
            ByVal cx As Integer, ByVal cy As Integer, _
            ByVal wFlags As Integer)
        End Sub

        Public Shared Sub SiempreEncima(ByVal handle As Integer)
            SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, wFlags)
        End Sub

        Public Shared Sub NoSiempreEncima(ByVal handle As Integer)
            SetWindowPos(handle, HWND_NOTOPMOST, 0, 0, 0, 0, wFlags)
        End Sub
    End Class

End Namespace

 

El código de la aplicación de ejemplo

Imports siempreEncima_vb.elGuille.Util

Public Class Form1
    Private frm2 As Form2

    Private Sub Form1_Load( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles MyBase.Load
        Me.btnEncima.Enabled = False
        Me.btnNoEncima.Enabled = False
    End Sub

    Private Sub btnMostrar_Click( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles btnMostrar.Click
        If frm2 Is Nothing OrElse frm2.IsDisposed Then
            frm2 = New Form2
        End If
        frm2.Show()
        Me.btnEncima.Enabled = True
        Me.btnNoEncima.Enabled = True
    End Sub

    Private Sub btnEncima_Click( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles btnEncima.Click
        If frm2 Is Nothing OrElse frm2.IsDisposed Then
            frm2 = New Form2
            frm2.Show()
        End If
        WinAPI.SiempreEncima(frm2.Handle.ToInt32)
    End Sub

    Private Sub btnNoEncima_Click( _
                ByVal sender As System.Object, _
                ByVal e As System.EventArgs) _
                Handles btnNoEncima.Click
        If frm2 Is Nothing OrElse frm2.IsDisposed Then
            frm2 = New Form2
            frm2.Show()
        End If
        WinAPI.NoSiempreEncima(frm2.Handle.ToInt32)
    End Sub
End Class

 

 


Código para C Sharp (C#)El código para C# (cualquier versión)

 

La clase con las declaraciones del API

using System;

// Para DllImport
using System.Runtime.InteropServices;

namespace siempreEncima_cs
{
    namespace elGuille.Util
    {
        public class WinAPI
        {
            // Constantes para SetWindowsPos
            //   Valores de wFlags
            const int SWP_NOSIZE = 0x1;
            const int SWP_NOMOVE = 0x2;
            const int SWP_NOACTIVATE = 0x10;
            const int wFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE;
            //   Valores de hwndInsertAfter
            const int HWND_TOPMOST = -1;
            const int HWND_NOTOPMOST = -2;
            //
            /// <summary>
            /// Para mantener la ventana siempre visible
            /// </summary>
            /// <remarks>No utilizamos el valor devuelto</remarks>
            [DllImport("user32.DLL")]
            private extern static void SetWindowPos(
                int hWnd, int hWndInsertAfter, 
                int X, int Y, 
                int cx, int cy, 
                int wFlags);

            public static void SiempreEncima(int handle)
            {
                SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, wFlags);
            }

            public static void NoSiempreEncima(int handle)
            {
                SetWindowPos(handle, HWND_NOTOPMOST, 0, 0, 0, 0, wFlags);
            }
        }
    }
}

 

El código del formulario principal

using System;
using System.Drawing;
using System.Windows.Forms;

using siempreEncima_cs.elGuille.Util;

namespace siempreEncima_cs
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Form2 frm2;

        private void Form1_Load(Object sender, EventArgs e)
        {
            this.btnEncima.Enabled = false;
            this.btnNoEncima.Enabled = false;
        }

        private void btnMostrar_Click(Object sender, EventArgs e)
        {
            if (frm2 == null || frm2.IsDisposed)
            {
                frm2 = new Form2();
            }
            frm2.Show();
            this.btnEncima.Enabled = true;
            this.btnNoEncima.Enabled = true;
        }

        private void btnEncima_Click(Object sender, EventArgs e)
        {
            if (frm2 == null || frm2.IsDisposed)
            {
                frm2 = new Form2();
                frm2.Show();
            }
            WinAPI.SiempreEncima(frm2.Handle.ToInt32());
        }

        private void btnNoEncima_Click(Object sender, EventArgs e)
        {
            if (frm2 == null || frm2.IsDisposed)
            {
                frm2 = new Form2();
                frm2.Show();
            }
            WinAPI.NoSiempreEncima(frm2.Handle.ToInt32());
        }  
    }
}

 

 


Espacios de nombres usados en el código de este artículo:

System.Runtime.InteropServices
 


Código de ejemplo (comprimido):

 

No hay fichero comprimido con el código

 


Ir al índice principal de el Guille

Valid XHTML 1.0 Transitional ¡CSS Válido!