Introduction

Displaying large Bitmap files on a Dialog, in its original size is quite difficult in the VC++ Environment. However, it is possible to display a large bitmap to a predefined area of the dialog using the StretchBlt( ) function. The major disadvantage of this is that some of the image's clarity will be lost. This article explains how to display large bitmaps in the desired area of your dialog in its original size with a scrolling technique used to show the entire bitmap.

Although the primary aim of this article is to display a bitmap with scrolling, it also covers the following three main objectives.

Loading a Bitmap in to the Dialog During Run-time.

Displaying Bitmap in its Original size by using Scrolling technique.

Implementing Flicker free drawing Using Double Buffering technique.

Loading Bitmap in to the Dialog During Run-time:

Sometimes the user may require different bitmaps to be loaded in to the dialog depending on the requirements of his GUI. This can be achieved by calling the LoadImage( ) function. The implementation of this is explained below

Place a Picture control in your dialog. Adjust its size as you wish. Remember, you are going to display the bitmap in this control. Big bitmaps will confine to the entire area of this control with a vertical scroll bar on Right side ( the scroll bar will be displayed if the height of the image is greater than the height of this control) and a horizontal scroll bar at the bottom of this control (the scrollbar will be displayed if the width of the image is greater than the width of this control). Small bitmaps will be displayed at the centre of this control without scrollbars, with equal clearance to the left & right, and top & bottom with respect to the control. So place your control with an artistic touch to give your dialog a nice appearance.

Take the properties of the picture control. Change its ID to IDC_STATIC1 and Type as Frame and Colour as Gray. Also uncheck the Visible check button so that the tick mark is removed from it.

Using Class Wizard, create a control variable of type CStatic for IDC_STATIC1. Let it be m_st1.

This much code will display a bitmap directly on to the picture control during run time. Remember the scrolling capability and alignment adjustments haven't been done yet and so the image will be displayed at the top corner of the Picture control, and if its size is bigger than that of the picture control, it will be clipped to the picture control's size. If the image is smaller than the size of the picture control it will be displayed without clipping, but without centre alignment. The following section describes how scrolling capability and alignment can be achieved.

Displaying the Bitmap at its original size using scrolling

Add a vertical scroll bar control to your dialog and place it touching the right edge of your picture control. Make its length to that of the height of your picture control. Add a Horizontal scroll bar control to your Dialog and place it touching the bottom edge of your picture control. Make its length to that of the width of your picture control.<?p>

Using Class Wizard, create member variables of type CScrollBar for your horizontal & vertical scrollbars. Let them be

You only need to show the scrollbars if the size of the bitmap is greater than that of the size of your picture control. So hide the scrollbars initially by writing the following code in your dialog's OnInitDialog() function.

Four situations arise when you are loading a bitmap in to your pre-defined picture control. They are:

Case 1: Both the width and height of the loaded bitmap is greater than that of the picture control. In such situations both the horizontal and vertical scrollbars are necessary to show the entire bitmap. The bitmap is displayed using the scrolling technique. The vertical scrolling range is equal to the height of bitmap-height of the picture control. The height and width of the bitmap is obtained by the following code, which is incorporated in the code which is needed for displaying bitmaps, which is reproduced here again as:

The maximum vertical scrolling range is m_bmInfo.bmHeight - m_size.cy, and the maximum horizontal scrolling range is m_bmInfo.bmWidth - m_size.cx. Make the horizontal and vertical scrollbars visible by calling

m_hbar.ShowWindow(true);
m_vbar.ShowWindow(true);

Case 2:THe width of the loaded bitmap is greater than that of the picture control and height is equal to or less than that of picture control. In such situations the horizontal scroll bar is necessary to show the entire bitmap. The bitmap is displayed using the scrolling technique. The horizontal scrolling range is given by m_bmInfo.bmWidth-m_size.cx.<?p>

