Click here to Skip to main content
15,884,298 members
Articles / Desktop Programming / MFC
Article

A C++ OCX for drawing pictures on any window of your Application

Rate me:
Please Sign up or sign in to vote.
3.00/5 (5 votes)
7 Nov 20022 min read 105.3K   2.9K   29   14
The control overwrites the windows event handler to overtake the paint event.

Introduction

This OCX gives you the possibility to zoom any picture you like on any window of (at least) your application. There are three major parts, namely loading the desired picture, re-direction of the Windows Event Handler and drawing the picture.

Windows NT, Windows 2000 and Windows XP do only allow an application to overwrite the Windows event handler of an own window. The example is more or less self explaining. The picture is loaded using OleLoadPicture(). The picture will be drawn using the Windows standard graphic API function strechblt().

To supersede the Windows event handler, SetWindowLong() is used.

Details

The drawing routine

The main drawing is done within the ondraw method. In case that the OCX should draw on other windows than itself, it will call ondraw directly.

As the OCX is generated using MFC, the method header is standard and has been automatically generated:

void CPictureZoomCtrl::OnDraw(
  CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)

PictureZoom is using a flag to identify whether a picture has already been loaded or not:

if (m_bNoPicture)
  return;

The first step is to create a compatible DC which needs to hold the picture:

CDC mdc; // memory DC
mdc.CreateCompatibleDC(pdc);
CBitmap* pOld = mdc.SelectObject(&m_Picture);

To prevent disturbing colors when drawing a stretched or shrunken picture, set the color mode properly:

pdc->SetStretchBltMode(COLORONCOLOR);
mdc.SetStretchBltMode(COLORONCOLOR);

In order to work with the picture, we needs its dimension:

m_Picture.UnrealizeObject();
BITMAP BM;
m_Picture.GetBitmap(&BM);

The next parts are a little tricky as we need to discern between 3 ways of displaying the picture. The first is to draw it without keeping the aspect ratio of the original picture:

if (!m_bAspectRatio)
  pdc->StretchBlt(0, 0, rcBounds.Width(),
    rcBounds.Height(),&mdc, 0, 0,
    BM.bmWidth, BM.bmHeight, SRCCOPY);

The next block differs between the other two cases:

