상세 컨텐츠

본문 제목

다중 모니터와 메시지 박스

C#

by 탑~! 2014. 1. 3. 08:37

본문

얼마 전까지 엄청난 스트레스를 받는 프로젝트를 진행했습니다빨리 끝나기만을 손꼽아 기다렸던 그런 프로젝트였습니다하지만 아무리 스트레스를 받고 짜증나더라도 개발에 관련된 일이건 인간관계에 관련된 일이건 배울 것은 있다는 것을 다시 한번 깨닫게  그런 프로젝트였습니다.

그래서 배운 것이 무엇이냐바로 다중 모니터를 사용하는 환경을 제어는 방법과 이때 발생되는 문제가 있다는 것입니다.

다중 모니터(Multi Monitor) 제어

일반적인 응용프로그램을 개발할 다중 모니터까지 고려할 일은 거의 없습니다다중 모니터라 하여 특별한 처리를  필요도 없을뿐더러 운영체제가  알아서 해주기 때문입니다하지만 개발할 응용프로그램이   이상의 (Form)으로 구성되고 상호작용을 한다면 얘기가 달라집니다 개의 폼이 동시에 실행되고  번째 모니터에  번째 폼이  번째 모니터에  번째폼이 나타나야 한다면 어떻게 처리해야 할까요문득 드는 생각은  모니터(Primary Monitor) 특별한 처리를  필요가 없을 것이고 모니터(Secondary Monitor) 폼을 출력할 경우만 고려하면  것입니다.

이는 그리 복잡하지 않은 로직으로 해결할  있습니다 번째 폼이  모니터에 출력되어야  경우  번째 폼의 Location 지정해 주면 됩니다 모니터의 왼쪽 상단 좌표는  모니터의 넓이(width) 0입니다, SecondForm.Location = new Point( 모니터의 width, 0) 같이 설정하면 됩니다하지만 닷넷은 이를 좀더 쉽고 편리하게 처리하기 위해 시스템상의모니터() 관리하는 Screen이라는 클래스를 제공합니다.

Screen 클래스는 시스템상의 모든 모니터를 알아내는 AllScreens라는 속성을 제공합니다 속성을 사용하면 현재 멀티 모니터를 사용하고 있는지를 알아낼  있으며 특정 모니터에 폼을 출력시킬 수도 있습니다.

_secondForm = new SecondForm();

Screen[] screens = Screen.AllScreens;

           

if (screens.Length > 1)

{

    _secondForm.Show();

    if (screens[1].Primary == false)

    {

// 위치  넓이를 설정 

        _secondForm.Bounds = screens[1].Bounds;

        // 위치만 설정

        //secondForm.Location = screens[1].Bounds.Location;

    }

}

 

AllScreens 속성을 통해 모든 스크린을 알아낸 다음스크린의 개수가 1 이상이면 멀티 모니터를 사용하고 있다고 가정할 있습니다. 0번째 스크린이  모니터이며 1번째 스크린이  모니터일 것입니다  확실하게 하기 위해 Screen Primary속성을 사용하여  모니터인지  모니터인지를 확인할 수도 있습니다.  이렇게  모니터가 있다면 Form Bounds 속성에 Screen Bounds 속성을 할당합니다. Bounds속성은  클라이언트 영역(스크롤 제목 표시줄 ) 포함한 위치  넓을값을 포함하고 있으며  번째 폼에  번째 스크린의 Bounds 할당하게 되면  번째 모니터에  차는 폼이 출력됩니다만약 위치만  번째 모니터에 지정하고 싶을 경우에는 Location 속성을 사용하면 됩니다.

이렇게 Screen 클래스를 사용하여 다중 모니터를 쉽게 제어했습니다하지만 이때 새로운 문제가 발생할  있습니다.

멋대로 표시되는 메시지 박스

 번째 폼과  번째 폼에서 각각 메시지 박스를 띄워보면   아무 이상이 없을 것입니다 폼을  모니터와  모니터로 이동하면서 메시지 박스를 띄워 보아도 아무 문제 없을 것입니다그렇다면  번째 폼에서  번째 폼의 메서드를 호출하여 메시지 박스를 출력해 보도면 어떻게 될까요우선  번째 폼에 ShowMessage라는 메서드를 만들고  메서드를  번째 폼에서 호출하는 코드를 만듭니다.

