Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Toolbar in the middle of elsewhere

0.00/5 (No votes)
19 Mar 2003 1  
This article explains how to place a toolbar right in the middle of a dialog or a form.

Sample Image - ArbTB.jpg

Introduction

Imagine you have a dialog, where you can enter text and other data related to the text. While the text should be formatted, the normal data entries should not. So you place a toolbar into your dialog, that has all the formatting buttons you need and find out, that it will dock only at the edges of your dialog. But I (the customer) wants this thing, where it belongs to: right over the format-able text entry.

To achieve the customer's need, there is a little more involved than just placing a button row in the middle of a form.

Creating the toolbar

Step one

Create a toolbar as usual and add a CToolBar member to your dialog, giving it any name that suits you. For a formatting toolbar a name like m_wndFormatBar sounds great.

Create a static control at that spot, where you want the toolbar to reside. Give this frame an ID (i.e. IDC_STC_TOOLBARFRAME). Make it slightly bigger then the tools, so you can see the space that becomes occupied by the toolbar. Within class wizard assign a member to this control. Make sure it is assigned to CStatic and not CString. Name it whatever you want (like m_Stc_ToolbarFrame).

Step two

Now comes the hard part. In the OnInitDialog method of your dialog, place following code. You may omit the comments.

// Positioning of toolbar

CSize sizeToolbar;
CRect mrect;
mrect.SetRectEmpty();
// attach command routing to dialog window

m_wndFormatBar.Create(this); 
m_wndFormatBar.LoadToolBar(IDR_TOOLBAR_FORMAT);
m_wndFormatBar.SetBarStyle(CBRS_ALIGN_TOP | CBRS_TOOLTIPS | CBRS_FLYBY);
m_wndFormatBar.ShowWindow(SW_SHOW);
// Calculate size of toolbar and adjust size of static control to fit size

sizeToolbar = m_wndFormatBar.CalcFixedLayout(false,true);
m_Stc_ToolbarFrame.GetWindowPlacement(&wpl);
wpl.rcNormalPosition.bottom = wpl.rcNormalPosition.top  + 
                                        sizeToolbar.cy + 4;
wpl.rcNormalPosition.right  = wpl.rcNormalPosition.left + 
                                        sizeToolbar.cx + 4;
// Position static control and toolbar

m_Stc_ToolbarFrame.SetWindowPlacement(&wpl);
m_wndFormatBar.SetWindowPlacement(&wpl);
// Adjust buttons into static control

m_Stc_ToolbarFrame.RepositionBars(AFX_IDW_CONTROLBAR_FIRST, 
    AFX_IDW_CONTROLBAR_LAST, 0);
m_Stc_ToolbarFrame.ShowWindow(SW_HIDE);

How this works

m_wndFormatBar.Create(this) tells the toolbar, to which window the commands are to be sent. Loading the images, setting the bar styles and displaying the toolbar is quite obvious. Then you calculate the size of the toolbar, and adjust the size of the static control accordingly with some margin.

After having done heavy numerical considerations we place the static control and put the toolbar in its lap. m_Stc_ToolbarFrame.RepositionBars tells the toolbar, which window it shall snuggle up to. Then make the static control disappear.

Omitting lines or doing the calculations wrong will be sentenced with weird optical results and strange behavior of your application. Check it out.

While the command routing is very simple, the visual updating of these commands is a little bit tricky.

Step three

Add the UpdateCommandUI handlers to your dialog and edit the methods as you would, in every Frame/View application. Do not care, when they do not seem to work. Actually they can't.

Step four

Add the line:

#include "afxpriv.h"

at the top of the dialog's cpp file, or put it inside stdafx.h. In your dialog's header file put the line:

afx_msg LRESULT OnKickIdle(WPARAM, LPARAM);

inside the message map. The best place is a line between the //}}AFX_MSG line and the DECLARE_MESSAGE_MAP() line. If there is no line, then make one by pressing return. In your dialog's cpp file look for the word END_MESSAGE_MAP(). Before that line, enter ON_MESSAGE(WM_KICKIDLE, OnKickIdle). If you forgot to include afxpriv.h the compiler will tell you, that it does not know anything about WM_KICKIDLE. (By the way, does this message mean that someone is idly kicking?)

Add the body of the OnKickIdle routine to your dialog class and call herein the CommandUpdateUI handlers. How? Have a look.

LRESULT CArbitraryToolbarDlg::OnKickIdle(WPARAM, LPARAM)
{ 
    CCmdUI cmdUI;
    cmdUI.m_nID = ID_FORMAT_BOLD; // The Command ID

    // Tell the dialog to call the UpdateCommandUI-routine

    cmdUI.DoUpdate(this, FALSE);
    cmdUI.m_nID = ID_FORMAT_DURCHSTRICH;
    cmdUI.DoUpdate(this, FALSE);
    cmdUI.m_nID = ID_FORMAT_KURSIV;
    cmdUI.DoUpdate(this, FALSE);
    cmdUI.m_nID = ID_FORMAT_UNTERSTRICH;
    cmdUI.DoUpdate(this, FALSE);
    cmdUI.m_nID = ID_EDIT_CUT;
    cmdUI.DoUpdate(this, FALSE);
    cmdUI.m_nID = ID_EDIT_COPY;
    cmdUI.DoUpdate(this, FALSE);
    cmdUI.m_nID = ID_EDIT_PASTE;
    cmdUI.DoUpdate(this, FALSE);
    return TRUE;
}

Step five...

Add the command handlers and test it. Drink a cup of coffee.

During this whole process you should compare your source code with mine. What you may adapt to your needs, what may not be altered I can't tell. This is taught only by experience, your experience.

The sample supplied has only the first seven buttons working. This is by design! After all, it is a sample not a full blown application.

The routines for squeezing the RichEditCtrl will be coming soon with its own class. So stay tuned.

After having read so long, may I ask you a favour? My little brother has been sent to war in the middle east now, would you please pray for him, so he will return safe and sound? Thank you.

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