Navigation Bar

11 November 2013

[ MFC ] - Creating custom Mapping Mode in Visual C++ using MM_ISOTROPIC

1. Introduction


In the previous MFC Article, we examined how the Mapping Modes works while performing the drawing operation. In this example, we will see how do we set the custom mapping modes. Out goal is below:
1) Set mapping mode so that the horizontal logical unit is 1 cm. Simply, 1 Unit = 1 c.m in X axis
2) Also, 1 Unit = 1 c.m in Axis.
3) Positive X is towards left
4) Positive Y is going Upwards
5) The Drawing origin should be in screen center


2. The Custom Mapping Mode


To achieve the above we need to use the Custom Mapping mode. From the previous article, you may now know that the mapping modes MM_ISOTROPIC, MM_ANISOTROPIC are custom mapping modes. In MM_ISOTROPIC mode, both X and Y-axis represents the same unit of measure. That is if X-axis represents 1 logical unit as 1 m.m then Y-axis also represent 1 logical unit as 1 m.m. In our example, we are going to use the MM_ANISOTROPIC mode.


3. About the Example


Have a look at the below depiction:




We are going to draw X Axis and Y Axis and then draw an ellipse. The ellipse will have 8 cm major axis and 4 cm minor axis when measured after having the hardcopy. So to achieve this drawing, we should set a mapping mode that will see one unit as 1 centimeter. Also, note that the Origin should be at the center of the screen.

OK. Let us walk through how do we create this example.


4. Coding the Example


1) Create a Single document interface application (SDI) and in the OnPaint Handler, we are going to perform the drawing specified above. First, we need to set the mapping mode as ISOTROPIC and ANISOTROPIC. In this example I specified the ISOTROPIC mapping mode as both X and Y-axis has the same unit of measure that is 1 logical drawing unit is 1 centimeter. Below is code that set the mapping mode:

CPaintDC dc(this); // device context for painting
dc.SetMapMode(MM_ISOTROPIC);


2) Once the mapping mode is set the screen resolution in terms of mm is returned using the GetDeviceCaps function by passing the HORZSIZE, VERTSIZE. The size returned in mm is based on the current resolution. The screen size in mm is stored in the variables width_in_mm and height_in_mm.

//Sample 01: Returns the Dimension in MM
int width_in_mm = dc.GetDeviceCaps(HORZSIZE);
int height_in_mm = dc.GetDeviceCaps(VERTSIZE);

The picture shown below tells that the 1 pixel is represented as 0.3525 mm approximately.

3) Once we have Screen resolution in mm, we need to get the screen resolution in pixels. We use the same GetDeviceCaps function to get the screen resolution in pixels. Below is the code:

//Sample 02: Return the dimension in pixels
int width_in_pixels = dc.GetDeviceCaps(HORZRES);
int height_in_pixels = dc.GetDeviceCaps(VERTRES);

4) Have a look at the below picture:
From the above picture you can see how the Window and "Viewport Extends" works together. Imagine that the gray lines 1 unit and 1 unit is one pixel. The Red line shows how the window is divided by logical measure, say, for example, imagine like this, the screen dimension of 7x5 mm is divided as 4 horizontal extends and 3 vertical extends. This same technique can be used in the below-given code.

//Sample 03: How the screen divided in terms of Logical Units.
//For Example, if horz size returned is 500 mm,
//the window is divided into 50 logical extents.
dc.SetWindowExt(width_in_mm/10, (-1 * height_in_mm)/10); // 10 MM = 1 Unit or 1 CM = 1 Unit

//Sample 04: How the screen divided in terms of pixels
dc.SetViewportExt(width_in_pixels, height_in_pixels);

In the above code we specified the following unit of measures:
Device Coordinate system’s unit of measure is done by the SetViewportExt function call. Let us say the resolution is 800x600, so the screen is divided as "800 extents" horizontally and "600 extents" vertically. That means each unit represents pixels; for example, if I say 10 unit in device coordinate then it is 10 pixels. For same 800x600 resolution, the screen size measured is 282x212 mm. Now, using the SetWindowExt function call, we divided the screen width as 28 extents and screen height as 21 extents. This way each unit measures 1 cm in the logical unit (Put down your calculator and I agree there is a slight precision loss).

