HowTo: Crear una pantalla de inicio (splash screen)
Nota: Otro post en respuesta a una pregunta bastante habitual en los foros MSDN: ¿Cómo crear una pantalla de inicio para mi aplicación?
He creado un pequeño proyecto de ejemplo, que pueda servir como plantilla base para que cada uno se lo personalice para su aplicación. Este proyecto tiene lo básico: Un formulario sin bordes con una imagen, una barra de progreso, una etiqueta para el título, otra para ir mostrando mensajes, y un botón por si se desea cancelar la carga del programa (al estilo Office 2010).
Él proyecto es muy sencillo y lo podéis descargar desde aquí:
La pantalla de inicio utiliza un thread para mostrar los diferentes mensajes al cargar, ya que así no se bloquea la aplicación (y la barra de progreso). Esto es así porque en el proyecto de ejemplo, al cargar la pantalla de inicio se lanza un segundo hilo que llama a un método ‘initApplication’, y desde éste método simulamos varios procesos largos (en realidad de un segundo cada uno), y cada vez que se inicia uno de ellos hay que cambiar el mensaje:
public void initApplication()
{
Thread.Sleep(DEFAULT_TIME);
this.Invoke((MethodInvoker)(() => setMessage("Searching for updates...")));
Thread.Sleep(DEFAULT_TIME);
this.Invoke((MethodInvoker)(() => setMessage("Connectiong to database...")));
Thread.Sleep(DEFAULT_TIME);
this.Invoke((MethodInvoker)(() => setMessage("Connectiong to webservices...")));
Thread.Sleep(DEFAULT_TIME);
this.Invoke((MethodInvoker)(() => setMessage("Loading settings...")));
Thread.Sleep(DEFAULT_TIME);
this.Invoke((MethodInvoker)(() => setMessage("Loading user preferences...")));
Thread.Sleep(DEFAULT_TIME);
this.Invoke((MethodInvoker)(() => setMessage("Starting application...")));
Thread.Sleep(DEFAULT_TIME);
if (this.InvokeRequired) this.Invoke(new Action(finishProcess));
}
Recordar que desde un hilo que no sea el hilo principal, en .NET no se puede actualizar la interfaz de usuario directamente. En su lugar debemos usar el método Invoke. En el ejemplo anterior llamamos a un método ‘setMessage’ que se encarga de mostrar el texto en la etiqueta correspondiente. Para poder llamar a este método mediante Invoke tenemos dos opciones: Podemos usar un MethodInvoker o un Action, en nuestro caso usaremos el primero, ya que un Action se usa cuando no hay paso de parámetros, y este método precisa de un parámetro con el mensaje a mostrar:
public void setMessage(string msg)
{
messageLabel.Text = msg;
}
Una vez finalizado el proceso de carga, se cierra el formulario y se devuelve un DialogResult = Ok. Por otro lado si en cualquier momento de la carga el usuario ha pulsado el botón ‘close’, se hace lo mismo pero devolviendo un DialogResult = Cancel:
private void finishProcess()
{
this.DialogResult = System.Windows.Forms.DialogResult.OK;
this.Close();
}
void closeButton_Click(object sender, EventArgs e)
{
this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.Close();
}
Como veis el proyecto es muy sencillo, sólo debéis recordar un detalle importante: En una aplicación WinForms el punto de entrada a la misma se define en el método estático Main del Program.cs, y aquí hay una línea que inicializa el formulario inicial de nuestra aplicación:
Application.Run(new fMain());
Lo primero que solemos pensar es que aquí deberíamos lanzar el formulario fSplashScreen, y al cerrarlo mostrar el formulario principal, verdad? Pues no, no podemos hacer eso. El motivo no es otro que este formulario inicial va a definir el ciclo de vida de nuestra aplicación, y si lo cerramos, cerramos la aplicación. Ya se que en VB puede cambiarse este comportamiento, pero entre nosotros… hacerlo siempre me ha parecido una chapuza 🙂
Así pues, aquí lanzaremos el formulario principal, y éste, al cargarse (mientras todavía no es visible) lanzará la pantalla de inicio de forma modal y esperará el valor de retorno. Si al cerrarse la pantalla de bienvenida el valor de retorno es Ok, continúa la carga y muestra el formulario principal, en caso contrario cierra el formulario principal y con por ende la aplicación:
void fMain_Load(object sender, EventArgs e)
{
showSplashScreen();
}
private void showSplashScreen()
{
using (fSplashScreen fsplash = new fSplashScreen())
{
if (fsplash.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) this.Close();
}
}
Espero que sirva como ejemplo a todos aquellos que desean tener una pantalla de inicio para sus aplicaciones. Un saludo!
Andorra, Noviembre 2010
17 Responsesso far
En mi caso mi aplicacion verifica las actualizaciones desde un servidor remoto (esta desarrollada en C#).
Como podria hacer para que realmente refleje el tiempo de busqueda de actualizacion (al arrancar sale el clasico cuadro de ‘Verificando requisitos’, seria bueno poder omitir ese cuadro con algo mucho mas elaborado).
Gracias.
Por si no me explico, como saber en q momento debo cambiar el label de accion actual de acuedo a la accion que se esta realizando.
Genial!. Muy interesante gracias!.
Máquina!!!, que grande eres, me viene de perlas para un par de proyectos en los que estoy metido, te pondré en los créditos con letras muy grandes!!!
@Jose: No te entiendo muy bien. No se si te refieres a una aplicación publicada con ClickOnce o a un formulario que tu mismo has creado. Si es el primer caso, no hay nada que puedas hacer, ClickOnce funciona ‘as is’, o sea, que no se puede cambiar. Si es el segundo caso, puedes usar el proyecto de ejemplo como base para tu propia ventana de actulización. No veo que problema puedes tener 🙂
@Carlos, @Oscar: De nada! Me alegro que os haya gustado. Un saludo!
Gracias @Lluis Franco, si la genere con click once (el generador por default de VS si no me equivoco).
Para poder hacer uso del Splash entonces lo tengo que generar con alguna otra herramienta?
(Disculpa tanta pregunta pero soy mas dado a desarrollar en PHP/Java y ahora q estoy desarrollando para escritorio me enredo un poco 🙁 )
Hola de nuevo,
ClickOnce es un sistema de publicación muy sencillito y no permite personalizar apenas nada. Si deseas más control, por ejemplo versionado online y otras cosas, lo mejor es que lo hagas tu mismo ‘a mano’. Lo malo es que se complica más, ya que debes encargarte tu mismo de lanzar otra aplicación creada por tí, que verifique actualizaciones, las descargue y luego inicie tu aplicación. Un curro vamos…
Ok, muchas gracias.
Por ultimo, tendras algo de bibliografia respecto al tema?}
Suena interesante esa parte. (imagino algo como GIT o SVN)
En que parte del codigo es cuando se cambia a la ventana principal? Veras mi intencion es que al hacer el cambio a la pantalla principal esta cambie a tamaño maximizado, intente hacerlo desde la ventana de propiedades del diseñador pero entonces al correr la aplicacion se muestra la pantalla principal maximizada y la pantalla de carga delante de la principal y se cicla la pantalla de carga. Despues intente usar la instruccion: this.WindowState=FormWindowState.Maximized; dentro de void fMain_Load y ahora si me muestra primero la pantalla de carga y al finalizar me muestra la pantalla maximizada el problema viene si doi clic en el boton de close de la pantalla de carga pues me manda este error:
No se controló ObejectDisposedException
-No se puede obtener acceso al objeto eliminado.
Nombre del objeto: ‘fMain’
Sugerencias para solucion de problemas. Asegurese de que no ha liberado el recurso antes de intentar utilizarlo. Este problema se soluciona si kito la instruccion this.WindowState = FormWindowState.Maximized; pero la pantalla principal aparece sin maximizar, puedes ayudarme con esto?
Ya logre solucionar el problema y que la aplicacion se maximize al terminar la pantalla de carga. Lo que hice fue que en la parte de private void showSplashScreen(){}
en lugar de usar un valor de retorno cancel use el OK y en lugar de cerrar maximizar y en el boton close de la pantalla de carga en lugar de la comparacion dialog result use Application.Exit();
con estos cambios hace todo lo que queria; maximizar la pantalla fMain al finalizar la pantalla de carga, cerrar toda la aplicacion al darle clic al boton close de la pantalla de carga sin que me mande el error que arriba puse.
Buena Aplicaion Gracias por el aporte!
Que la programacion os acompañe!
Encontre otra solucion! añadi un else. El codigo quedo asi:
private void showSplashScreen()
{
using (fSplashScreen fsplash = new fSplashScreen())
{
if (fsplash.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) this.Close();
else this.WindowState = FormWindowState.Maximized;
}
Saludos.!
oye una duda intente abrir el archivo kn el visual basic expres 2010 y me dice k no es compatible esta version me podrias ayudar diciendo me k version utilizaste me estoy iniciando en esto y la verdad es interesante pero es komplicado entenderlo …gracias
aparece el mensaje de error «la solicitud de proyecto no está instalada. Compruebe que está instalada la aplicación para el tipo de proyecto ()».
@flako, Si se puede abrir el proyecto con VSXpress!
Genial bro grax !!! justo lo que necesitaba 5 estrellas
Esta muy bueno Luis Franco, agradecerte por el aporte.
Aprovechando del conocimiento que tienes, pedirte agregar un login de usuarios con base de datos ok.
Gracias nuevamente por los aportes que realizas y el tiempo que te tomas en hacerlos. Bye
HowTo: Crear una pantalla de inicio (splash screen) – Lluís Franco on Geeks.ms