Tag Archives: image viewer

Overlay Drawing in CScrollView – Part 2

As shown in the previous article, drawing in a fixed position on a scroll view rises some problems. We thought at tree possible solutions:

  1. Use layered windows. This is quite good but relatively complicated and still rises problems, especially in MDI applications. By curiosity or just for fun, you can download a demo here: Overlay text in MDI using layered windows.
  2. Get rid of CScrollView and directly derive from CView. This may be a good/professional solution but implies a lot of work, “reinventing the wheel”.
  3. Derive from CScrollView, and override the necessary virtual methods in order to modify the default behavior according to our needs.

Finally, I chose the option #3, by implemeting an MFC-extension class, CImageView, derived from CScrollView. Additonally, I made a class CImageDoc to be used togheter with CImageView in a document-view architecture (MDI/SDI MFC project). To make a simple image viewer with overlay drawing capability, you simply have to derive from these classes. Note that, CImageView has additional built-in features like image zoom-in, zoom-out, and zoom to selection, dragging image with the mouse, and so on.
Next is a brief list of public and virtual methods, to be used according to your needs.

CImageView class

  • CImageView::SetBackPatternBrush – sets a background brush based on a bitmap.
  • CImageView::SetBackSolidBrush – sets a background brush based on a solid color.
  • CImageView::SetHandCursor – sets “hand” cursor, used when user begins dragging the image.
  • CImageView::SetHandDragCursor – sets “hand drag” cursor, used when the user is dragging the image.
  • CImageView::ZoomIn – increments the image zoom.
  • CImageView::ZoomOut – decrements the image zoom.
  • CImageView::ZoomToOriginalSize – displays the image in its original size.
  • CImageView::ZoomToWindowWidth – fits image to the view’s width.
  • CImageView::ZoomToWindow – fits the image in the view.
  • CImageView::ZoomToRectangle – (virtual) can override the default type of “zoom to selection”.
  • CImageView::DrawBackgound – (virtual) can override the backgound filling mode.
  • CImageView::DrawImage – (virtual) can override the default image drawing mode.
  • CImageView::DrawOverlay – (pure virtual) override is mandatory; it is designed for “overlay drawing”, according to each application requirements.

CImageDoc class

  • CImageDoc::GetImage – returns a reference to contained source bitmap.
  • CImageDoc::IsValidImage – returns TRUE if the source bitmap is valid.
  • CImageDoc::GetImageSize – returns the source bitmap sizes.
  • CImageDoc::LoadFromFile – (virtual) load the bitmap from a BMP file. Can be overridden if for example, instead of LoadImage WinAPI function we are using something else, whichallows loading more image file formats (JPEG, GIF, TIFF, PNG, etc).

Demo project

The demo project is a simple image viewer with overlay drawing capability. For demo purpose, it draws over the source image a text and an animated image.

Overlay Drawing - Demo Project

Image Viewer with overlay drawing – Demo project

To make something similar, you just have to:

  1. Download the demo project.
  2. Add to your project the definition and implementation files (.h and .cpp) for CImageView, CImageDoc, and CMemDC classes.
  3. Derive your own classes form CImageView and CImageDoc (as in demo project are CDemoView and CDemoDoc).
  4. Override CImageView::DrawOverlay to perform your own custom overlay drawings.
  5. Do anything else as shown in the demo project. .

If something is unclear, as well as for any remark or recommendation, please do not hesitate to leave a reply

See also

Downloads

Overlay Drawing in CScrollView – Part 1

The problem

If we want to make a simple image viewer with scroll capability, CScrollView MFC class is great. Let’s say, we have a CBitmap object in the document class, that keeps the image to be displayed. All we have to do in the view’s class (derived from CScrollView) is something like this:

  1. Override CScrollView::OnUpdate virtual function and set the scroll sizes according to the image sizes.
  2. Override CScrollView::OnDraw virtual function and draw the image.

No sweat, like a walking in the park! Of course, we can further improve it by adding more features, like image zoom and so on.
Now, let’s say, we have to draw a text over the image in a fixed position. One first attempt would be to simply draw the text in view’s client area, after the bitmap has been bit-blitted, like in the next example:

It is not working OK: when scrolling the view, some weird “effects” occur. Let’s see a little “movie” that shows what happens when the user scrolls the view.

  1. Let’s say we have loaded and displayed a bitmap. Additionally, using the code from above examples, we wrote a little text in the top-left corner of the view.

    Before ScrollWindow

    Before ScrollWindow

  2. When the user clicks in the vertical scrollbar, the view window receives WM_VSCROLL message with SB_PAGEDOWN scroll-bar code. If put a breakpoint in the beginning of OnDraw, the image looks like this:
    After ScrollWindow  and before OnDraw

    After ScrollWindow and before OnDraw

    Somewhere in CScrollView implementation, the ScrollWindow function has been called. That simply shifted up the contents of the view. The remained area from the bottom side is invalidated in order to be further drawn in WM_PAINT message handler (in case of views, OnDraw virtual function).

  3. Finally, when OnDraw function is done, we get this:

    After OnDraw

    After OnDraw

Hmmn…the text has been moved up, even in OnDraw we’ve tried to put it back at the same coordinates. That’s because ScrollWindow moved up the area which contains the text. Besides, the area containing the text was not invalidated, so TextOut did nothing. Of course anyone can say: “it’s easy from now, just invalidate the whole view’s client area, somewhere at the end of scroll message handler”. Yes, may be a little bit better but still not OK. When scrolling, the text will “jump” and flicker.

In CODEPERT forum, we discussed different ideas for overcoming this problem, including the using of layered windows (that works quite fain but still rises some issues). Next time, I’ll show the best solution we found. Just keep in touch!

Resources

See also