OK. What is the importance of specifying the extents? Let us start with a detailed explanation that may help you understand the coordinate transformation in terms of Pixels versus Logical units. From the above picture, the Device Coordinate System uses the gray lines and the Logical Co-ordinate system uses Red lines as a unit of measures. MFC Framework and Win32 API uses both the coordinate systems. For example, the WM_LBUTTONUP uses the device coordinate system to specify the mouse cursor location in terms of (x, y) pixels. Whereas, the drawing functions exposed by the CDC (Device Context) expects the Logical coordinate system. Now, think how a user can draw a 10 cm line by using the mouse.

In this case, a coordinate conversion is required. Your code may go like this:
1) The mouse events capture the Line start and end
2) Start point and end points are converted to Logical unit from Device unit
3) These converted points (Dimensions) passed to the Line Drawing functions

Note that at the first step itself showing the line dimension (In logical unit) helps the user to draw 10 cm line. Now you may have an idea of coordinate space conversion. Two kinds of conversion are possible and they are:
a) Device Space to Logical Space
b) Logical Space to Device Space

In my previous article I specified that except MM_ISOTROPIC and MM_ANISOTROPIC, all co-ordinate have the valid mappings. These two mapping modes are custom mapping modes and that means you decide the mapping between Logical and Physical unit. I am moving to the next coding part and at the end of the article, we will derive the coordinate transformation formula.


5) Next, we shifted the viewport origin towards the center of the screen. Below is the code for it.

//Sample 05: Set Viewport Orgin to the Screen Center
CRect rct;
GetClientRect(&rct);
dc.SetViewportOrg(rct.right/2, rct.bottom/2);


6) Once the drawing origin is shifted to the screen center, the x-axis and y-axis are drawn using the MoveTo, LineTo functions. Next using the device context an ellipse is drawn to the screen. Now all the units specified here are in Centimeter.

//Sample 06: Draw the Axis
dc.MoveTo(-10,0);
dc.LineTo(10,0);
dc.MoveTo(0,-8 );
dc.LineTo(0,8);

//Sample 07: Draw the Ellispse
dc.Ellipse(0, 4, 8, 0);


 Source Code : Download



13 August 2013

[ MFC ] - Mapping Modes in VC++ Explained with SetWindowOrg, SetViewPortOrg

1. Introduction


MFC supports two kinds of coordinate systems. One is Device coordinate and the other one is Logical Co-Ordinate. In device coordinate, we specify everything in terms of pixels. In logical coordinate, we measure each unit in terms of Metric standard or British standard. How each unit maps to the logical measure is called the mapping. We can specify the mapping using the mapping modes.

In this article, I will walk you through the examples and explanation videos, which will help you in understanding the Mapping modes and performing the drawing using the device contexts. I will also help in understanding the ViewPort Origin and Window Origin.


2. Create SDI Application


The first step is creating the SDI Application without any document view Architecture support. Once the application is created, you can start your drawing using the OnPaint() handler. OK, Have a look at the below picture:



In the above depiction, the black screen is the desktop (Hided the Icons) and top left corner of the desktop (shown as P1) is the origin of the screen coordinate. The notepad application is displayed on top of the desktop(Screen) area. Point P2 specifies the origin of the notepad window or we can say that P2 is the origin of the window coordinate system. If there are three windows in the desktop area, then three such window coordinate exits (one for each window). The client area of the window is nothing but the working area of the window. In the case of the notepad, the actual working area is the portion of the window in which we actually type our textual content. Point P3 specifies the Origin of the client coordinate system. In all these coordinate systems we use the device coordinate meaning that the location and sizes are specified in terms of pixels.

We will talk more about the device coordinate in detail in some other article. But in the below piece of code, I will start with the client coordinate and then will move to mapping mode and logical coordinate based drawing.

CRect rct;
GetClientRect(&rct);

When you run the SDI application it looks like below (Resized):




The screen marked in blue is termed as client area of the window. The GetClientRect function will help in getting the rectangular marked as blue in the above depiction. We get four values left, top, right and bottom and this is also shown above. Look at the below video that debugs and examines value after calling GetClientRect() function.

3. Mapping Modes


