|
개발 2007. 8. 13. 15:24
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
WTL로 프로그래밍하기#2 – 위저드로 생성되는 코드
저자 : hanburn
날짜 : 2007.08.13
환경 : WTL7.5, VS-2003
지난시간에는 WTL에 대해서 간략하게 알아보고 설치하고 환경 설정하는 것 까지 알아보았다. 이제 WTL로 간단한 프로젝트를 만들어 보자. VS를 열면 WTL application wizard가 보일 것이다. 이것을 선택하여 시작하도록 하자.
그런 다음에는 너무나도 익숙한 화면이다. SDI, MDI, Dialog base 등 초기의 프로그램 형태를 선택할 수 있는 창이 나온다. MFC의 wizard와 상당히 유사한 모습이다. 아래 그림처럼 Dialog Base를 선택하고 Generate .CPP Files를 체크한 뒤에 Finish를 선택하면 된다.
이렇게 하면 위저드가 기본 골격 코드를 생성하는데, 생성된 코드를 한번 살펴 보면서 시작하자.
먼저 프로젝트이름.cpp 파일을 살펴보면 아래와 같은 코드가 보일 것이다.
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
HRESULT hRes = ::CoInitialize(NULL);
...
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
int nRet = Run(lpstrCmdLine, nCmdShow);
_Module.Term();
::CoUninitialize();
return nRet;
}
우리가 잘 알고있는 WinMain 함수이다. 여기서 살펴볼 것은 _Module 이라 전역객체 인데, MFC의 theApp 와 비슷한 놈이다. MFC에서는 CWinApp를 상속받아서 각 프로그램마다 한 개씩 있던 것을 보았을 것이다. WTL에서는 CAppModule클래스의 전역객체인데, 쉽게 생각하면 전체 프로그램의 관리자 역할로 보면 될 것이다. _Module.Init()/Term() 사이에 있는 Run() 이라는 함수가 윈도우 시스템의 메시지를 가지고 와서 배분을 해주는(DispatchMessage) 역할을 하는 부분이다. 전역함수인 Run 함수에 대해서 조금 더 자세히 알아보자
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
CMainDlg dlgMain;
if(dlgMain.Create(NULL) == NULL)
{
ATLTRACE(_T("Main dialog creation failed!\n"));
return 0;
}
dlgMain.ShowWindow(nCmdShow);
int nRet = theLoop.Run();
_Module.RemoveMessageLoop();
return nRet;
}
웬지 MFC에서 InitInstance 부분과 유사한 느낌을 받을 것이다. 메인 다이얼로그를 생성하고 메시지루프를 처리하고.. WTL은 MFC보다 역할의 구분을 클래스로 잘 구분을 해놓은 느낌이다. Design Pattern Explained에서 말하는 역할 중심의 설계랄까? ^^
Run함수에서 CMessageLoop 객체를 만들고 _Module에 추가를 해주어서 메시지 펌핑을 받도록 처리하고 있다. CMessageLoop의 run함수에 우리가 익숙하게 보는 다음과 같은 코드가 들어있다.
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
if(!PreTranslateMessage(&m_msg))
{
::TranslateMessage(&m_msg);
::DispatchMessage(&m_msg);
}
이렇게 함으로써 Dialog의 기본 골격 코드를 살펴 보았다. 그리고 WTL의 위자드에서 Dialog를 선택하고 DoModal을 체크하게 되면 더 간단하게 아래처럼 Dialog의 DoModal을 호출해 준다.
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
HRESULT hRes = ::CoInitialize(NULL);
...
hRes = _Module.Init(NULL, hInstance);
int nRet = 0;
{
CMainDlg dlgMain;
nRet = dlgMain.DoModal();
}
_Module.Term();
::CoUninitialize();
return nRet;
}
보통 WTL으로 프로그래밍을 할 때, 기본적으로 생성되는 Dialog를 사용하지 않을 때는 첫번째 처럼 기본 틀을 생성하고, Dialog대신 내가 만든 윈도우를 Create 하고 Show를 해주게 되어서, 보통은 Domodal을 체크 않하고 많이 사용한다. (이것은 개인적인 취향이다. )
다음으로는 MainDlg.h 를 살펴보자. 실제적인 Dialog에 대핸 메시지 처리 및 기타 주요한 부분을 담당하는 부분이다.
class CMainDlg : public CDialogImpl<CMainDlg>,
public CUpdateUI<CMainDlg>,
public CMessageFilter,
public CIdleHandler
{
public:
enum { IDD = IDD_MAINDLG };
virtual BOOL PreTranslateMessage(MSG* pMsg);
virtual BOOL OnIdle();
BEGIN_UPDATE_UI_MAP(CMainDlg)
END_UPDATE_UI_MAP()
BEGIN_MSG_MAP(CMainDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
COMMAND_ID_HANDLER(IDOK, OnOK)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
END_MSG_MAP()
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
void CloseDialog(int nVal);
};
여기서 조금 낯설 수가 있다. 평소에 잘 사용 안하던 다중상속을 사용한 것이다. 전형적인 ATL 스타일인 것이다. 여러가지 template class 로부터 상속을 받고 있는데, 이것들은 다음 시간에 알아보도록 하겠습니다.
개발 2007. 8. 12. 00:11
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
윈도우의 트레이 영역을 구하는 함수이다. 윈도우가 트레이로 최소화 될때 DrawAnimatedRects(m_hWnd, IDANI_CAPTION, rcFrom, rcTo); 함수를 이용하면 최소화 되는 것처럼 트레이 영역으로 이동하는 것을 볼 수 있다.
void GetTrayWndRect(RECT *pRect) { HWND hwndTaskBar=::FindWindow(_T("Shell_TrayWnd"), NULL); if (hwndTaskBar){ HWND hwndTray=::FindWindowEx(hwndTaskBar, NULL, _T("TrayNotifyWnd"), NULL); if (hwndTray) ::GetWindowRect(hwndTray, pRect); else { //tray부분을 못찾으면 task바의 구석탱이를 그렇다고 믿게 하자. ::GetWindowRect(hwndTaskBar, pRect); pRect->left=pRect->right-20; pRect->top=pRect->bottom-20; } } else { //task바를 못찾으면 그냥 화면 하단부 int nWidth = GetSystemMetrics(SM_CXSCREEN); int nHeight = GetSystemMetrics(SM_CYSCREEN); SetRect(pRect, nWidth-40, nHeight-20, nWidth, nHeight); } }
개발 2007. 8. 11. 23:58
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
윈도우 탐색기가 가끔가다가 죽는 경우가 있는데, 보통은 자동으로 다시 실행이 된다. 자동으로 실행이 않되면 작업관리자를 실행시켜서 새작업 실행으로 explorer.exe 를 실행시키면 된다. 그런데 윈도우 탐색기가 다시 실행되면 Tray 영역에 있던 아이콘이 사라지게 된다. 그러나 MSN 같은 몇몇 프로그램은 Trya 에 아이콘이 있는데, 그것을 다음과 같이 하면 된다.
// 메시지 등록 UINT g_uShellRestart; g_uShellRestart = RegisterWindowsMessage(__Text(“TaskbarCreated”));
// Message Map 에서 ON_REGISTERED_MESSAGE(g_uShellRestart, OnTrayShow)
// 메시지 핸들러 LRESULT CMyDlg::OnTrayShow(WPARAM wParam, LPARAM lParam) { // TrayIcon을 다시 보여줍니다. ShowTray는 Tray를 보여주는 함수입니다. m_Tray.ShowTray(); }
위에서 보면 알겠지만, explorer가 다시 실행될때 TaskbarCreated 라는 메세지가 발생이 된다. 이것을 잡아서 처리하면 되는 것이다.
개발 2007. 8. 10. 17:02
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
TimyXML 사용해보기 - xml로 만들기
저자 : hanburn 날짜 : 2007.08.10 환경 : VS-2003, TinyXML 2.5.3
앞에서는 xml 파일이나 xml문자열에서 파싱을 해서 원하는 정보를 뽑아오는 것을 해보았다. 그러면 이제는 반대로 설정이나 원하는 정보를 xml 형식으로 만들어 보자. 앞에서 사용한 xml을 만들어 보도록 하자
<?xml version="1.0" ?> <MyApp> <!-- Settings for MyApp --> <Messages> <Welcome>Welcome to MyApp</Welcome> <Farewell>Thank you for using MyApp</Farewell> </Messages> <Windows> <Window name="MainFrame" x="5" y="15" w="400" h="250" /> </Windows> <Connection ip="192.168.0.1" timeout="123.456000" /> </MyApp>
일단 xml 의 형식선언부터 시작해 보자..
TiXmlDocument doc; TiXmlElement* msg; TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" ); doc.LinkEndChild( decl );
이렇게 하면 <?xml version="1.0" ?> 이 생성된다. 다음으로는, 서브 노드를 추가해보자.
TiXmlElement * root = new TiXmlElement( "MyApp" ); doc.LinkEndChild( root );
간단하다. 그리고 new로 생성한 TiXmlElement를 해제할 필요가 없다. 내부에서 자동으로 삭제를 해주기 때문이다. (편리하군~ ^^) 그런 다음 주석문장을 추가해 보자.
TiXmlComment * comment = new TiXmlComment(); comment->SetValue(" Settings for MyApp " ); root->LinkEndChild( comment );
주석은 TiXmlComment 클래스를 사용하면 된다. 편리하군.. 다음으로는 Message 서브노드와 하위 노드및 데이터를 추가해보자
TiXmlElement * msgs = new TiXmlElement( "Messages" ); root->LinkEndChild( msgs );
msg = new TiXmlElement( "Welcome" ); msg->LinkEndChild( new TiXmlText( "Welcome to MyApp" )); msgs->LinkEndChild( msg );
msg = new TiXmlElement( "Farewell" ); msg->LinkEndChild( new TiXmlText( "Thank you for using MyApp" )); msgs->LinkEndChild( msg );
역시 쉽니다. 다음에는 노드를 추가하고 Attribute를 설정해보자 레벨을 맞추기 위해서 root의 하위로 추가 한것을 주의 깊게 봐야 한다.
TiXmlElement * windows = new TiXmlElement( "Windows" ); root->LinkEndChild( windows );
TiXmlElement * window; window = new TiXmlElement( "Window" ); windows->LinkEndChild( window ); window->SetAttribute("name", "MainFrame"); window->SetAttribute("x", 5); window->SetAttribute("y", 15); window->SetAttribute("w", 400); window->SetAttribute("h", 250);
다음은 마지막으로 Double 값 (소수점 값) 을 설정하는 예를 보자
TiXmlElement * cxn = new TiXmlElement( "Connection" ); root->LinkEndChild( cxn ); cxn->SetAttribute("ip", "192.168.0.1"); cxn->SetDoubleAttribute("timeout", 123.456); // floating point attrib
이렇게 하면 우리가 원하는 xml이 doc에 만들어 졌다. 이것을 파일로 저장할 수도 있고 xml 문자열로 만들수도 있다. 방법은 아래를..
// 파일로 저장 doc.SaveFile("text.xml");
//문자열로.. TiXmlPrinter printer; printer.SetStreamPrinting(); Doc.Accept( &printer ); char* pAA = printer.CStr(); // char* 를 반환한다. std::string str = printer.Str(); // std::string으로 반환한다.
이로써 간단하게 TinyXML의 사용법을 마칠까 한다.
개발 2007. 8. 10. 14:57
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
TimyXML 사용해보기 - xml에서 읽어오기
저자 : hanburn 날짜 : 2007.08.10 환경 : VS-2003, TinyXML 2.5.3
XML에 대해서는 이미 알고 있다고 가정합니다. (모르면 공부하고 다시 오세요 ^^)
일단 XML을 파일에서 읽을수도 있고 문자열로 읽을 수도 있다. 아래 예에서 사용할 xml 파일은 다음과 같다.
<?xml version="1.0" ?> <MyApp> <!-- Settings for MyApp --> <Messages> <Welcome>Welcome to MyApp</Welcome> <Farewell>Thank you for using MyApp</Farewell> </Messages> <Windows> <Window name="MainFrame" x="5" y="15" w="400" h="250" /> </Windows> <Connection ip="192.168.0.1" timeout="123.456000" /> </MyApp>
먼저 파일에서 읽을때는,
TiXmlDocument document; document.LoadFile(_File_Name_);
문자열로 읽을때는,
TiXmlDocument document; document.Parse(szXML);
너무 쉽다. 그런 다음에는 원하는 값을 찾아오면 된다. 먼저 노드와 엘리먼트를 가지고 오는 방법을 알아보자. ( 노드는 자식을 가지고 있는 것이고 엘리먼트는 마지막에 있는 놈이다. )
TiXmlElement* pRoot = document.FirstChildElement("MyApp"); if( NULL == pRoot ) return FALSE; // 해당 Element가 없으면 널이므로.. 체크해주는게 좋다.
그럼, <Welcome> 태그로 가서 데이터를 가지고 와보자.
pElement = pRoot->FirstChildElement("Message"); pElement = pElement->FirstChildElement("Welcome"); char* pAA = pElement->Value(); // pAA 은 "Welcome" 이다. pAA = pElement->GetText(); // pAA 은 "Welcome to MyApp" 이다.
이번에는 다음에 windows 태그로 가서 name 속성을 읽어 와보자.
pElement = pRoot->FirstChildElement("Windows"); char* pAA = pElement->Attribute("name"); // pAA에 "MainFrame"이 들어온다. int x; pElement->Attribute("x", &x); // x 에 숫자 5가 들어온다.
그다음에는 루프를 돌면서 child 노드를 순환하는 방법이다.
pNode = pRoot->FirstChild("sub_node"); for( pNode ; pNode ; pNode = pNode->NextSibling()) { pAA = pNode->Value();
pElement = pNode->FirstChildElement("item"); pAA = pElement->GetText(); }
개발 2007. 8. 10. 14:22
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
TinyXML은 간단하고 작은 C++ XML 파서 입니다. 사용하기가 편리하고 다른 프로그램으로 이식하기도 수월한 편입니다. 온라인 도움말 : http://www.grinninglizard.com/tinyxmldocs/index.html소스를 받는곳 : http://sourceforge.net/projects/tinyxml/설치하려면.. 일단 소스 받는곳에서 소스를 환경에 맞게 받는다. 윈도우 버전으로 받으면 VC++6.0 작업화일과 VS.NET 용 솔루션 파일이 포함되어 있다. 사용하는 방법은 2가지로 나눌수 있다. ( 그리고 각각 STL을 사용하는 버전과 아닌 버전으로 되어 있다. ) 1. 해당 소스를 컴파일 하여 생성되는 Tinyxml.lib와 헤더파일을 이용하는 방법 - 이방법은 제공되는 솔루션 파일( tinyxml.sln) 을 열어서 빌드만 하면 된다. - 사용하는 프로젝트가 멀티 쓰레드이면 런타임 라이브러리를 멀티 쓰레드로 변경해야 한다. (기본 설정은 싱글 쓰레드로 되어 있다. - tinyXml.lib 는 스태틱 라이브러리로 컴파일시에 exe에 포함되므로 따로 배포를 않해도 된다. 2. 소스를 직접 포함시켜서 사용하는 방법. - 필요한 파일을 프로젝트에 파일 추가로 등록한다. (tinystr.h(cpp), tinyxml.h(cpp), tinyxmlerror.cpp, tinyxmlparse.cpp 총 6개다 ) - 컴파일을 하려고 하면 precompile header 관련하여 에러가 난다. - 프로젝트 설정에서 cpp의 (3개 파일) precompile header 사용을 빼버린면 된다.
어떻게 보면 거의 같은 방법이다. ㅎㅎ 개인적으로 2번째 방법을 선호한다. 개발중에 cpp 소스를 가끔 보게 되므로.. 그럼 다음 글에서는 간단한 사용법들을 알아보자.
개발 2007. 8. 9. 10:00
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
간단한 코드이지만 가끔 생각이 안날때가 있다.. ㅋㅋ
원리는 간단하다. 윈도우의 확장스타일(WS_EX_) 을 얻어와서 속성만 변경해 주면 된다.
아래는 예제 코드이다.
HideApplicationTitleBar() { DWORD dwStyle = GetWindowLong(m_hWnd, GWL_EXSTYLE); dwStyle &= ~WS_EX_APPWINDOW; dwStyle |= WS_EX_TOOLWINDOW; SetWindowLong(m_hWnd, GWL_EXSTYLE, dwStyle); }
영화&책 2007. 8. 8. 16:14
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
경청
<저자> <소개> 저자 : 조신영 & 박현찬 출판사 : ?? ‘듣는 사람’보다 ‘말하는’ 사람이 더 많은 이 시대와 우리 사회에 가만히 상대에게 귀 기울여 듣는 것이 얼마나 위대한 소통의 지혜인지 일깨워주는 자기계발서. 저자는 보통의 대한민국 40대 전후의 직장남성을 주인공으로 내세워 우리가 일상적으로 겪는 단절된 소통의 답답함을 현실적으로 접근시킨다. 직장과 가정이라는 삶의 터전에서 점점 더 주변인물로 소외되어가는 남성들이 늘어가고 있는 요즘, 이 땅에서 직장인으로, 남편으로, 아버지로 더불어 잘 살아가기 위해 꼭 한 번쯤은 귀 기울여야 할 삶의 자세를 전하는 책이다. <줄거리> 악기 제조 회사에서 일하는 이청은 아내와 별거중이고 아들은 발달장애의 증상이 있다. 평소 회사에서 듣기 실은 말은 '알았다' 라고 말하고 넘기며 타인의 말을 자기 편한 대로만 받아 들이는 사림이다. 회사에서 구조조정이 되어서 대리점 개설권을 받고 명예퇴직을 하게 된다. 대리점 오픈날 갑자기 쓰러진 이청은 뇌줄기암에 걸린 것을 알게된다. 갑자기 찾아온 불행들에 좌절하지만, 마지막으로 아들에게 무언가 남겨주고 싶다는 생각에 예전에 근무하던 회사의 강원도 악기 공장으로 가서 바이올린 제작을 배우게 된다. 제작 3팀에 무급사원으로 제조를 배우던 이청은 치악산의 나무노인과 독순술을 가리쳐 주는 구박사를 통해서 듣는 것의 소중함을 배우게되고, 문제가 많았던 3팀의 분위기를 바꾸게 된다. <느낌> 읽기에 편한 책이었다. 간간이 있는 삽화와 큼직한 글씨.. 이청득심(以聽得心) : 귀기울여 경청하는 일은 사람의 마음을 얻는 최고의 지혜이다. 평소에 듣기를 얼마나 잘 할까? 나를 되돌아보면 말하기를 즐거워 하는 편인것 같다. 상대방이 하는 말중 정말 듣기 싫은 말도 있는데, 이런 말도 경청을 할 수 있을까? 누구나 알고있는 경청의 중요함을 다시 한번 일깨워 주는 책이지만.. 상대가 재미없는 말을 하거나, 독선적인 모습으로 하는 말도 경청을 해야 할까? 물론 경청을 하면 득이되겠지만.. 어려운 일임에는 틀림없다. 나무노인처럼 자연의 소리를 들어 볼 수 있을까? ㅎㅎ 이청은 죽음을 앞두고 있어서 듣는 것에대해서 더 몸으로 느낄수 있었던 것은 아닐까 생각해 본다.
개발 2007. 8. 6. 21:43
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
WTL로 프로그래밍하기
저자 : hanburn 날짜 : 2007.08.06 환경 : WTL7.5, VS-2003
MFC로 프로그래밍을 해오다가 WTL을 접해보게 되었다. 예전부터 듣기는 했었는데, 직접 사용해 보니 가볍고 좋은 라이브러리인 것 같다. WTL의 장점이 뭐가 있을까? 아직 많이 써보지는 않아서 뭐라 딱히 말 할 수 없지만 일단 느껴본 것은 실행파일이 작다는 것이다. 간단한 Dialog 기반의 프로그램을 만들어서 컴파일하면 32KB 밖에 안된다. 물론 MFC를 사용 안하고 Win32로만 만들면 더 작아지겠지만, 프로그램 제작에 들어가는 편리함에 비한다면 충분히 감수할 만한 것 같다.
WTL은 Window Template Library으로 사용을 원만하게 하려면 template에 대해서 충분히 익숙해 저야 한다. 아직 template에 대해서 잘 모르더라도 너무 걱정하기 마시길.. 차차 익숙해 지겠지요..
WTL에 대한 ms 싸이트의 간단한 설명을 보면 다음과 같습니다.
Windows Template Library (WTL) is a library for developing Windows® applications and UI components. It extends ATL (Active Template Library) and provides a set of classes for controls, dialogs, frame windows, GDI objects, and more. This version provides support for Windows Vista and Visual Studio 2005, and also support for the Windows CE platform.
윈도우어플리케이션과 UI 컴포넌트를 개발하기 위한 라이브러리로, ATL을 확장하고 컨트롤, 다이얼로그, 프레임 윈도우 GDI 객체 등등을 제공한다고 하는 군요.. 한마디로 UI를 처리할 때 사용하는 라이브러리라는 것입니다.
사용하려면 일단 설치를 해야 되는데, 아래의 URL에서 다운받을 수 있다.
WTL 7.5 : http://www.microsoft.com/downloads/details.aspx?familyid=48CB01D7-112E-46C2-BB6E-5BB2FE20E626&displaylang=en
WTL 8.0 : http://www.microsoft.com/downloads/details.aspx?familyid=e5ba5ba4-6e6b-462a-b24c-61115e846f0c&displaylang=en&tm
(현재 최신 버전은 8.0이 나왔는데, 지금의 강좌에서는 7.5 버전을 기준으로 하겠습니다. )
설치하는 과정은 다운을 받아서 압축을 풀면, AppWiz및에 VS버전에 맞는 자바스크립트 셋업 파일을 클릭해주면 된다. 그리고 아래처럼 include 폴더를 추가해주면 끝이다.
그리고 앞으로 시작할 강좌는 www.codeproject.com/wtl/ 의 wtl4mfc 강좌를 참고로 하여 진행이 되는 강좌입니다. 사용하는 버전은 WTL 7.5를 사용하고 VS-2003에서 코딩이 이루어 집니다.
개발 2007. 7. 31. 10:41
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
WTL 7.5 버전을 사용중인데.. SplitterWnd에 Pane 을 서로 교환(Swap)할 수 있는 기능이 없다. SwapPane() 이라는 함수가 있으면 좋을텐데..
그래서 SwapPane의 기능을 아래처럼 구현 해보았다.
if( m_wndSplitter.GetSplitterPane(SPLIT_PANE_TOP) == m_wndHeadline ) { m_wndSplitter.SetSplitterPane(SPLIT_PANE_TOP, m_wndSection); m_wndSplitter.SetSplitterPane(SPLIT_PANE_BOTTOM, m_wndHeadline); } else { m_wndSplitter.SetSplitterPane(SPLIT_PANE_TOP, m_wndHeadline); m_wndSplitter.SetSplitterPane(SPLIT_PANE_BOTTOM, m_wndSection); }
그러나 atlsplit.h의 소스에 아래처럼 되어있어서 ATLASSERT가 발생하였다..
bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true)
{
ATLASSERT(nPane == SPLIT_PANE_LEFT || nPane == SPLIT_PANE_RIGHT);
if(nPane != SPLIT_PANE_LEFT && nPane != SPLIT_PANE_RIGHT)
return false;
m_hWndPane[nPane] = hWnd;
ATLASSERT(m_hWndPane[SPLIT_PANE_LEFT] == NULL || m_hWndPane[SPLIT_PANE_RIGHT] == NULL || m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]);
if(bUpdate)
UpdateSplitterLayout();
return true;
}
음.. 그래서 그냥 아래처럼 처리하였다..
if( m_wndSplitter.GetSplitterPane(SPLIT_PANE_TOP) == m_wndHeadline )
{
m_wndSplitter.m_hWndPane[SPLIT_PANE_TOP] = m_wndSection;
m_wndSplitter.m_hWndPane[SPLIT_PANE_BOTTOM] = m_wndHeadline;
m_wndSplitter.UpdateSplitterLayout();
}
else
{
m_wndSplitter.m_hWndPane[SPLIT_PANE_TOP] = m_wndHeadline;
m_wndSplitter.m_hWndPane[SPLIT_PANE_BOTTOM] = m_wndSection;
m_wndSplitter.UpdateSplitterLayout();
}
좀 깔끔하지는 않지만.. 일단 해결..
|