###Frame
아래의 함수들은 CFrameWnd
또는 CFrameWndEx
를 상속받은 클래스의 메소드에서 이루어 진다.
######1. 시스템 버튼[최소화/최대화/닫기]
OnCreate
에서 아래의 함수 호출.
this->ModifyStyle(WS_SYSMENU, 0);
######2. 메뉴 제거
PreCreateWindow
에 아래 코드 추가
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs){
/*...*/
if (cs.hMenu!=NULL) {
::DestroyMenu(cs.hMenu);
cs.hMenu = NULL;
}
return TRUE;
}
######3.프레임 덧칠하기
OnNcPaint
에서 테두리의 영역을 정의해 색칠한다.
아래의 그림은 윈도우 프레임영역(CFrameWnd::OnNcPaint()가 그려야 하는
영역, 이 함수의 CWindowDC
는 사실 모든 윈도우 영역을 그릴수 있음.)
void CMainFrame::OnNcPaint() {
CRect rect_window;
this->GetWindowRect(&rect_window);
rect_window.NormalizeRect();
rect_window.OffsetRect(-rect_window.left, -rect_window.top);
//Fixed value
CBrush brush;
brush.CreateSolidBrush(RGB(127, 127, 127));
CRect rect_window_top = rect_window;
CRect rect_window_bottom = rect_window;
CRect rect_window_left = rect_window;
CRect rect_window_right = rect_window;
rect_window_top.bottom = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYSIZEFRAME);
rect_window_bottom.top = rect_window_bottom.bottom - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYSIZEFRAME);
rect_window_left.right = GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXSIZEFRAME);
rect_window_right.left = rect_window_right.right - GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXSIZEFRAME);
ncpaint->FillRect(rect_window_top,&brush);
ncpaint->FillRect(rect_window_bottom, &brush);
ncpaint->FillRect(rect_window_left, &brush);
ncpaint->FillRect(rect_window_right, &brush);
}
이 함수를 사용하려면 OnNcActivate
함수에서 무조건 호출해줘야 한다.
BOOL CMainFrame::OnNcActivate(BOOL bActive) {
this->OnNcPaint();
return TRUE;
}
######4. 둥근 테두리 제거
위의 방식으로 색을 덧칠하면 이상하게 윈도우 윗부분만 둥글다(Window7의 프레임을 덧칠한것이기 때문)
이를 해결하고자 OnSize
메소드에서 SetWindowRgn
함수를 호출한다.
마지막 두 인자를 0으로 주면 직사각형의 창이 생성된다.
void CMainFrame::OnSize(UINT nType, int cx, int cy) {
CFrameWnd::OnSize(nType, cx, cy);
CRect rect_window;
this->GetWindowRect(&rect_window);
rect_window.NormalizeRect();
rect_window.OffsetRect(-rect_window.left, -rect_window.top);
CRgn rgn;
rgn.CreateRoundRectRgn(0, 0, rect_window.Width(), rect_window.Height(),10,10);
this->SetWindowRgn(static_cast<HRGN>(rgn.GetSafeHandle()), TRUE);
}
######6. 시스템 버튼 그리기
확장성과 종속성방지를 위해 리소스에 있는 비트맵을 사용한다.
역시 OnNcPaint
함수에서 그린다.
std::vector<CRect> m_sysbtn; //추후에 상자 정보를 알기위해 멤버변수로 정의.
void CMainFrame::OnNcPaint() {
//프레임 그리기 생략
std::vector<UINT> bitmap_resource = {IDB_FRAME_CLOSE,IDB_FRAME_MAXIMIZE,IDB_FRAME_MINIMIZE};
int padding = 4;
CSize btn_sz(rect_window_top.Height() - padding * 2, rect_window_top.Height() - padding * 2);
CPoint btn_pt(rect_window.right - rect_window_right.Width()-btn_sz.cx,
rect_window.top + padding);
this->m_sysbtn.clear();
CDC cdc;
cdc.CreateCompatibleDC(ncpaint);
for (size_t i = 0; i < bitmap_resource.size(); i++) {
BITMAP bmp;
CBitmap cbmp, *old_cbmp = nullptr;
cbmp.LoadBitmap(bitmap_resource[i]);
cbmp.GetBitmap(&bmp);
old_cbmp = cdc.SelectObject(&cbmp);
ncpaint->TransparentBlt(btn_pt.x, btn_pt.y,btn_sz.cx ,btn_sz.cy, &cdc, 0, 0,bmp.bmWidth,bmp.bmHeight, RGB(255, 255, 255));
this->m_sysbtn.push_back(CRect(btn_pt.x,btn_pt.y,btn_pt.x+btn_sz.cx,btn_pt.y+btn_sz.cy));
btn_pt.x -= btn_sz.cx +5;
cdc.SelectObject(old_cbmp);
}
}
######7. 마우스 추적 활성화
이 함수는 마우스가 창 밖을 나갔을때 호출된다. Hover된 버튼을 해지하거나 할때 사용된다.
void CMainFrame::OnNcMouseMove(UINT nHitTest, CPoint point) {
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE | TME_NONCLIENT;
tme.dwHoverTime = 0;
TrackMouseEvent(&tme);
CFrameWnd::OnNcMouseMove(nHitTest, point);
}
void CMainFrame::OnNcMouseLeave() {
//Hover 기능의 해지 등등...
CFrameWnd::OnNcMouseLeave();
}