In this case vertical scroll bar is not needed, but for displaying the bitmap centralised with respect to the picture control, the Bitmap should be drawn at an offset from the top corner of the picture control given by

offsety = m_pt.y + ((m_size.cy - m_bmInfo.bmHeight)/2);

Where offsety is the offsetted 'y1' co-ordinate in the (x1,y1) (x2,y2) co-ordinate system and m_pt.y is the original 'y1' co-ordinate.

A clearance of (m_size.cy - m_bmInfo.bmHeight)/2) is also produced from the bottom of the picture control. So the horizontal scrollbar should be shifted up by an amount (m_size.cy - m_bmInfo.bmHeight)/2 using the MoveWindow( ) function as explained below.

m_hbar.MoveWindow(offsetx,offsety+m_bmInfo.bmHeight,m_size.cx,18);

Make the horizontal scrollbar visible and the vertical scrollbar invisible by calling

m_hbar.ShowWindow(true);
m_vbar.ShowWindow(false);

Case 3: The height of the loaded bitmap is greater than that of the picture control and the width is equal to or less than that of picture control. In Such situations the vertical scrollbar is necessary to show the entire bitmap. The bitmap is displayed using scrolling technique. The vertical scrolling range is given by m_bmInfo.bmHeight-m_size.cy.

In this case horizontal scrollbar is not needed, But for displaying the bitmap centralised with respect to the picture control, the Bitmap should be displayed at an offset from the top corner of the picture control given by:

offsetx= m_pt.x + ((m_size.cx - m_bmInfo.bmWidth)/2);

Where offsetx is the offseted 'x1' co-ordinate in (x1,y1) (x2,y2) co-ordinate system and m_pt.x is the original 'x1' co-ordinate.

A clearance of ( (m_size.cx - m_bmInfo.bmWidth)/2) is also produced from the extreme right side of the picture control. So the vertical scroll bar should be shifted left of the right edge of picture control by an amount (m_size.cx - m_bmInfo.bmHeight)/2 using the MoveWindow( ) function as explained below.

m_vbar.MoveWindow(offsetx+m_bmInfo.bmWidth,offsety,18,m_size.cy);

Make the vertical scrollbar visible and horizontal scrollbar invisible by calling

m_hbar.ShowWindow(false);
m_vbar.ShowWindow(true);

Case 4: The height and width of the loaded bitmap is equal to or smaller than that of the picture control. In Such situations the vertical and horizontal scrollbars are not needed to show the entire Bitmap. The Bitmap is displayed centrally, as such, in the picture control. For displaying the bitmap centrally with respect to the picture control, the bitmap should be displayed at an offset from the top corner of the Picture control given by:

Where 'offsetx' is the offseted z co-ordinate, the 'x1' co-ordinate is in the (x1,y1) (x2,y2) co-ordinate system where m_pt.x is the original 'x1' co-ordinate and offsety is the offsetted y co-ordinate, and 'y1' co-ordinate is in the (x1,y1) (x2,y2) co-ordinate system and m_pt.y is the original 'y1' co-ordinate.

Make the vertical and horizontal scrollbars invisible by calling

m_hbar.ShowWindow(false);
m_vbar.ShowWindow(false);

Fill up the SCROLLINFO structure for horizontal scrollbar and vertical scrollbar as given below.

Remember, depending on the requirements of your loaded image, the positions of the scrollbars may be changed. So before displaying another bitmap in to your dialog, release the memory holding the current bitmap and reset the positions of scrollbars to their original location, i.e. to the positions where you placed them during the design of your dialog, by calling

Now your bitmap is ready to be displayed on the dialog with scrollbars (if needed). But still it's not able to scroll to show the remaining portions. We need to handle the WM_VSCROLL and WM_HSCROLL messages to re-draw the bitmap depending on the scroll bar positions for this.

Using Class Wizard, handle WM_VSCROLL and WM_HSCROLL messages and write the following code in their handler.

