'2010/08'에 해당되는 글 1건

  1. BackgroundWorker를 이용한 스플래시윈도우 (3) 2010.08.24
.Net의 Windows Forms 애플리케이션은 System.Windows.Forms.Application.Run() 정적 메서드가 메인루프를 도는 구조인데, 기본적으로 싱글스레드이므로 Application.Run은 한 번만 호출되기 마련이다. 하지만 백그라운드 워커를 사용해 간단하게 스레드를 만들고, 이 스레드에서 Application.Run으로 다른 폼을 실행하면 동시에 두 개의 폼을 띄울 수 있다. 이 방법을 통해 애플리케이션의 스플래시 윈도우, 통칭 로딩화면을 보여주는 것이 가능하다. 샘플 코드는 C#이지만 .Net지원 언어라면 유사하게 구현할 수 있을 것이다.

다음 코드는 이미 MainForm과 SplashForm이라는 두 개의 폼이 작성되어 있음을 전제로 한다.

static class Program
{
	static System.ComponentModel.BackgroundWorker splashThread =
		new System.ComponentModel.BackgroundWorker();

	static Forms.SplashForm splash;

	/// 
	/// 해당 응용 프로그램의 주 진입점입니다.
	/// 
	[STAThread]
	static void Main()
	{
		Application.EnableVisualStyles();
		Application.SetCompatibleTextRenderingDefault(false);

		splash = new Forms.SplashForm();
		splashThread.DoWork += bgworker_DoWork;
		splashThread.RunWorkerAsync();

		var main = new Forms.MainForm();

		main.Load += Main_Loaded;
		Application.Run(main);

	}

	static void Main_Loaded(object sender, EventArgs e)
	{
		Action v = splash.Close;

		splash.Invoke(v);
	}

	static void bgworker_DoWork(object sender,
								System.ComponentModel.DoWorkEventArgs e)
	{
		Application.Run(splash);
	}
}

원리는 간단하다. MainForm에 애플리케이션이 사용하는 모든 컴포넌트들의 초기화 작업을 정의하고 SplashForm에 간단한 화면구성만을 배치하면 동시에 실행시켜도 SplashForm이 먼저 뜨게 되어 있다. 그러므로 main의 Load이벤트에 리시버를 달아서 MainForm이 완전히 로딩되면 splash가 닫히도록 해 주면 된다.

그런데 Main_Loaded가 호출되는 것은 메인스레드인데 splash는 다른 스레드에서 실행되고 있으므로 Main_Loaded에서 바로 splash.Close()하면 당연하지만 크로스 스레드 문제가 발생한다. 이를 막기 위해 splash.Close를 제네릭 대리자로 받고 스플래시 폼이 스스로 닫는 동작을 호출하도록 하면 된다.

Close가 호출되면 스플래시 스레드의 Application.Run이 반환하며 메인스레드만 남는다.

유의할 점.
두 폼이 동시에 떠 있을 때 작업표시줄에 스플래시 윈도우가 표시되지 않도록 해당 폼 속성을 꺼 주는 것이 좋다.


Tag //