else
{
  double Strech = double(rcBounds.Width()) / double(BM.bmWidth);
  int iHeight = Strech * BM.bmHeight;
  int iWidth = Strech * BM.bmWidth;

  int yMove = ((iHeight - rcBounds.Height()) / 2) / Strech;

The first of these other two cases is that the picture needs to be cut at the top and bottom to draw it in a zoomed way over the whole given window. The first step to do so is to calculate the upper left corner on the source (unscaled!) bitmap:

if (yMove >= 0)
{
  // Strech for width
  int xp = -m_xAdd;
  int yp = yMove - m_yAdd;

  if (xp < 0)
    xp = 0;

  if (yp < 0)
    yp = 0;

  if (xp > iWidth - rcBounds.Width())
    xp = iWidth - rcBounds.Width();

  if (yp > (iHeight - rcBounds.Height()) / Strech)
    yp = (iHeight - rcBounds.Height()) / Strech;

Now as I was a little unsatisfied with center-only display of pictures, I decided to allow some alignment-settings as well:

if (m_Align == TOP)
  yp = 0;
else if (m_Align == BOTTOM)
  yp = (iHeight - rcBounds.Height()) / Strech;

m_xAdd = -xp;
m_yAdd = yMove - yp;

The last step in case one is to simply blit the Source-Rectangle on the target window using strechblt():

  // Blit only on the rectangle that is invalid
  CRect SourceRect((rcInvalid.left * BM.bmWidth) /
    rcBounds.Width() + xp,
    (rcInvalid.top * (rcBounds.Height() / Strech)) /
    rcBounds.Height() + yp,
    (rcInvalid.right * BM.bmWidth) / rcBounds.Width()
    + xp, (rcInvalid.bottom * (rcBounds.Height() /
    Strech)) / rcBounds.Height() + yp);
  pdc->StretchBlt(rcInvalid.left, rcInvalid.top,
    rcInvalid.Width(), rcInvalid.Height(),&mdc,
    SourceRect.left, SourceRect.top,
    SourceRect.right - SourceRect.left,
    SourceRect.bottom - SourceRect.top, SRCCOPY);
}

The second case is more or less equal to the step before. The only difference is that the picture will now be truncated on the left and right hand-sides. This happens, when the window on which to draw has a proportion less than 1 (seen as width against height).

else
{
  Strech = double(rcBounds.Height()) / double(BM.bmHeight);
  int iHeight = Strech * BM.bmHeight;
  int iWidth = Strech * BM.bmWidth;

  int xMove = ((iWidth - rcBounds.Width()) / 2) / Strech;
  int xp = xMove - m_xAdd;
  int yp = -m_yAdd;

  if (xp < 0)
    xp = 0;

  if (yp < 0)
    yp = 0;

  if (xp > (iWidth - rcBounds.Width()) / Strech)
    xp = (iWidth - rcBounds.Width()) / Strech;

  if (yp > iHeight - rcBounds.Height())
    yp = iHeight - rcBounds.Height();

Again, I decided to allow some alignment (to the left or right border of the window):

    if (m_Align == LEFT)
      xp = 0;
    else if (m_Align == RIGHT)
      xp = (iWidth - rcBounds.Width()) / Strech;

    m_xAdd = xMove - xp;
    m_yAdd = -yp;

    // Blit only on the rectangle that is invalid
    CRect SourceRect((rcInvalid.left *
      rcBounds.Width()/Strech) / rcBounds.Width() +
      xp, (rcInvalid.top * BM.bmHeight) / rcBounds.Height()
      + yp, (rcInvalid.right * rcBounds.Width()/Strech)
      / rcBounds.Width() + xp, (rcInvalid.bottom * BM.bmHeight)
      / rcBounds.Height() + yp);
    pdc->StretchBlt(rcInvalid.left, rcInvalid.top,
      rcInvalid.Width(), rcInvalid.Height(),&mdc,
      SourceRect.left, SourceRect.top,
      SourceRect.right - SourceRect.left,
      SourceRect.bottom - SourceRect.top, SRCCOPY);
  }
}

The last step of drawing is to free all used resources:

  mdc.SelectObject(pOld);
  mdc.DeleteDC();
}

This article will be continued in the next days as soon as there is more time between work and studies.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Austria Austria
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralWM_ERASEBKGND Pin
venrag2-Jan-06 22:35
venrag2-Jan-06 22:35 
Question[Message Deleted] Pin
venrag19-Dec-05 19:16
venrag19-Dec-05 19:16 
AnswerRe: PostMessage Pin
Romout19-Dec-05 21:02
Romout19-Dec-05 21:02 
GeneralRe: PostMessage Pin
venrag19-Dec-05 21:28
venrag19-Dec-05 21:28 
GeneralCompiling problems Pin
FlyingDancer28-Jun-05 16:51
FlyingDancer28-Jun-05 16:51 
GeneralRe: Compiling problems Pin
Romout28-Jun-05 21:25
Romout28-Jun-05 21:25 
QuestionNothing More ? Pin
Maximilien7-Nov-02 8:44
Maximilien7-Nov-02 8:44 
AnswerI agree Pin
Jonathan de Halleux7-Nov-02 8:46
Jonathan de Halleux7-Nov-02 8:46 
GeneralRe: I agree Pin
Chopper8-Nov-02 0:23
Chopper8-Nov-02 0:23 
GeneralRe: I agree Pin
Maximilien8-Nov-02 2:40
Maximilien8-Nov-02 2:40 
GeneralRe: I agree Pin
Chopper8-Nov-02 2:42
Chopper8-Nov-02 2:42 
GeneralRe: I agree Pin
Maximilien8-Nov-02 2:49
Maximilien8-Nov-02 2:49 
GeneralMaybe a solution Pin
Romout8-Nov-02 2:52
Romout8-Nov-02 2:52 
GeneralRe: Maybe a solution Pin
Stephane Rodriguez.8-Nov-02 4:15
Stephane Rodriguez.8-Nov-02 4:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.