//FirstForm.cs

private void btnSendMessage_Click(object sender, EventArgs e)

{

    if (_secondForm != null)

    {

        _secondForm.ShowMessage(txtMessage.Text);

    }

}

 

//SecondForm.cs

public partial class SecondForm : Form

{

    public void ShowMessage(string message)

    {

        //소유자를 설정하지 않으면 메시지 박스는 (primary) 모니터에 표시된다.

        MessageBox.Show(message);

}

}

 

 번째 폼의 btnSendMessage 버튼을 클릭하면  번째 폼의 ShowMessage 메서드가 호출되며   어떤 일이 발생하는지 보도록 하겠습니다메시지 박스는  모니터에 출력될 것입니다 그럴 수도 있지 하며 넘어갈  있는 문제 같아 보이지만 개발자가 아닌 일반 사용자들은 버튼을 클릭하면  번째 폼에 어떤 동작이 수행될 것이라 예상하고 있습니다  메시지 박스는  모니터에 출력되고 메시지 박스가 모달 다이얼로그(ModalDailog)이다 보니  번째 폼은 비활성화 되어 아무런 동작도 수행되지 않게 됩니다사용자는 메시지 박스를 보지 못하고 응용프로그램이 죽었다 또는 얼었다고 말할 것입니다개발자 입장에서 해결은 해야 하지만 사용자로부터 전달받은 오류의 내용은 그냥 죽었다 또는 얼었다라는 말뿐입니다당연히 오류를 재현하기도 힘들어 문제의 원인을 찾기 어려울 것입니다.

 부분은 전적으로 개발자의 잘못이며 개발자가 해결해야  부분입니다 글의 목적이 바로  문제를 해결하는 것입니다.

 메시지 박스가  모니터에 뜨는 것일 까요?

MessageBox 클래스는  많은 오버로드(overload) 제공하고 있습니다하지만 저를 포함한 대부분의 개발자들은 메시지 매개변수 하나만을 받는 오버로드를 사용하는 경우가 많습니다이것이 바로 문제의 원인입니다. MessageBox  번째 매개변수로 소유자(Owner) 지정할  있습니다소유자는 MessageBox 소유하게 되는 개체로 보통 메시지 박스를 띄우는 폼이 소유자가 됩니다. MessageBox 소유자를 지정하지 않을 경우 자동으로 소유자를 지정하게 됩니다자동으로 소유자를 지정하는데  문제가 될까요리플렉터(.NET Reflector) 통해 MessageBox 내부를 보면 소유자를 지정하는 다음과 같은 코드를   있습니다.

else if (owner == IntPtr.Zero)
    owner = UnsafeNativeMethods.GetActiveWindow();

 

소유자가 IntPtr.Zero, 소유자가 지정되지 않으면 UnsafeNativeMethods.GetActiveWindow() 통해 현재 활성화된 윈도우를 소유자로 지정하게 됩니다드디어 문제가 해결되었습니다.

소유자를 지정하지 않은 상태에서  번째 폼의 버튼을 클릭하면 활성화된 윈도우는  번째 폼이 됩니다이때  번째 폼에서 메시지 박스를 띄울 것이며  메시지 박스의 소유자는 활성화된 윈도우  번째 폼이 되는 것입니다

문제점이 명확해 졌으니 해결해 보도록 할까요 그렇습니다소유자를 지정하기만 하면 됩니다.

public void ShowMessage(string message)

{

    //메시지 박스의 소유자를 설정하지 않으면 메시지 박스는 (primary) 모니터에 표시된다.

    //MessageBox.Show(message);

    // 문제를 해결하기 위해서는 소유자를 반드시 설정해야 한다.

    MessageBox.Show(this, message);

}

MessageBox  번째 매개변수로 소유자를 반드시 지정하는 습관을 기르는 것이 아주 중요합니다이런 습관이 없었기에 이런 아티클을 쓰고 있지만 어쨌든 좋은  하나 알았으니 만족하며 저를 포함한 모든 개발자 분들이 소유자를 지정하는 습관을 길렀으면 합니다.



출처 : http://kyeongkyun.tistory.com/87


관련글 더보기