The mapping modes are useful to perform the real world drawing. Say for example; let us say the software utility you are making is useful to perform an engineering drawing. When the drawing is printed out, you want to see the 10 mm line drawn in your monitor, measured exactly as 10 mm in the hard copy, taken from the printer. In this case, we need a way to represent how a single drawing unit measures to the real world measuring standards. MFC supports eight mapping modes which are shown in the below-specified picture:



For MM_TEXT mapping mode, the positive X moves from the default top left corner origin, to the right side. MM_ISOTROPIC and MM_ANISOTROPIC have a user-defined coordinate system. In MM_ISOTROPIC both x, y units are measured equally. But in the MM_ANISOTROPIC mode X and Y can have different units of measure. The above picture also shows for a given "mapping mode" how a single logical unit is measured. The MM_TEXT mapping mode is the default mapping mode used by MFC. Using the SetMapMode function of the underlying Device Context, you can pick any one of the mapping modes shown above.

4. Drawing a Line using mapping Modes


In the OnPaint handler, let us draw a line using MM_TEXT mode. Remember from the previous picture that each unit you specify to the drawing function represents a pixel. For an example, if the length of line 100 means, it is 100 pixels long as the mapping mode is MM_TEXT. Next thing we should remember is that the origin is in the upper-left corner of the window and positive Y goes down. So to see something when you draw, you should specify both x, y units in positive (Look at the picture for reference). OK, let us start drawing the line. Have a look at the below code:

//Sample 02: Draw Lines and see where the Origin is.
dc.MoveTo(0,0);
dc.LineTo(100,100);

In the above code, first, we moved the drawing pen to the Origin 0,0. Then asked to draw the line by specifying the end point as 100,100. When you run the Example you will see a line from origin 0,0 to the point at 100,100. This can be illustrated something like the below one:


For More explanation look at the video: 



What happens if I change the mapping mode from the default MM_TEXT to MM_LOMETRIC? The first thing one should be aware is that the Unit of measure changes from pixels to a millimeter. The second thing is that the Positive Y axis shifts its direction. Below is the Example that uses the MM_LOMETRIC as the mapping mode.

//Sample 03: Set New Mapping Mode
dc.SetMapMode(MM_LOMETRIC);
dc.MoveTo(0,0);
dc.LineTo(100,-100);
For More explanation look at the video: 


5.  Shifting the Origin using SetViewPortOrg


In the previous examples, we saw that how can we set the mapping modes on the device context. Also in the previous examples, the drawing origin is kept in the top left corner of the window, which is default origin. Device context has the capability of changing the origin from the default left corner using the SetViewPortOrg function call.
This function expects the new location in terms of pixel and shifts the drawing origin from top left corner to the new location. Have a look at the below code:

//Sample 01: Client Rectangle.
CRect rct;
GetClientRect(&rct);
//Sample 04.1: Shift the Origin to Screen Center
dc.SetViewportOrg(rct.right/2, rct.bottom/2);

In the OnPaint() handler, first the Origin is shifted from the top left corner to the center of the window. The rct is the CRect object, which has the Client Area dimension in device Co-Ordinate. So we specify the center of the client area in terms of a pixel to the SetWindowOrigin. Below is the picture which shows the shifted Origin:


The code in effect is shown in the above picture. The Red one is the origin before the shift and the blue one is the origin after the shift. Remember, again that we specified the new origin in terms of pixels. In the below code a blue pen is created and then a line is drawn. As there is no mapping mode set yet, the device context takes MM_TEXT as the mapping mode.

//Sample 04.2: Draw a blue Line MM_TEXT
CPen pen(PS_SOLID, 2, RGB(0,0,255));
CPen* OldPen = dc.SelectObject(&pen);
dc.MoveTo(0,0);
dc.LineTo(100,100);

After drawing the blue line, the red line is drawn in the MM_LOENGLISH mapping mode. At this stage, since you have gained a good idea of mapping modes, I am not going to explain that once again.

//Sample 04.2: Draw a Red Line using MM_LOENGLISH
dc.SetMapMode(MM_LOMETRIC);
CPen pen1(PS_SOLID, 10, RGB(255,0,0));
dc.SelectObject(&pen1);
dc.MoveTo(0,0);
dc.LineTo(100,100);
dc.SelectObject(OldPen);
Now running the entire code makes your drawing look like the one shown below:


