Crear un protector de pantalla con C#

Hace ya algún tiempo, en una de las empresas en las que colaboro, se me ocurrió la idea de hacer un protector de pantalla un poco personalizado. Como el tema del diseño no es que sea mi fuerte, opté por hacer algo sencillito y que, entre otras cosas, intentara tener la aceptación de los usuarios. Así, me marqué los siguiente objetivos:

  • Fondo negro ( ¿he dicho que el diseño no es lo mío? )
  • Movimiento
  • Sencillez

Es curioso el efecto que puede llegar a hacer un par de logotipos moviéndose por la pantalla de nuestro ordenador…así que nos ponemos manos a la obra.

¿ Qué necesito para crear un protector de pantalla?.

Nada. Sólo las herramientas que estamos usando día tras día. Igual ahora que estamos tan metidos todos en los temas de Web, el empezar un proyecto de WinForms nos da un poco de pereza, pero creo que todos hemos empezado por ahí. De hecho, un protector de pantalla tan sólo es un proyecto .EXE al cual, una vez compilado, le cambiaremos la extensión por .SCR. Vale… ya sé que un protector de pantalla debería tener una serie de opciones que el usuario podría cambiar y además se debería poder ver desde la ventana de Vista Previa de los protectores, pero estamos hablando de un protector sencillito y corporativo, de tal manera que, para simplificar, no vamos a dejar que el usuario modifique ninguna opción (Al fin y al cabo, cuando esté acabado, se lo impondremos mediante directiva de sistema, así que no hacen falta muchas opciones).

Empezamos pues, creando un proyecto WinForms, que tendrá un único formulario, al que cambiaremos las propiedades siguientes:

   1: public Form1()
   2: {
   3:     InitializeComponent();
   4:  
   5:     // Fondo negro
   6:     this.BackColor = Color.FromArgb(0, 0, 0);
   7:     // Ejecución maximizada
   8:     this.WindowState = FormWindowState.Maximized;
   9:     // Eliminamos los bordes del formulario
  10:     this.FormBorderStyle = FormBorderStyle.None;
  11:     // El formulario recibirá cualquier evento antes que sus controles
  12:     this.KeyPreview = true;
  13:     // El formulario, siempre en primer plano
  14:     this.TopLevel = true;
  15: }

Configuremos cómo cerrar el formulario

Antes de nada, intentaremos configurar el entorno para que podamos cerrar el protector. A mí siempre me han molestado los protectores de pantalla que se descargan cuando, sencillamente mueves el ratón, aunque sea por error, así que como ahora soy yo el que lo hace, lo haré a mi gusto: para descargar el protector, sólo será válida la tecla de ESC o un clic de ratón. Estas opciones son muy fáciles de modificar al gusto del consumidor.

   1: public Form1()
   2: {
   3:     ... // Código anterior
   4:     this.TopLevel = true;
   5:  
   6:     // Control de eventos
   7:     this.Click += new EventHandler(Form1_Click);
   8:     this.KeyPress += new KeyPressEventHandler(Form1_KeyPress);
   9: }
  10:  
  11: void Form1_Click(object sender, EventArgs e)
  12: { 
  13:     CierraFormulario(); 
  14: }
  15:  
  16: void Form1_KeyPress(object sender, KeyPressEventArgs e)
  17: {
  18:     if (e.KeyChar == (char)Keys.Escape)
  19:         CierraFormulario(); 
  20: }
  21:  
  22: /// <summary>
  23: /// Cierra el formulario
  24: /// </summary>
  25: private void CierraFormulario()
  26: {
  27:     this.Close();
  28: }

Vamos a rellenar el formulario

Un Timer será nuestro mejor aliado a la hora de conseguir el efecto del movimiento cada cierto tiempo, así que lo dejamos preparado para que acceda al método movimientoObjetos() cada segundo.

   1: #region Temporizador
   2:  
   3: Timer temporizador;
   4:  
   5: private void activaTemporizador()
   6: {
   7:     temporizador = new Timer();
   8:     temporizador.Tick += new EventHandler(temporizador_Tick);
   9:  
  10:     temporizador.Interval = 1000;
  11:     temporizador.Enabled = true;
  12: }
  13:  
  14: void temporizador_Tick(object sender, EventArgs e)
  15: {
  16:     movimientoObjetos();
  17: }
  18: #endregion

Ahora nos queda la parte divertida, es decir, cómo distribuir algún que otro objeto por la pantalla y que se vayan moviendo cada segundo, es decir, cada vez que sea llamado el método movimientoObjetos().

