'2008/07'에 해당되는 글 6건
- 2008/07/30 [MFC] CScrollView와 줌인 줌아웃 처리.
- 2008/07/17 [MFC] Ruler 소스.. 메모리 DC 사용한 자연스러운 효과구현..
- 2008/07/17 [MFC] 스냅, 도킹 관련 구현 샘플..
- 2008/07/17 윈도우즈 업데이트 오류날때.. 레지스트리 등록 필수!!
- 2008/07/09 [MFC] CxImage 1비트 이미지 만들기...
- 2008/07/06 [MFC] Polyline 형태 라인에 옵셋 포인터 찍기.
[MFC] Ruler 소스.. 메모리 DC 사용한 자연스러운 효과구현..
중점 :
- 줌인 줌아웃 처리를 위한 float 변수를 하나 추가 했습니다.
- ScrollView의 페이지 크기를 저장하는 CSize 변수를 하나 추가 했습니다.
- 방향키 UP, DOWN 을 사용해서 줌인, 줌아웃 처리를 보여 줍니다.
이제 설명을 시작하겠습니다.
Ruler 보완
Ruler의 기존 소스를 보게 되면 마우스로 스크롤 할때 Ruler가 따라 가지 않습니다.
기존 코드를 볼가요?
// 기본 Ruler
CRect rulerRect;
rulerRect.left = scrollPosition.x;
rulerRect.right = rulerRect.left + curArea.Width();
rulerRect.top = scrollPosition.y;
rulerRect.bottom = rulerRect.top + 20;
m_RulerHorz.Draw( pDC, rulerRect.left, rulerRect.top, rulerRect.Width(), rulerRect.Height(), scrollPosition.x );
분명히 scrollPosition.y를 해줬는데도 안됩니다.
이걸 해결 하기 위해서는 휠을 움직여서 화면을 업데이트 한 것이기 때문에
아래의 OnMouseWheel함수를 오버라이드(?) 해서 Invalidate()를 해줘야 됩니다.
BOOL CRulerSampleView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
Invalidate();
return CScrollView::OnMouseWheel(nFlags, zDelta, pt);
}
그리고 Scroll의 Bar를 움직여도 화면이 업데이트 되어야 하기 때문에 아래의 함수들도 같이 처리
void CRulerSampleView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
Invalidate( true );
CScrollView::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CRulerSampleView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
Invalidate( true );
CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
}
이렇게 하고 나면 휠 또는 스크롤바를 움직여도 Ruler가 자연스럽게 화면에 보이는걸 알 수 있습니다.
자자..
이제 줌인 줌아웃 처리를 해볼까요..
줌인 줌아웃 처리를 위해서 아래의 코드를 RulerSampleView.h 에 추가 합니다.
CSize m_PageSize;
float m_Zoom;
그리고 RulerSampleView.cpp 에는 아래와 같이 해봅시다.
> 우선 줌 성분 초기화를 생성자 함수에 추가
m_Zoom = 1.f;
> ScrollVew이기 때문에 페이지의 크기를 추가
void CRulerSampleView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
m_PageSize = CSize( 1000, 1000 );
SetScrollSizes(MM_TEXT, m_PageSize);
}
> 드로잉 코드에 m_Zoom을 적절하게 수정해 줍니다.
테스트를 위한 위치값을 10개를 생성했습니다. 이건 코드 보시면 알수 있어요..
드로잉 할때 아래와 같이 처리 합니다.
vector< CPoint >::iterator iter;
for( iter = m_TestData.begin(); iter != m_TestData.end(); iter++ )
{
CRect rect;
rect.left = (*iter).x;
rect.top = (*iter).y;
rect.right = rect.left + 50;
rect.bottom = rect.top + 50;
rect.left *= m_Zoom;
rect.top *= m_Zoom;
rect.right *= m_Zoom;
rect.bottom *= m_Zoom;
pDC->FillRect( &rect, &redbrush );
}
위의 붉은 부분을 m_Zoom으로 곱해줍니다.
> 이렇게 하고 나서 이제 이벤트를 추가해줘야 겠죠.
방향키를 통해서 줌인 줌아웃 성분을 증가 감소 합니다.
void CRulerSampleView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if( nChar == VK_UP )
{
m_Zoom -= 0.1f;
CClientDC dc(this);
m_RulerHorz.CreateDC( &dc, 10000, 20, m_Zoom );
m_PageSize = CSize( 1000*m_Zoom, 1000*m_Zoom );
SetScrollSizes(MM_TEXT, m_PageSize);
Invalidate();
}
if( nChar == VK_DOWN )
{
m_Zoom += 0.1f;
CClientDC dc(this);
m_RulerHorz.CreateDC( &dc, 10000, 20, m_Zoom );
m_PageSize = CSize( 1000*m_Zoom, 1000*m_Zoom );
SetScrollSizes(MM_TEXT, m_PageSize);
Invalidate();
}
CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
}
위의 코드에서 보듯이 Ruler도 줌 성분이 달라지면, Ruler의 줌 성분을 보정해서 메모리 DC를 생성합니다.
그리고 ScrollView의 페이지도 m_Zoom에 따라서 사이즈를 제조정 해줍니다.
이렇게 하면 아래와 같은 프로그램을 만들 수 있습니다.
관련샘플 :
.
.
메모리 DC를 활용한 스크롤바의 Ruler 샘플입니다.
기존의 다른 다이얼로그에 포함시켜서 한 것보다 더 자연스럽네요.
그리고 스크롤 이동시에 잔상이 남지 않아서 더 좋은거 같습니다.
작업한 부분
1. 메모리 DC를 생성
2. 메모리 DC에 해당 Ruler의 크기 정보를 넣어서 미리 다 그려놓는다.
3. 스크롤 이동할때 마다 OnDraw()가 호출되고 그 내부에서 스크롤 포지션 값을 사용해서
BitBlt 해서 처리 한다.
4. 잔상 효과는 OnHScroll(), OnVScroll()를 오버라이드 해서 Invalidate()를 해줘야 됩니다.
실행 파일 :
.
관련 파일 :
.
그중에 가장 좋은건 아무래도 컨트롤 간의 도킹(?) 같은 기능이라고 보여 집니다.
아래의 이미지와 같이 컨트롤을 이동할때 마다 왼쪽, 오른쪽, 위, 아래, 그리고 중앙 에 대해서 실시간적으로 위치를 보정해 주는 기능이 정말 편하다고 생각 됩니다.
이번 툴의 샘플은 위와 같은 기능이 뷰에서도 많이 사용되게 되는데요.
가장 많이 사용되는 건 아무래도 스냅 기능이 아닐까 생각 됩니다.
해당 스냅의 간격에 맞춰서 객체를 이동시키는 방법 입니다.
스냅 구현
스냅을 구현할때 전 아래의 공식을 사용했습니다.
void CDataBox::MoveSnap( CPoint& pos )
{
if( _bEnableSnap )
{
pos.x = pos.x - ( pos.x % _snapValue );
pos.y = pos.y - ( pos.y % _snapValue );
}
}
간단하게 설명을 하면 _snapValue가 스냅의 값이며, pos는 현재 위치를 담는 변수 입니다.
% 연산자를 사용해서 해당 스냅 간격에 대한 나머지를 구해서 현재 포지션에서 빼주는 방법으로 처리했습니다.
스냅을 처리하다 보면 현재 객체의 포지션값을 스냅으로 처리 하게 되면 제대로 동작하지 않습니다.
객체의 값은 항상 스냅이 적용되지 않은 값을 가지고 있어야 한다고 보여집니다.
화면에 보여질때 스냅의 처리를 통해서 보여지는게 조금더 유연하다고 생각 됩니다.
객체 도킹
객체의 도킹은 마우스로 이동할때마다 처리 해야 합니다.
다시 말해서 선택된 객체와 선택되지 않은 객체 간의 검사를 말합니다.
현재 객체의 위치와 다른 객체의 위치를 검사해서 도킹의 리미트 값의 범위 안에 들어왔을때
현재 객체를 대상 객체의 위치로 보정해 주는 방법 입니다.
여기에 더 해서 도킹이 이루어질 대상 객체와의 라인을 그려 주면 더 좋을듯 합니다.
위와 같이 해당 객체의 상태에서 파란선이 나오면서 객체가 같은 Y 축의 위치로 보정 됩니다.
이 소스는 조금 정리가 더 되어도 좋다고 생각 됩니다.
DataBox의 객체 관리 클래스에서 도킹을 담당하지만,
이것을 도킹 관련 클래스를 하나 두어서 작업 하는게 더 좋다고 보여 지네요..
관련 샘플 :
.
윈도우즈 업데이트 할때 일부 문제로 인해서 업데이트가 수행되지 않습니다.
아래와 같이 서비스 종료 후에 업데이트 dll을 등록해 주고 서비스 재시작 해주면 된다.
C:\>net stop wuauserv
C:\>regsvr32 %windir%\system32\wups2.dll
C:\>net start wuauserv
흑백의 이미지를 CxImage로 만들때 8비트, 24비트의 이미지로 만들 필요가 없습니다.
이때 1비트의 이미지로 해도 충분한 공간이 나온다는 얘긴데요.
아래의 코드는 1비트의 이미지를 생성하는 코드 입니다.
void GToleranceImage::MakeBuffer2Image()
{
SAFE_DELETE( _pbuffer2Image );
assert( _pbuffer2Image == NULL );
// 넓이와 폭을 사용해서 이미지 버퍼를 생성합니다.
// 이때 1비트의 이미지로 설정합니다.
_pbuffer2Image = new CxImage( _width, _height, 1, CXIMAGE_FORMAT_BMP );
// 이미지의 팔레트를 지정합니다.
// 흑백 이미지를 만들거기 때문에 0번과 1번 팔레트를 설정합니다.
_pbuffer2Image->SetPaletteColor(0, RGB(0, 0, 0));
_pbuffer2Image->SetPaletteColor(1, RGB(255, 255, 255));
// 해당 내용을 추가합니다.
// SetPixelColor로 하지 않고, SetPixelIndex로 하게 됩니다.
for( int y = 0; y < _height; y++ )
{
for( int x = 0; x < _width; x++ )
{
BYTE color = _bufferXY[y][x];
if( color == 255 )
_pbuffer2Image->SetPixelIndex( x, y, 1 );
else
_pbuffer2Image->SetPixelIndex( x, y, 0 );
}
}
_pbuffer2Image->Flip();
}
x, y 의 포인터 배열을 폴리라인이 형성되어 있을때
그 라인에 대한 옵셋값을 사용해서 포인터를 찍는 샘플 코드 입니다.
확대를 하면 아래와 같은 포인터가 생성되는걸 확인할 수 있습니다.
Left, Right 키를 통해서 옵셋 값을 늘리고 줄이고 할 수 있습니다.
실행 파일 :
.
관련 코드 :
.

RulerSample.exe
TestRulerSolution.zip
Prev
Rss Feed