For More explanation look at the video: 


6. Using the SetWindowOrg


At this stage, you know what the SetViewportOrg does. In a short summary again, the SetViewPortOrg sets the drawing origin by specifying the values in terms of pixels. The SetWindowOrg function set the given logical point as Lower Left Corner of the client Area Window.

Note the difference, View Port Origin is specified in terms of pixels and Window Origin is specified in terms of Logical units, which depends on the currently set mapping mode of the device context. Have a look at the below Example:

//Sample 05.1 Set the Mapping Mode and Viewport origin
dc.SetMapMode(MM_LOMETRIC);
dc.SetViewportOrg(rct.left, rct.bottom);

//Sample 05.2 Set this new location as top left of the client area
dc.SetWindowOrg(-100 , -100);

//Sample 05.3 Draw the Verticle and Horizontal line from the Origin (Viewport)
CPen pen1(PS_SOLID, 1, RGB(255,0,0));
CPen* OldPen = dc.SelectObject(&pen1);
dc.MoveTo(0,0);
dc.LineTo(0,500);
dc.MoveTo(0,0);
dc.LineTo(500,0);
dc.SelectObject(OldPen);

In this example first we set the mapping mode, as MM_LOMETRIC and I do not want to tell what it is. Then we shifted the drawing origin to lower left corner of the screen by specifying a location to be shifted as pixels. Then using the SetWindowOrg function, we specify the logical unit -100, -100 should be at the lower left corner of the window. Once this is done, we draw two lines using Red color Solid Pen. In those lines, one moves from the drawing origin(View Port Origin) to 500 unit in the positive, X direction and other one moves 500 units in positive, Y direction. Have a look at the below picture to understand this as it confuses most of MFC professionals:



For More explanation look at the video: 


Source Code : Download

26 June 2013

[ MFC ] - Using MCIWndCreate to Embed Video Player in your application

1. Introduction


In this article, we will see how do we play an AVI video file. To play the AVI file we are going to use the Media Control Interface function (MCI). The Animate control that ships with MFC pack can play the AVI files but you will not get any sound when the video is playing. OK. Let us start with this simple and short example that plays the video file comp.avi. The Avi file that I am packing with this example has no sound information, so you should replace that with any video file, which has sound information in it.



2. Start the Example


Create a Dialog based Visual C++ MFC application and name the application as AVIFilePlay. Once the project is created, we need to access the functions from the MCI Library. To provide access to the library add Vfw32.lib in the additional dependencies entry of the Project settings. The below screenshot shows where you should provide the access to the external library:


Once the required library access is provided to the project we can start our coding.



3. Coding for Playing the AVI File


1) Add the required header to the Dialog Class Implementation file. In our case, I added the header file in the AviFilePlayDlg.cpp.

//Sample 01: Required Header
#include "Vfw.h"

Note that our project is aware of the header file Vfw.h as in the previous step, we provided access to the required library file.


2) Next, in the OnInitDialog function implementation, by passing the window handle of our dialog to the function MCIWndCreate, the media control interface (MCI) window is created. Note that the file that we like to play is available in the D:\Temp directory. You can play the file from any path by specifying the fully qualified path to the windows media Avi file. The call to the function MCIWndCreate on success, return the window handle and that handle is stored in the hVideoWindow. Below is code:

//Sample 02: Create Media Control Interface Window
CAVIFilePlayApp* pApp = (CAVIFilePlayApp*) AfxGetApp();
HWND hVideoWindow = MCIWndCreate(this->m_hWnd,  pApp->m_hInstance,
       NULL, _T("D:\\Temp\\Comp.Avi"));


3) Finally, we make a call to the MCI function MCIPlay. The MCIplay function requires a window handle, which is compatible for playing the window media file (Avi in out case). Below is the code for it:

//Sample 03: Play the Video
MCIWndPlay(hVideoWindow);

When you run the application the video play occurs as shown below:


Source Code: Download




27 May 2013

[ MFC ] - CDialogbar Example: Diaplaying combobox in Dialog Bar Control

1. Introduction to DialogBar example


In this example, we are going to see how do we create and use DialogBars. The dialog bar acts like a toolbar. Unlike toolbar, a dialog bar can have controls that can be placed in a normal dialog. The dialog bar can be docked like a toolbar. To better explain, think of a toolbar with a radio button, a checkbox and a combo box in it. What you just now imagined can be easily achieved through a dialog bar control.