Como tenemos muy asumido que el diseño no es lo nuestro y que las coordenadas de la pantalla es una especie de película de ciencia-ficción, vamos a echar mano de un componente del namespace System.Windows.Forms, concretamente el TableLayoutPanel. Este componente tiene un método que nos solventará el problema de ir desplazando cualquier objeto. El método en sí es SetCellPosition, que permite, precisamente eso, colocar un objeto en una posición cualquiera. Lo único que deberemos mirar con anterioridad es conocer si ya existe algo en esa posición y podemos comprobarlo con otro método (GetControlFromPosition) del mismo control.

Así pues, crearemos dentro de nuestro formulario un control TableLayoutPanel que tenga un número determinado de filas y columnas y que estén distribuidos de una manera uniforme. En mi caso, he creado un ejemplo de tabla 10×10 y he añadido algún que otro ornamento (estos controles nos dan la ventaja que poder jugar con las propiedades RowSpan y ColumnSpan de los controles que añadimos en ellos, por si tenemos algún gráfico más grande).

image_thumb[12]

Por tanto, ya podemos hacer un bucle que se recorra todos los controles que hemos ido añadiendo, que aleatoriamente seleccione una celda, mire si está ocupada y, si no es así, que deje el elemento:

   1: /// <summary>
   2: /// Provoca el efecto de movimiento de los objetos en pantalla
   3: /// </summary>
   4: private void movimientoObjetos()
   5: {
   6:     int filas = tabla.RowCount;
   7:     int columnas = tabla.ColumnCount;
   8:  
   9:     Random r = new Random(System.DateTime.Now.Millisecond);
  10:     bool posicionado;
  11:  
  12:     lblReloj.Text = DateTime.Now.ToShortTimeString();
  13:  
  14:     foreach (Control ctr in tabla.Controls)
  15:     {
  16:         posicionado = false;
  17:  
  18:         while (!posicionado)
  19:         {
  20:             int posibleColumna = r.Next(columnas);
  21:             int posibleFila = r.Next(filas);
  22:  
  23:             if (tabla.GetControlFromPosition(posibleColumna, posibleFila) == null)
  24:             {
  25:                 tabla.SetCellPosition(ctr, new TableLayoutPanelCellPosition(posibleColumna, posibleFila));
  26:                 posicionado = true;
  27:             }
  28:         }
  29:     }
  30:     Application.DoEvents();
  31: }

 

Pues, en principio, ya tenemos el esqueleto de nuestro propio Protector de Pantalla. Sé que es sencillito tal cuál está, pero tiene la ventaja de poder personalizarse al gusto sin tocar casi nada de código. En la empresa, por ejemplo, añadí dos o tres logotipos que tienen por ahí del grupo y además añadí una frase aleatoria que introducen los mismos usuarios en un apartado de la intranet. Estas cosas a los jefes suelen gustarles.

¡Vale, muy bien!, pero, ¿qué pasa con el ratón?

Cierto, se me olvidaba un detalle con el que me peleé bastante rato. Si se te ocurre dirigir, desde el Form_Load un disparador al mover el ratón, te encontrarás que no llega a abrirse. Para ello, lo que hice fue lo siguiente: Guardar un punto en el que se almacena la posición del ratón, así se puede comparar con una nueva coordenada en caso de que se desplace.

   1: #region Control de ratón
   2:  
   3: private Point mouseXY;
   4: void tabla_MouseMove(object sender, MouseEventArgs e)
   5: {
   6:     Point puntoActual = new Point(e.X, e.Y);
   7:     if (!mouseXY.IsEmpty)
   8:     {
   9:         if (puntoActual != mouseXY)
  10:             CierraFormulario();
  11:  
  12:     }
  13:     mouseXY = puntoActual;
  14: }
  15: #endregion

 

Ya sólo nos queda compilarlo, cambiar la extensión de .EXE a .SCR y añadirlo a la carpeta %System%Windows para que aparezca entre el resto de protectores.

Dejo la aplicación por si alguien quiere entretenerse y modificarlo a su gusto: enlace

4 thoughts on “Crear un protector de pantalla con C#

  1. Muchas Gracias, Excelente ayuda…solo faltó agregar que con cualquier tecla que se presione del teclado, el screensaver también se cierre…pero eso es sencillo.

  2. El tiempo de latencia puede ejecutarse como con cualquier otro protector. En la empresa, cuando tuve que ponerlo, lo hice mediante gpo.

    Para lo demás creo que es mejor que cada uno use su imaginación. Cuando lo instalé en la empresa hice que apareciera aleatoriamente una frase entre las que los usuarios insertaban en la intranet…

Responder a anonymous Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *