반응형

1. Modal / Transient , 의 개념

어플리케이션의  코드 실행 중간에, 사용자의 피드백(interaction)을 유도하는 대화상자를 띄워 사용자가 선택을 하고 대화상자가 닫힐 때까지, 코드 흐름이 멈춰 있도록 할 수 있는 기능을 말합니다.

이런 기능은 특정 상황에서 매우 유용하고, 편리한 코드 작성을 할 수 있도록 도와줍니다.

예를 들면아래와 같은 플로우(flow) 작성하고 싶다고 가정 합니다.

1. 프로그램 실행
2. copy button 선택
3. copy 할 것인지 묻는 message box 를 띄움  (Do you wanna start copy?)
4. 사용자가 OK를 누르면, copy를 실행함.

Platform을 개발하면서 Windows 에서 제공하는 Modal 과 같은 기능을 어떤 방식으로 지원할까에 대해서 여러차례 고민 해봤습니다.

실제로 기능 자체의 구현은 어려운 것이 아니나, 예외 상황에 대한 처리가 항상 문제가 되더군요.


가장 기본적인 예외 상황은 UI 상 modal 과 Code상으로 Modal 상태에서 parent window가 종료된다거나, modal을 실행한 주체가 종료된다면, messagebox를 띄워서 기다리고 있는 코드의 다음 라인들은 어떻게 처리되어야 하는 가 입니다.

이 외에도 여러가지 예외상황을 만들때가 많습니다.이는 마치, multi-thread programming 과 비슷한 양상을 나타냅니다.

그래서 아래 코드의 pWind->DoModal()의 앞 과 뒤에서 내부 변수나 외부 변수들 그리고 객체의 상태가 달라질 수 있다는 의미 입니다.

즉 MyTestWindow 가 삭제되었거나 그 내부변수들의 정보가 바뀌어있을 수도 있다는 의미죠.

 

void MyTestWindow::KeyPressed() {
  HFile hDBCopyLog = CreateFiile("Log.txt");
  pWind = CreateModalMessageBox("Do you wanna start copy?");
  returnValue = pWind->DoModal(); //<-- -3. Modal window가 뜨고 코드상으로 아래로 진행되지 않고 멈춰 있는 부분 
           if (returnValue == OK) {
    CopyFile(pathDest, pathSrc);
    sprintft(testBuf, "handle=%d", this->m_hWin); //< --B.this와 this->m_hWin 이 정상적이다라는 보장이 없음 
    WriteFile( hDBCopyLog, testBuf);
    CloseFile(hDBCopyLog);
    return TRUE;
  }
 

만약 위와 같은 코드가 있다고 한다면, DoModal() 내부에서 분명 event 처리를 할수 있는 event loop 이 구현 되어있을 것입니다.
이 이벤트 loop에서 pWind를 가지고 있는 application 이나 window를 종료 했다면 User 입력을 기대하고 작성했던 OK일때 처리 부분이 수행이 안되게 될 수도 있습니다.
또 더 심각하게 본다면 this 나 m_hWin 도 정상적으로 살아있을것이라는 보장도 못하게 됩니다.


2. Modal 기능 구현

DoModal 기능은 의외로 간단한데요.

아래와 같이 platform에서 제공하는 event를 처리loop 코드를 참조하여 event queue 처리 로직을 loop로 제공하면 됩니다.

 

result MessageBox::DoModal() {
  while (!bEixt) {
    ReceiveMessage(&msg);
    ProcessMsg(&msg);
  }
}

WIN32 기준으로 봤을때...
Window들을 모두 종료 시키고 어플리케이션을 빠져 나가야 하는 경우라고 가정한다면,

 

WM_QUIT 메세지를 받게 되면, WM_QUIT에 의해 modal window가 삭제 될것 입니다. 그러나 parent window는 삭제가 되지 않기 때문에, WM_QUIT을 다시 한번 event queue에 넣어야 합니다.

이렇게 하면 Modal loop을 빠져 나가고,WM_QUIT 메세지를 재 생성해서(PostQuitMessage) 바깥에 있는 main loop에서 정리할 수 있도록 해줘야 합니다.

result MessageBox::DoModal() {
  while (!bEixt) {
    ReceiveMessage(&msg);
    if (msg.type == WM_QUIT) {
      bExit = TRUE;
      PostMessageFront(&msg);
      bException = TRUE;
    }
    if (!bException)
      ProcessMsg(&msg);
  }
}


platform 을 개발하는 입장에서   Modal을 구현하여 제공 해야 한다면 위와 비슷한 방법으로 application 종료 event를 받으면 우선 이 이벤트를 부모 window부터 처리하는 것이 아니라 modal window에서 먼저 처리를 하고 , modal window를 종료 시키고, 같은 event를 다시 event queue에 넣어서 modal event loop을 빠져 나간 다음에 main loop(또는 상위 event loop) 에서 처리할 수 있도록 합니다.

modal이 한개가 아니라 중첩, 3중첩 되어 있을 가능 성도 있기 때문입니다.

 

 

1. 프로그램 실행
2. delete button 선택
3. delete 할 것인지 묻는 message box 를 띄움  (Do you wanna delete this file?)
4. 진짜로 지울 것인지 묻는 message box 를 띄움  (리얼리?)
5 파일을 지움

 

 

+ Recent posts