In this example we are going to design a dialog bar, then we will place that in a Rebar control that will be docked on the Main Frame window of the SDI application.



2. About the Example


The example that we are going to make is shown below:


It is a single document interface (SDI) application. Note that, for the end user the Dialog bar displayed on the example look like a toolbar having the Combo box and Edit Box. There is nothing more to explain here. Let us start the implementation.



3. Create the SDI application


Create the MFC SDI Application without document view support. In the wizard you can disable the Document view support, which is shown below:



1. First “Single document” option is picked
2. Next, the check mark in the “Document/View architecture” support is removed
3. Then “use Unicode libraries” also un-checked.

Next, we can accept all the default options in the wizard to create a SDI Application without any document/view support. Once you are in the IDE, build the project and launch it to make sure everything is perfect.



4. Add DialogBar Resource


The next step is adding the dialog bar resource to the project. To add dialog bar resource, right-click on the project name in the resource pane (looking at the previous article’s video to add a toolbar, you will understand how to add dialog bar), then select add a new resource. From the displayed dialog, select the option IDD_DIALOGBAR and click New. This is shown below:


Once dialog bar resource is added to the project, double click the added resource and start placing the controls. The below given screenshot helps in designing your dialog bar control. Once this designing is done, we will move to writing the code to display the dialog bar.




5. Source Code - Implementation


1) First, declare the dialog bar along with other required MFC Objects in the MainFrm.h. Note that we have declared CReBar instance also. Like the previous article, we are going to host the dialog bar object the CReBar control. Below is the declaration:
 
//Sample 01: Required declarations
private:
       CToolBar m_toolbar;
       CDialogBar m_dlgbar;
       CReBar m_rebar;

2) int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) is the function that we are going to modify now. Since we want to display only the dialog bar on the Main window, the code that display MFC’s default toolbar is commented out as shown below:

//Sample 02: No need to create Main Toolbar.
//                  You can even remove it from the
//                  Resource
//if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
//     | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
//     !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
//{
//     TRACE0("Failed to create toolbar\n");
//     return -1;      // fail to create
//}

3) Since we commented out the code that displays MFC’s default toolbar, the below-specified code also need to be commented out.

//Sample 03: I will take care of displaying the Dialogbar in the Toolbar
//// TODO: Delete these three lines if you don't want the toolbar to be dockable
//m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
//EnableDocking(CBRS_ALIGN_ANY);
//DockControlBar(&m_wndToolBar);

4) First, create the MFC’s ReBar Control by passing the “this” pointer as a parameter to the Create Function. The parameter passed in the parent to the rebar control. So the Main Window of our application is the parent for the Rebar control. This code is shown below:

//Sample 04: Create the rebar control. Specify MainFrame window as it's Parent      
m_rebar.Create(this);

5) Next, the Dialog Bar control is created by making the resource edited template denoted by IDD_DLGBR_1. We used the create function of the CDialogBar to create it from the resource id IDD_DLGBR_1. The first parameter specifies that the CReBar control instance is the parent for the CDialogBar instance we are creating now. The Flag CBRS_ALIGN_TOP specifies that Dialog bar control will be aligned on top of the Main Frame window. The last parameter can be a number that acts as the command id. I used same resource id as command id.

//Sample 05: Create the Dialog Bar and specify that m_rebar as it's Parent
m_dlgbar.Create(&m_rebar, IDD_DLGBR_1, CBRS_ALIGN_TOP, IDD_DLGBR_1);

6) Just like how we added the Toolbar controls in the previous example, the dialog bar m_dlgbar is added to the ReBar control. You can refer the previous article to know more about the AddBar function. But from here you can know that the using the AddBar function you can add CToolBar as well as CDialogBar.

//Sample 06: Add the dialog bar control to the Rebar
m_rebar.AddBar(&m_dlgbar, RGB(255,255,0), RGB(0,0,255), "Dbar 1"

       RBBS_GRIPPERALWAYS | RBBS_CHILDEDGE );

Source Code : Download

12 May 2013

[ MFC ] - Floating Toolbars using ReBar Control


