Tuesday, December 16, 2008

How to Make a Screen Magnifier in MFC


The thought was to make a screen magnifier using a "transparent" MFC dialog and try to calculate its relative position inside the whole screen.

I've spent 2 days on these problem and finally solved it using a MFC CDialog class to simulate a magnifier. The CMagifierDlg is inherited from the CDialog Class and has its own attributs and methods:
int m_nZoom;
CDC *m_pMemDC;
BOOL m_bIsActived;
int m_nH, m_nW; //Screen width and height
HICON m_hIconI; HICON m_hIconO; HICON m_hIconE;

void OwnerDraw();
void SaveScreen();

The UI is like:




And the events are:

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

afx_msg void OnRButtonDown(UINT nFlags, CPoint point);

afx_msg void OnPaint();

afx_msg void OnWindowPosChanged(WINDOWPOS FAR* lpwndpos);

afx_msg void OnTimer(UINT nIDEvent);

afx_msg void OnExit();

afx_msg void OnZoomin();

afx_msg void OnZoomout();


Then, you make a memory DC of the screen and in the OnPaint(CDC *pDC) function, you write:

void CMagnifierDlg::OwnerDraw()

{
CDC *pDC = GetDC();

if (pDC && m_pMemDC)

{ CRect clientRect;

CRect windowRect;

GetClientRect(clientRect);

GetWindowRect(windowRect);
if (!m_nZoom) //ZOOM = 0

{

pDC->BitBlt( clientRect.left, clientRect.top, clientRect.Width(), clientRect.Height(), m_pMemDC, windowRect.left, windowRect.top, SRCCOPY ); }

else //ZOOM > 0

{ int cx, cy, cw, ch;

cx = clientRect.left; cy = clientRect.top; cw = clientRect.Width(); ch = clientRect.Height();

int wx, wy, ww, wh;

wx = windowRect.left; wy = windowRect.top;

ww = windowRect.Width(); wh = windowRect.Height();

//////////////////////////////////////////////////////////////////////////

// Confine the magnifier's movable region in the screen

if (wx <>
{ ww += wx; cx = wx*(-1); cw += wx; wx *= -1; }

if (wy <>
{ wh += wy; cy = wy*(-1); ch += wy; wy *= -1; }

//////////////////////////////////////////////////////////////////////////

// Core algorithm for Magnifier //

int x_ = 0, y_ = 0; //视口原点 P'(x', y')

int w_ = 0, h_ = 0; //视口尺寸 M'(w', h')

int mw = 0, mh = 0; //可移动区域 Sm (m_nW - ww, m_nH - wh)

int mw_ = 0, mh_ = 0; //视口可移动区域,相对于放大镜 Sm' (ww - w_, wh - h_)

double xk = 0.0, yk = 0.0; //放大镜在屏幕中的位置比

w_ = ww / (m_nZoom + 1); h_ = wh / (m_nZoom + 1);

mw = m_nW - ww; mh = m_nH - wh; mw_ = ww - w_; mh_ = wh - h_;

xk = (double)wx / (double)mw; yk = (double)wy / (double)mh;

x_ = wx + (int)(double(mw_) * xk); y_ = wy + (int)(double(mh_) * yk);

StretchBlt( pDC->m_hDC, cx, cy, cw, ch, m_pMemDC->m_hDC, x_, y_, w_, h_, SRCCOPY );

//////////////////////////////////////////////////////////////////////////

}

}
//Draw buttons CRect r,rb; GetWindowRect(&r);
CButton* bt = (CButton*)GetDlgItem(IDC_ZOOMIN);

bt->GetWindowRect(&rb);

int _x = r.Width() - rb.Width() * 3 - 9;

int _y = r.Height() - rb.Height() - 5;

bt->MoveWindow(_x,_y,rb.Width(),rb.Height());

bt->SetIcon(m_hIconI);
bt = (CButton*)GetDlgItem(IDC_ZOOMOUT);

bt->GetWindowRect(&rb);

_x = r.Width() - rb.Width() * 2 - 7;

_y = r.Height() - rb.Height() - 5;

bt->MoveWindow(_x,_y,rb.Width(),rb.Height());

bt->SetIcon(m_hIconO);
bt = (CButton*)GetDlgItem(IDC_EXIT);

bt->GetWindowRect(&rb);

_x = r.Width() - rb.Width() - 5;

_y = r.Height() - rb.Height() - 5;

bt->MoveWindow(_x,_y,rb.Width(),rb.Height());

bt->SetIcon(m_hIconE);
}

No comments:

Post a Comment

(Coding && Eating) || Sleeping