Now you can scroll your bitmap and the remaining portions of it can be viewed by horizontal and vertical scrolling. Still there exists a problem. The screen will flicker continuously when you scroll the bitmap. Here comes another technique to tackle this problem. The finishing touch to this Project. Nothing but "Double buffer technique for flicker free drawing", which we will adopt.

Implementing Flicker free drawing Using Double Buffering technique

To eliminate flicker in drawing you need to draw everything on a memory DC, and then copy it to the real DC using BitBlt or StretchBlt functions. This technique is called double buffering. The drawing technique used in this article is double buffering. It is explained in the earlier sections. Secondly, you need to override the OnEraseBackground( ) event. The default implementation of this event clears the background of the control with the current value of the BackColor property. However, it is not always necessary to repaint the entire area of the control, and doing so unnecessarily can cause flickering. Bypass the OnEraseBackground( ) event while you re-paint your dialog with InvalidateRect(&rectStatcClient). This can be achieved by signalling a global variable. Declare a global variable of type BOOL, say BOOL erase, and initialise it to false. Map the WM_ERASEBKGND message and override it as

Before you call the InvalidateRect & rectStatcClient functions, set the variable 'erase' to true. Now OnEraseBkgnd( ) is bypassed.

Reset 'erase' flag to false at the end of your OnPaint function. This will remove the bypassing of OnEraseBkgnd(pDC) event and the background will be erased when WM_ERASEBKGND is sent by other events other than InvalidateRect( &rectStaticClient ).

I hope that you are now able to draw a bitmap with scrolling capability in your dialog. Go through the demo project and learn more from it.

NOTE: This code has been tested on the Windows 2000 platform and it is found to work properly. Your valuable suggestions and corrections are always welcomed. Refer to the MSDN Documentation for more details on 'Double Buffering', 'MoveWindow( )' and 'BitBlt()'.

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.

hi I did that and it worked but now I have another problem.I have a global variable of that bitmap class in my main dialog class and I have a button in my main dialog whitch has dialog2.domodal();but when I run the program and press the button and close dialog2 and press the button for second time it cause an error which I think is for initializing the class for just one time.how can I init it every time I use the button on main dialog,it doesent let me to call its oninitdialog().thank you so much for your previous answer.

HiI used this code to have a bitmap in my project.I'm new in VC6 and I need to use this bitmap in another class(an other Dialog) not in my main dialog and I don't know how to write the codes which are in the functions like onPaint() or onInitDialog().please help me and tell me where I should write them in my project.

Hi,I hope you know how to add a new dialog box to an existing project. Once the dialog box is added, take the class wizard and select the name of the dialog class from the 'Class name' selection combo box. Ensure that you are in the 'Message Maps' tab of the 'Class Wizard' dialog box. From the 'Member functions:'list box select 'OnInitDialog' & 'OnPaint'functions and press the 'Add Function' button. This will create the required function body in the .cpp file for your dialog class. Hope this will solve your problem.

After seeing your articles, i thought, why cant i ask you about my requirement. Acctually i have to gather an image from the clipboard and i have to get all its details, like its length,breath,no.of pixes,and other details.and i have to convert all the details into an array.

i could able to gather the image from clipboard. and then i got struck while gathering its details. and my code goes like this:

Pls let me know the error you are getting while loading the image. I guess it happens due to the in sufficient memory. From the resolution of the image itself it is obvious that the image size will be too high. Also let me know the size of the image you are trying to load.

error C2065: 'm_size' : undeclared identifiererror C2228: left of '.cx' must have class/struct/unionerror C2228: left of '.cy' must have class/struct/unionerror C2065: 'm_pt' : undeclared identifiererror C2228: left of '.x' must have class/struct/unionerror C2228: left of '.y' must have class/struct/union

I'm getting these errors in OnPaint; I think U have to explain better on the displaying technic!!!