1. What is Rebar?


The Rebar MFC control acts as the hosting container for the MFC Toolbar controls. Using the rebar control you can float around the toolbar control in the same row and you can easily re-arrange the control. The rebar control is not limited to host only the toolbars, it can host control like EditBox, Combobox etc. Have a look at the below depiction:

Here, we have two toolbars housed on the rebar. The Gripper is the one, which allows us to move the toolbar around the rebar. When we use the rebar, the user will have the facility of moving the toolbar using its gripper and even they can move the toolbar one below the other one. In this article, I will show how do you create two toolbars and house that using the MFC Rebar.



2. Example – Using the MFC Rebar Control


The example application that we are going to build in this article is shown in the below picture:


Our example is a Single Document Interface (SDI) application, which displays six toolbar buttons in two ToolBars. These two ToolBars are housed by the Rebar control. Placing the toolbar on the rebar allows the user to move the toolbar over the Rebar control using the Gripper. Using the grippers, we can also place a toolbar in separate rows.

OK. Let us start building this example.



3. Create ToolBar1 and ToolBar2


Create SDI MFC Application. To create the Toolbar we should use the resource Editor. Firstly, switch to the Resource view, then right click the project name to access the New Resource Dialog.



This will open an “Add Resource” dialog as shown below. From the dialog pick the Toolbar and hit the new button. Do this one more time to add next toolbar. Remember we are going to add two toolbars to the rebar.


Once the toolbars are added, Double click on the toolbar from resource view and draw each button. Below is the screen shot of the Second toolbar:


Once drawing the Toolbar is finished, Right click on each toolbar and assign the ID. The Below picture shows, First button in the First Toolbar is selected, then its property is accessed and ID_TB1_CMD1 is typed for the ID Field. Remember to set this property for each toolbar button from left to right. This will give ID number in ascending order, which will later help us in specifying the command range.


If you find difficulties in designing the toolbar, have a look at the below video which demonstrates creating a toolbar through visual studio editor.








4. Create Bitmap resource


To create a bitmap follow the same procedure explained in the previous section. In the “Add Resource” dialog instead of selecting the toolbar, we should select the Bitmap and hit new. This will add bitmap node in the resource explorer. Once the Bitmap is added, edit it using the resource editor. The below screen shot shows the bitmap used as the background for the example application:

Note that the height of the bitmap matches the height of the toolbar buttons which 32 pixels tall. Also, note that the each toolbar size is set to 32 x 32 pixels.  This you can refer from the previous section’s property screen shot. The video shown below explains creating a bitmap using the visual studio resource editor.



5.  Displaying Toolbar in a Rebar control


When you created a "SDI Application", accepting all the defaults in the wizard, MFC leaves default code that we are going to comment out now. First, go to the resource view and delete the default toolbar named as IDR_MAINFRAME.

1) Navigate to the Function CMainFrame::OnCreate. Comment out the code that creates the default toolbar that you deleted from the resource editor. The toolbars, Menus and status bar are created usually in the CMainFrame::OnCreaye. The code snippet shown below:

//Sample 01: Comment out the toolbar creation as we deleted it
//if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
//     | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
//     !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
//{
//     TRACE0("Failed to create toolbar\n");
//     return -1;      // fail to create
//}

// TODO: Delete these three lines if you don't want the toolbar to be dockable
//Sample 02: Comment Out
//m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
//EnableDocking(CBRS_ALIGN_ANY);
//DockControlBar(&m_wndToolBar);


2) In the CMainFrame class, add the below shown private member variables. The two CToolBar objects will be loaded with the toolbars created using the Resource editor. The CBitmap object m_bckBmp will be used to set the background for the Rebar. CReBar object will be used to host the toolbar objects. The entire relationship goes like this: Toolbar buttons are hosted by the toolbar, the toolbar is hosted by the ReBar and the ReBar is hosted by MainFrame. Now you know why we are declaring all the objects here in the CMainFrame class.

private:
//Sample 03: Declaration required for the Toolbar, Bitmap, and Rebar
       CToolBar m_FirstToolBar;
       CToolBar m_SecondToolBar;
       CBitmap m_bckBmp;
       CReBar m_rebar;

