65.9K
CodeProject is changing. Read more.
Home

Guarantee Correct Spacing for toolbar Separators on Multiple TB_ADDBUTTONS Calls

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2 votes)

Jan 16, 2020

CPOL
viewsIcon

3905

A solution for: If the toolbar is created button by button with single TB_ADDBUTTONS calls, the width of the separators is not calculated correctly.

Introduction

I create my toolbar by single TB_ADDBUTTONS message calls. I used TB_ADDBUTTONS message calls to create separators as well. But the width of the separators starts too small and then it increases with each separator.

Background

To get the right separator width (8px each), the TBSTYLE_SEP must not be added to the toolbar separately. To solve this problem, I changed my API and added the bPrependSeparator argument. This is the result:

Using the Code

I know - it could be made shorter, but the code is readable and does what it should:

/// <summary>
/// Adds a new button to the tool bar.
/// </summary>
/// <param name="hBmpImage">The handler of the tool bar button image bitmap.
/// Can be <c>NULL</c>, if <c>byStyle</c> doesn't need an image.</param>
/// <param name="hBmpMask">The handler of the tool bar button mask bitmap.
/// Can be <c>NULL</c>, if transparency is not required.</param>
/// <param name="uiCommandID">The tool bar button command ID, that is in sync
/// with the menu item command ID.</param>
/// <param name="byState">The initial tool bar button state.</param>
/// <param name="byStyle">The tool bar button style.</param>
/// <param name="wszText">The optional text to display below the image.</param>
/// <param name="bPrependSeparator">The flag determining whether to prepend a separator.
/// </param>
/// <returns>The number of remaining image list slots for tool bar button images.</returns>
/// <remarks>Can still be called like this to create an not-prepended separator
/// (but the space isn't correct):
/// pToolBar->AddButton(NULL, NULL, (UINT)0, TBSTATE_ENABLED, TBSTYLE_SEP);</remarks>
UINT OgwwToolBar::AddButton(HBITMAP hBmpImage, HBITMAP hBmpMask, 
                            UINT uiCommandID, BYTE byState,
                            BYTE byStyle, LPCWSTR wszText, BOOL bPrependSeparator)
{
    if (hBmpImage != NULL)
    {
        ::ImageList_Add(_hImageList, hBmpImage, hBmpMask);
        _wBitmapUsed++;
    }

    if (bPrependSeparator != FALSE)
    {
        TBBUTTON tbb[2];
        ::ZeroMemory(tbb, sizeof(tbb));

        tbb[0].iBitmap   = 0;
        tbb[0].idCommand = 0;
        tbb[0].fsState   = TBSTATE_ENABLED;
        tbb[0].fsStyle   = TBSTYLE_SEP;
        tbb[0].iString   = 0;

        tbb[1].iBitmap   = (_hImageList != NULL) ? _wBitmapUsed - 1 : 0;
        tbb[1].idCommand = uiCommandID;
        tbb[1].fsState   = byState;
        tbb[1].fsStyle   = byStyle;
        tbb[1].iString   = 0; // SendMessageW(hToolBar, TB_ADDSTRING, 0, (LPARAM)wszText);

        // Try this if it doesn't work out right away:
        //::SendMessageW((HWND)_hHandle, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
        ::SendMessageW((HWND)_hHandle, TB_ADDBUTTONS, 2, (LPARAM)tbb);
    }
    else
    {
        TBBUTTON tbb;
        ::ZeroMemory(&tbb, sizeof(tbb));

        tbb.iBitmap   = (_hImageList != NULL) ? _wBitmapUsed - 1 : 0;
        tbb.idCommand = uiCommandID;
        tbb.fsState   = byState;
        tbb.fsStyle   = byStyle;
        tbb.iString   = 0; // SendMessageW(hToolBar, TB_ADDSTRING, 0, (LPARAM)wszText);

        ::SendMessageW((HWND)_hHandle, TB_ADDBUTTONS, 1, (LPARAM)&tbb);
    }

    return (_wBitmapCount - _wBitmapUsed);
}

Happy programming!

Points of Interest

Not everything that is allowed/compiles works.

History

  • 16th January, 2020: Initial version