I have discussed this topic with
Dominic Mitchell, and the following Text is a part from what he told me.
While the informations are not at all general but partly specific to my actual project, it shows some "How To's " with Toolbars that may be of interest to anyone having to do with toolbars.
--------------------------------------------------------
Toolbar and Phoenix
===================
There is a bug in the Windows toolbar that causes a stack fault when the toolbar has a certain
combination of styles and it is moved, or setting or clearing a style causes it to move.
The following of some of my notes that describe some of the bugs in the Windows toolbar.
Memory leak
-----------
Rapidly creating and destroying toolbars that use the system bitmaps in commctrl.dll
produces a nasty leak in GDI resources. To make matters worse the resources are
not restored even after the application terminates. Toolbars that do not use the
system bitmaps do not exhibit this problem.
I cannot think of a single common control supplied by Microsoft that does not
have a plethora of bugs.
CCS_NOPARENTALIGN and dynamic resizing
--------------------------------------
A toolbar with is style may enter a WM_SIZE loop that can lead to a stack fault
when it is dynamically resized. Use the CCS_NORESIZE style for toolbars
that deeply embedded in for example rebars. When a toolbar with the CCS_NOPARENTALIGN
style is resized, it walks across the screen.
CCS_NODIVIDER
-------------
Common controls with a divider(CCS_NODIVIDER style not set)
have a tendency to move vertically when their size or position
is changed. To prevent this behaviour, remove the divider style
before setting size and position properties.
There is a check in the designer that attempts to break out of the runaway recursion, but even
that fails sometimes.
Your modified code
==================
You have three options,
1) Use the original code I sent with a toolbar with the TBSTYLE_FLAT, TBSTYLE_LIST,
TBSTYLE_EX_MIXEDBUTTONS and CCS_NORESIZE styles. The drawback with this method is that when the
buttons have the BTNS_SHOWTEXT style, the text is displayed to the right of the image.
2) Destroy and recreate the toolbar. This involves the most work because the toolbar state
will have to be stored somewhere in order for it to be rebuilt. The toolbar state can be stored
in the registry or a stream.
3) Vary the size of the toolbar buttons in such a way that the text is hidden or visible. This allows
text to be displayed at the bottom or right of the button image.
The rest of this document describes the third option.
Modify layout rules
===================
Open the Layout Manager and delete the rule that produces the following macro:
//Action Act On Relative To
//------- ------------------------------------ ----------------------------------------------
// Macro Part Widget(First, Last) Part Widget % Offset
//------- ------ ---------------------------- ------ ------------------------- --- ------
STRETCH, BOTTOM, IDC_MDIFORM1_PAGER1, 0, HEIGHT, IDD_MDIFORM1, 10, 0
Deleting the rule allows the pager to change its size as the height of the toolbar changes.
Toolbar control styles
======================
Only the following styles should be set for the toolbar control:
CCS_NORESIZE
TSTYLE_FLAT
Make sure TBSTYLE_EX_MIXEDBUTTONS is not checked.
Toolbar button styles
=====================
If the button is not a separator, it style should be BTNS_BUTTON, at the very least, it should
not be BTNS_AUTOSIZE or BTNS_SHOWTEXT.
Code to vary size of buttons
============================
'-------------------------------------------------------------------------------
FUNCTION Toolbar_ToggleText _
( _
BYVAL hWndToolbar AS DWORD, _ ' handle of toolbar control
BYVAL fShowText AS LONG _ ' true = show text, false = hide text
) AS LONG
LOCAL szText AS ASCIIZ * %MAX_PATH
LOCAL trc AS RECT
LOCAL tsize AS SIZEL
LOCAL tbbi AS TBBUTTONINFO
LOCAL iButton AS LONG
LOCAL cButtons AS LONG
LOCAL hWndLabel AS DWORD
LOCAL iBtnWithLabel AS LONG
LOCAL x AS LONG
LOCAL y AS LONG
LOCAL cxCtrl AS LONG
LOCAL cyCtrl AS LONG
LOCAL cyOffset AS LONG
LOCAL cxyButton AS LONG
LOCAL hImgListNormal AS DWORD
LOCAL hFont AS DWORD
LOCAL cxIcon AS LONG
LOCAL cyIcon AS LONG
LOCAL hDC AS DWORD
LOCAL cxText AS LONG
LOCAL cyText AS LONG
LOCAL hWndPager AS DWORD
LOCAL cxPager AS LONG
LOCAL cyPager AS LONG
' If text is being shown
IF fShowText THEN
' Calcualte width and height of buttons
hImgListNormal = SendMessage(hWndToolbar, %TB_GETIMAGELIST, 0, 0)
ImageList_GetIconSize hImgListNormal, BYVAL VARPTR(cxIcon), BYVAL VARPTR(cyIcon)
hDC = GetDC(hWndToolbar)
SaveDC hDC
SelectObject hDC, SendMessage(hWndToolbar, %WM_GETFONT, 0, 0)
tbbi.cbSize = SIZEOF(tbbi)
tbbi.dwMask = %TBIF_BYINDEX OR %TBIF_STYLE OR %TBIF_COMMAND
tbbi.pszText = VARPTR(szText)
tbbi.cchText = %MAX_PATH
cButtons = SendMessage(hWndToolbar, %TB_BUTTONCOUNT, 0, 0)
iButton = 0
WHILE iButton < cButtons
szText = ""
IF SendMessage(hWndToolbar, %TB_GETBUTTONINFO, iButton, BYVAL VARPTR(tbbi)) THEN
IF (tbbi.fsStyle AND %BTNS_SEP) <> %BTNS_SEP THEN
SendMessage hWndToolbar, %TB_GETBUTTONTEXT, tbbi.idCommand, BYVAL VARPTR(szText)
GetTextExtentPoint32 hDC, BYVAL tbbi.pszText, LEN(tbbi.@pszText), tsize
cxText = MAX(cxText, tsize.cx)
cyText = MAX(cyText, tsize.cy)
END IF
END IF
INCR iButton
WEND
RestoreDC hDC, -1
SendMessage hWndToolbar, %TB_SETBUTTONSIZE, 0, MAKDWD(cxText + 6, cyIcon + cyText + 9)
' Text is being hidden
ELSE
' Let the toolbar set the default size for the buttons
SendMessage hWndToolbar, %TB_SETBUTTONSIZE, 0, MAKDWD(0, 0)
END IF
hWndPager = GetParent(hWndToolbar)
GetWindowRect hWndPager, trc
cxPager = trc.nRight - trc.nLeft
' Height(6 pixels add to compensate for edges of the pager)
cyPager = HIWRD(SendMessage(hWndToolbar, %TB_GETBUTTONSIZE, 0, 0)) + 6
SetWindowPos hWndPager, %NULL, 0, 0, cxPager, cyPager, %SWP_NOZORDER OR %SWP_NOMOVE OR %SWP_DRAWFRAME
SendMessage hWndPager, %PGM_RECALCSIZE, 0, 0
' -------------------------------------------------------
' Reposition embedded control(s)
' Note: this code assumes that is an embedded control at the
' location of button 17.
hWndLabel = GetDlgItem(hWndToolbar, %IDC_MDIFORM1_TEXTLBL1)
GetWindowRect hWndLabel, trc
cxCtrl = trc.nRight - trc.nLeft
cyCtrl = trc.nBottom - trc.nTop
' Get the bounding rectangle of the separator
iBtnWithLabel = 17
cyOffset = 1
SendMessage hWndToolbar, %TB_GETITEMRECT, iBtnWithLabel, BYVAL VARPTR(trc)
' Calculate new position of the label
x = (trc.nLeft + trc.nRight - cxCtrl) \ 2
y = (trc.nTop + trc.nBottom - cyCtrl) \ 2 + cyOffset
SetWindowPos hWndLabel, %NULL, x, y, cxCtrl, cyCtrl, %SWP_NOZORDER OR %SWP_DRAWFRAME
' -------------------------------------------------------
END FUNCTION
How to invoke code above
========================
'-------------------------------------------------------------------------------
FUNCTION MDIForm1_MainMenu1_ViewToolbar _
( _
BYVAL hWnd AS DWORD _ ' handle of window that owns the menu
) AS LONG
LOCAL hWndPager AS DWORD
LOCAL hWndToolbar AS DWORD
LOCAL hMenu AS DWORD
LOCAL fChecked AS LONG
hMenu = GetMenu(hWnd)
fChecked = ((GetMenuState(hMenu, %IDM_TOOLBAR, %MF_BYCOMMAND) AND %MF_CHECKED) = %MF_CHECKED)
IF fChecked THEN
CheckMenuItem hMenu, %IDM_TOOLBAR, %MF_BYCOMMAND OR %MF_UNCHECKED
ELSE
CheckMenuItem hMenu, %IDM_TOOLBAR, %MF_BYCOMMAND OR %MF_CHECKED
END IF
hWndPager = GetDlgItem(hWnd, %IDC_MDIFORM1_PAGER1)
hWndToolbar = GetDlgItem(hWndPager, %IDC_MDIFORM1_TOOLBAR1)
Toolbar_ToggleText hWndToolbar, NOT fChecked
' Update the layout
SendMessage hWnd, gdwADM_LAYOUT, hWnd, %IDD_MDIFORM1
END FUNCTION