3) In the OnCreate function of the CMainFrame, First, we create both the toolbars by calling CreateEx function. Note that we are setting a TBSTYLE_TRANSPARENT flag during the creation of the CToolBar. This is because we want to set the background for the ReBar control and to make it visible we are setting the toolbar as Transparent. You can run this example application without this flag to see how it works. After creating the Toolbar, we are loading the Toolbar buttons by calling the function LoadToolBar and by giving the resource Id for the toolbar.

//Sample 04:Create both the toolbars
m_FirstToolBar.CreateEx(this, TBSTYLE_FLAT | TBSTYLE_TRANSPARENT );
m_FirstToolBar.LoadToolBar(IDR_FIRST_TB  );
m_SecondToolBar.CreateEx(this, TBSTYLE_FLAT | TBSTYLE_TRANSPARENT );
m_SecondToolBar.LoadToolBar(IDR_SECOND_TB );

4) Next, we will add a handler function for each toolbar buttons coming from both the toolbars. The handler function declaration is made at the MainFrame.h file. This is shown below:

//Sample 05: Declare a dummy Handler Function for all the toolbar
//                        button
       void SomeFunction(UINT someparam);

5) The handler function definition is shown below. This function does not require any explanation.

//Sample 06: A do nothing toolbar handler
void CMainFrame::SomeFunction(UINT someparam)
{
       //Do Nothing. In real world there will be dedicated functions
       //for toolbar actions
       AfxMessageBox("Toolbar Clicked");
}

6) Next, inside the message map entry, Place two entries of ON_COMMAND_RANGE. This macro maps a range of command Ids to a specific handler function. Let us take the first message map entry for the explanation. The first two Ids ID_TB1_CMD1 and ID_TB1_CMD3 define the Range for all three buttons in the first toolbar. This ID number should be in ascending order. You can make sure this by visiting the Resource.h file. The third parameter defined the function mapped to the Command Ids. The code given below shows that all six toolbar buttons coming from two different toolbars mapped to a single handler function named SomeFunction.

//Sample 07: Handler for the toolbar buttons
       ON_COMMAND_RANGE(ID_TB1_CMD1, ID_TB1_CMD3, SomeFunction)
       ON_COMMAND_RANGE(ID_TB2_CMD1, ID_TB2_CMD3, SomeFunction)

7) OK. The toolbars are ready. Next, we load the bitmap resource into the CBitmap object m_bckBmp. The LoadBitmap function takes the bitmap resource id as the parameter and loads the resource-edited bitmap into the bitmap object.

//Sample 08: Create the Bitmap
m_bckBmp.LoadBitmap(IDB_TB_BACK);

8) Now we have everything ready. The toolbar is ready; bitmap for setting the background is ready. The code given below loads the toolbar into the ReBar Control. First, the rebar control is created calling Create function with the “this” pointer as a parameter. The pointer specifies CMainFrame as the parent to the m_rebar.

Next, we add the toolbars one by one. The second and third parameter specifies the ForeColor and BackClolor for the ReBar control. While adding the toolbars we asked to display the edges also asked to display the Gripper always. The below code snippet sets a solid color to the rebar control:

//Sample 09: Create the Rebar and Add toolbars to it
m_rebar.Create(this);
m_rebar.AddBar(&m_FirstToolBar, RGB(255,0,0), RGB(0,255,0),"TB 1", RBBS_GRIPPERALWAYS
                    | RBBS_CHILDEDGE);
m_rebar.AddBar(&m_SecondToolBar, RGB(255,0,0), RGB(0,255,0),"TB 2", RBBS_GRIPPERALWAYS
                          | RBBS_CHILDEDGE);



9) The below-commented code shows the rebar with the bitmap as the background.

////Sample 10: Create the Rebar and Add toolbars to it
//m_rebar.Create(this);
//m_rebar.AddBar(&m_FirstToolBar, "TB 1", &m_bckBmp, RBBS_GRIPPERALWAYS
//                        | RBBS_CHILDEDGE);
//m_rebar.AddBar(&m_SecondToolBar, "TB 2", &m_bckBmp, RBBS_GRIPPERALWAYS
//                         | RBBS_CHILDEDGE);

The screenshot shows the application’s appearance when the Sample10 is executed and Sample09 is commented out:


The video given below shows the usage of the Rebar.


Source Code : Download