Introduction
Well, since we've had no new and / or exciting articles recently, I realised twas down to me to bridge the gap, so to speak. Nothing new here at all and I wasn't going to bother, but as a friend told me: "some people haven't nutted this stuff out yet."
Oh, and we'll be using lcc (see the archive) since I hate gui based stuff. You can grab my example sources here.
As most people are aware, Miscreantsoft provided a bunch of standard (boring,ugly) common controls intended to supplement the standard controls. There are quite a few of 'em, but in this article we'll be looking at toolbars and tooltips ('cos they're easy peasy and as such won't take too long to write about =] )
Before We Begin
Prior to using common controls, we need to include the common control header file, commctrl.h, in your program. Any program that uses common controls must call the api function InitCommonControls() beforehand. This ensures that the correct dll is loaded and initialised.
The last thing we have to do is make sure we link the common controls library at, urm, link time =]
Here We Go...
All of the common controls are child windows. We can create them in much the same way we would for a regular window, i.e with: CreateWindow(), CreateWindowEx(), or a specific api call for that control.
Toolbar Icons
A toolbar is basically a graphical version of a menu, therefore we're gonna need graphics. Fire up your favourite image editor and create the pictures for your toolbar buttons. There are a few restrictions here :
#define-ing Stuff
Now we have our button bitmap for the toolbar I'm sure we have an idea what each button should do, so lets #define them. This is toolbar.h
#define ID_NEWFILE 100
#define ID_OPENFILE 101
#define ID_SAVEFILE 102
Ok, that was easy enough. Now we add another couple of defines, one for the toolbar itself, and another for the toolbar bitmap (continuing toolbar.h)
#define ID_TOOLBAR 200
#define ID_TBAR_BMP 300
Now we add our crap to the resource file toolbar.rc:
#include <windows.h>
#include "toolbar.h"
ID_TBAR_BMP BITMAP "tbicons.bmp"
Now lets do some 'coding'...
The Toolbar
Before we can create the toolbar, we need to set up an array for the buttons. Funnily enough this is an array of structure TBBUTTON. The structure is defined as follows :
typedef struct
{
int iBitmap; // Number of Picture in the Bitmap, Starting at zero
int idCommand; // ID of the button which is sent when pressed
BYTE fsState; // Initial State of the button
BYTE fsStyle; // The Style of the button
DWORD dwData; // User-defined Data, Should be zero if unneeded
int iString; // Index of optional string associated with the button
} TBBUTTON;
Each button needs to be individually configured to reflect how it should act, e.g Enabled, Disabled, Toggle-able etc. Lets look at our first button:
TBBUTTON tbut[NUM_BUTTONS];
tbut[0].iBitmap = 0;
tbut[0].idCommand = ID_NEWFILE;
tbut[0].fsState = TBSTATE_ENABLED;
tbut[0].fsStyle = TBSTYLE_BUTTON;
tbut[0].dwData = 0L;
tbut[0].iString = 0;
We do this for each of the buttons in the toolbar. fsState can take of the following values:
TBSTATE_CHECKED | Button is pressed |
TBSTATE_ENABLE | Button is active |
TBSTATE_HIDDEN | Button is inactive and hidden |
TBSTATE_INDETERMINATE | Button is greyed out and inactive |
TBSTATE_PRESSED | Button is pressed |
TBSTATE_WRAP | Wrap following buttons to next line |
fsStyle, again can take any valid combination of the following values:
TBSTYLE_BUTTON | Your bog-standard button |
TBSTYLE_CHECK | Button toggles between on / off when clicked |
TBSTYLE_CHECKGROUP | Check button -part of a mutually exclusive group |
TBSTYLE_GROUP | Standard button -part of mutually exclusive group |
TBSTYLE_SEP | Button seperator ( see below ) |
Now that we've defined our buttons, we can finally create our toolbar. We do this with the CreateToolbarEx() function
( bet you could never have guessed ) Much the same way we'd create any other window really. Prototype:
HWND CreateToolbarEx( HWND ParenthWnd,DWORD dwStyle,WORD ID,int NumButtons,HINSTANCE hInst,
WORD BPID,LPCTBBUTTON ButtonHeight,int BMPWidth,int BMPHeight,UINT Size );
For a detailed explanation of the parameters check your win32 programmers reference, but they should be fairly self explanatory. Lets create our toolbar...
tbarhWnd = CreateToolbarEx( hWnd,WS_VISIBLE ¦ WS_CHILD ¦ WS_BORDER, ID_TOOLBAR, NUM_BUTTONS,
hInst,ID_TBAR_BMP,tbut,NUM_BUTTONS,0,0,20,19,sizeof(TBBUTTON));
A Note on Seperators
Looking at the sample bitmap, you'll see that the last icon is empty. This is intentional, it will serve as our 'seperator' and is essentially for aesthetic purposes. With this we can group related buttons together on the toolbar.
We define a seperator just as we would a normal button, except we would set the fsStyle to TBSTYLE_SEP.
idCommand should be set to zero.
Modifying After Creation
As with other windows, we can change the status of the bits 'n' bobs of the toolbar by sending it messages. We use the standard api function, SendMessage(). We can send the following messages:
In all cases, wParam should contain the ID of the button, e.g ID_OPENFILE.
TB_CHECKBUTTON | Press/Clear Button, lParam != 0 to Press, 0 to clear |
TB_ENABLEBUTTON | Enable/Disable Button, lParam != 0 to enable, 0 to disable |
TB_HIDEBUTTON | Hide/Show Button, lParam != 0 to hide, 0 to show |
For example, say we wanted to disable the Save File button (Disk Icon) We'd write something like this:
SendMessage( tbarhWnd,TB_ENABLEBUTTON,ID_SAVEFILE,0 );
What About When the Button Is Clicked?
Heh, same as with any control. A WM_COMMAND message is sent to your window function, where the lower word of wParam contains the ID of the control that sent the message. Intercept it and act accordingly. See my lame source.
Moving Right Along, Adding Tooltips.
This bit really is piss easy. In case you don't know, tooltips are the lil thingy's that popup to tell you what a button does if you leave the mouse over a control. Firstly we need to add the TBSTYLE_TOOLTIPS style when we create the toolbar. This tells wincrash to send WM_NOTIFY messages to our program whenever the mouse is left over a toolbar button.
Once this message arrives at our doorstep, lParam points to a TOOLTIPTEXT structure. Looks a lil like this:
typedef struct
{
NMHDR hdr;
LPSTR lpszText;
char szText[80];
HINSTANCE hinst;
} TOOLTIPTEXT;
typedef struct
{
HWND hwndFrom;
UINT idFrom;
UINT code;
} NMHDR;
When we are sent this structure (via WM_NOTIFY) we need to examine hdr.code to see if it equals TTN_NEEDTEXT.
If it does we need to look at hdr.idFrom to see which button on the toolbar is requesting this info.
Finally we have a few ways which we can supply the tooltip text, we'll look at the easiest -making lpszText point to the string.
As always we'll try to clear this up, with some more source code :
LPTOOLTIPTEXT TtipText;
case WM_NOTIFY :
TtipText = (LPTOOLTIPTEXT)lParam;
if( TtipText->hdr.code == TTN_NEEDTEXT )
switch( TtipText->hdr.idFrom )
{
case ID_NEWFILE :
TtipText->lpszText = "Create a New File";
break;
And so on and so forth.
The End of Another Lame Article
Well, we're done, again. Thanks for reading, hope you've learnt something new. Once again, feel free to make use of any of the stuff on CoRNSouP... as a coder, it's your site too. As always, comments / essays / bugs etc are more than welcome. Mail us... lates.
--NRoC 17/02/99 22:20