Why are you only handling 3 events? The windows CSCrollBar class has 11. I'm especially suprised you didn't handle SB_LINEDOWN. Do you not expect the user to hit a down arrow? This article is very overrated IMO.

From a Sun Microsystems bug report (#4102680): "Workaround: don't pound on the mouse like a wild monkey."

Displaying all is out of the scope of this work. Why don't you try handling the rest. You can never blame the author. The Author has presented a good idea in a neat manner. If it is not meeting your need it's your responsibility to tailor it for your needs. The author is not written the article for you alone. It's for the entire developers. Author's can never satisfy all kinds of readers. Under rating an article just because of the reason that it does not satisfy your needs is not fair. Whatever missing you add it as a value addition to the code so that whole developers can make use of it. Your question is already answered by Okeno Palmar in the FAQ with title "Well Done + Code" http://codeproject.com/bitmap/bmpscroll.asp#xx732666xx

Every CWnd has scrolling functionality built-in. But I can't figure out if it is possible to use it. While calling m_myStaticFrame.SetScrollInfo( SB_VERT, ... ) and m_myStaticFrame.EnableScrollBarCtrl( SB_VERT ) is enough to show the vertical scrollbar, it simply doesn't behave as if it is enabled. Creating the static frame with SS_NOTIFY style has no obvious effect. The article at http://www.codeproject.com/staticctrl/staticctrl_tut.asp suggests only limited messages are supported in a CStatic.

I've seen this question asked in other places over the past 2-3 years... but with no answers. Can anyone confirm it one way or other?

Thank you for the great article!Let me make tiny remark.Actually, to prevent background erasing after InvalidateRect(..)we just need to pass FALSE as second parameter:InvalidateRect(&rectStaticClient,FALSE); Thus additional variable erase is not necessary and code becomes neater.

Can i ask for anyone help to have a Bitmap Display with Scrolling in the additional dialog boxes of my application...i tried doing alot of time but fail...Can anyone feedback to me onhow the programming might be like??Thank you

Is it possible to add a bitmap image onto the view window with scrolling facility. I tried doing it by deriving the view class from CScrollView class but could program the scrollbar correctly.Please help

Thanks alot for this contribution, really help me out with an app I'm doing. Just to add to your code, if you want to be able to click in the scrollbars and have teh image scroll till that position is reached add the following to the SCROLLINFO setup in OnShow():

horz.nPage = m_bmInfo.bmWidth / m_size.cx;

Also to get full functionality in the OnHScroll(), I adapted this code from the MSDN help:

Hi, I have developed a dialog based application in which i have an static control, on this static control i am placing a bitmap through SetDIBitsToDevice() function. In else part of OnPaint() i am calling the bitmap displaying function. I am facing a problem while painting. after executing the application if i activate another window and minimize that window, the bitmap gets washed. If i activate a window that is smaller than the bitmap size then only the part that is covered with the activated window gets washed when i minimize the newly activated window. I am not able to target the problem.

Hi, I have developed a dialog based application in which i have an static control, on this static control i am placing a bitmap through SetDIBitsToDevice() function. In else part of OnPaint() i am calling the bitmap displaying function. I am facing a problem while painting. after executing the application if i activate another window and minimize that window, the bitmap gets washed. If i activate a window that is smaller than the bitmap size then only the part that is covered with the activated window gets washed when i minimize the newly activated window. I am not able to target the problem.

Hi this paper is a good job,but i has a question.in practical condition, we must preview an opened image in a dialog(such as D/C adjustment dialog),then how can we get the handle of the image to realize the same function as u talk here? please teach me. i'm a freshman.

yes! i want preview the effect of brightness and contrast adjustment,and when press "OK", return the processed image. since the image is open not as a resource,and not through filename,how can i load it into the dialog? thanks

I think the answer to this question is available from the help topic on MoveWindow()in MSDN Help for Visual C++. If you change that parameter you can see that the width of the scroll bar also getting changed in accordance with the change in that parameter. I think you are experimenting on the topic. Nice i appreciate you for ur research mentality

How come you don't need to delete either of the HBITMAPS at the end of the app, I know one h_BmpNew gets deleted every time OnShow is called, but when the app finishes it is still selected.And what abot h_BmpOld?

Whenever a windows based application quits by normal procedure, all resources including memory will be released automatically. hence it may not create any harms even if the resource is not freed explicitly.

I got a bitmap displayed in the client area of my window.The bitmap fills the client area in 800x600 display setting.But in 1024x768 the client area increases and the bitmap does'nt fill the client area. How can I solve this problem?

I tried to implement your code, and everything worked great except one error. My only problem is that in my OnPaint (copied mostly from your page)the last line, CDialog::OnPaint();, gets an error saying that it can't access a protected member:error C2248: 'CDialog::OnPaint' : cannot access protected member declared in class 'CDialog'

I have everything working except that I'm bothered that the scrollbars aren't painted the "XP" way as all my other scroll bars are. By this I mean that in all my other dialog boxes, my scroll bars are displayed according to my XP System settings (green, stylized etc) but these 2 scrollbars are just gray.

More importantly, how can I make these scrollbars listen to the mouse wheel scrolling, clicks on the top or bottem arrow of scroll bar, and clicking in the blank space in the bar area?/dylandlorimer@cyrano.com

your messages is two months old now, but I'm gonna answer anyway, because I just stumbled over this article when looking for the answer to a problem, and I found it very helpful.

First of all, the scrollbar style has to do with the way you insert the control into your project. If you are using VC++ 6.0 and insert a scrollbar into a dialog, it uses the scrollbar control the came with VC++ 6.0 (which looks like the old gray scrollbar you have right now). If you want to use XP style scrollbars, you have to insert a different scrollbar control. I haven't done this yet, but my guess is that you either need to get the XP scrollbar control (ActiveX object or .ocx or something like that) and insert that one into your program, or (more probably) you have to access some DLL where you can instantiate the scrollbar from that fits your operating system, scheme, color settings etc.

I have a more precise answer to your second question, though: In WINUSER.H you can find all scroll bar commands that can be handled by your message handler for the WM_HSCROLL event:

The message handler in the given program listing only takes care of TOP, BOTTOM and THUMBTRACK commands, if you also want to respond to left/upper and right/lower arrow and the free space in between, you also have to take care of the respective LINELEFT (left arrow), LINERIGHT (right arrow), PAGELEFT (free space left from thumbnail) and PAGERIGHT (free space right from thumbnail)commands, set your thumbnail positions, and invalidate the bitmap.

Note: As you can see most of the values have two definitions, because the same values are sent for horizontal and vertical scrollbars, but you can use the right defines in your code to make it more readable.

For the horizontal scrollbar, the following additional case lines would give the scrollbar the behavior you are used from it:

You have to play around with the +1 and -1 values a bit, this would move your bitmap by only one pixel, which is really slow. A value of 3 or 5 might be better.

The third question with the mouse wheel is a different story. The mouse wheel is not connected to a control, for example in most programs the mouse wheel will do the same in every position of the window. So you have to handle the respective WM_MOUSEWHEEL event and see which control your mouse is over when the wheel was used (you only need that if you have more than one vertical scrollbar, for example in a split window situation). With that information you have to fire WM_VSCROLL event yourself that takes the appropriate action. I think that also explains why the mousewheel behaves differently in for example Internet Explorer and Notepad. In Notepad the mousewheel just fires a LINEDOWN or LINEUP event, just as if you clicked on the up or down arrow. But in Internet Explorer (if you have smooth scrolling activated) the contents of the screen is moved (BitBlt-ed) and the position of the scrollbar is adjusted accordingly.

Sorry for the lengthy answer, I hope you can find the valuable bits in it for you!