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
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)
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
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
|
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
|