Written by Eric Slaats
When I started programming PM applications I was really amazed that simple, common things that most application feature like buttonbars, multi windowing (tile, cascade etc.) weren't standard features. On my first attempt to build an application, I wanted to include a buttonbar so I started looking for an API call that would place all the buttons for me in the right place. There isn't such a call! The lack of this call made me construct a method like Marc and I described in "Building Custom Controls" (see EDM/2 3-4). The method described in that article is complete and does everything it should do. However, I wasn't satisfied with the amount of code it took when writing another (very small) application. So I started to experiment with the menu styles and found a very simple way to implement a buttonbar.
In this (short) article I'll describe this very simple approach to build a buttonbar. It functions very well, but it also has some drawbacks (see the section Concluding Notes). If you're willing to accept this, you'll be rewarded with a toolbar which is very very easy to implement.
Bitmap Buttons In A Menu
In the introduction I stated that there isn't a API call to build a buttonbar. In fact this isn't true. We can build a menu filled completely with buttons containing a bitmap. So, in fact, OS/2 has a method to build a buttonbar! (This approach is already been handled in "Building Custom Controls" in EDM/2 3-4.)
To use bitmaps in a menu, the bitmaps should be known in the .RC file. To accomplish this we need to do two things. First we need to create identifiers for all the the bitmaps we want to use. These are usually kept in the header file.
// Bitmap identifiers #define ONE 101 #define TWO 102 #define THREE 103 #define FOUR 104 #define FIVE 105
Figure 1) Bitmap identifiers
These declarations are used in the RC file to associate the bitmaps with an identifier.
// Bitmap declaration BITMAP ONE "ONE.BMP" BITMAP TWO "TWO.BMP" BITMAP THREE "THREE.BMP" BITMAP FOUR "FOUR.BMP" BITMAP FIVE "FIVE.BMP"
Figure 2) Bitmap filename declaration
The next step in creating a menu with bitmaps is building the actual menu. The following lines in the .RC file describe the buttonbar menu.
// Menu declaration MENU TOOLMENU BEGIN MENUITEM "#101", IDM_ONE, MIS_BITMAP MENUITEM "#102", IDM_TWO, MIS_BITMAP MENUITEM "#103", IDM_THREE, MIS_BITMAP MENUITEM "#104", IDM_FOUR, MIS_BITMAP MENUITEM "", MIS_SEPARATOR MENUITEM "#105", IDM_FIVE, MIS_BITMAP END
Figure 3) Menu template
The menustyle for each of the buttons is MIS_BITMAP. This means the menuitem will display as a bitmap and the RC compiler expects the identifiers of the bitmaps in the textarea of the menuitems. We'll put the identifier of the bitmap preceded by a `#' in the text area.
Besides the declaration of the menuitems a MIS_SEPARATOR is included. This line in the RC file will put a blank between the buttons FOUR and FIVE. This way we have a method to separate groups of buttons.
If a window is built using the menu described above, we'll get a window which will look like this:
In this example button 32X32 bitmaps are used. These bitmaps are shaped as a button. Of course any bitmap can be used. The bitmaps used in this example can be found in the toolbar2.zip file. [Editor's note - Eric forgot to send this file with the article. It will be placed on the EDM/2 ftp site as soon as possible.]
Adding 'Normal' Menu Items
Well I promised a simple buttonbar. The 'trick' is indeed very simple. We add the normal menuitems to the menu defined in the previous section. The thing to do is to give the 'normal' menu items the same identifier as the corresponding button. (It isn't forbidden to have more than one item with the same identifier in one menu!) This way we're sure the button and the menuitem trigger the same case item in the window procedure.
If we leave the menu like this, the buttons and the menuitems are displayed in one row (given a large enough window). If we want a buttonbar, we want it to be displayed underneath the normal menu items. This effect can be accomplished to ad the MIS_BREAK stye to the first menuitem that has to be displayed on the second row. The menu code in the RC file should look something like this:
// Menu declaration MENU TOOLMENU BEGIN MENUITEM "~One", IDM_ONE MENUITEM "~Two", IDM_TWO MENUITEM "Th~ree", IDM_THREE MENUITEM "~Four", IDM_FOUR MENUITEM "F~ive", IDM_FIVE MENUITEM "#101", IDM_ONE, MIS_BITMAP | MIS_BREAK MENUITEM "#102", IDM_TWO, MIS_BITMAP MENUITEM "#103", IDM_THREE, MIS_BITMAP MENUITEM "#104", IDM_FOUR, MIS_BITMAP MENUITEM "", MIS_SEPARATOR MENUITEM "#105", IDM_FIVE, MIS_BITMAP END
Figure 5) New menu template
The MIS_BREAK style is normally used to build a submenu with two or more columns. Using it like this we create a menu with two rows, thus separating the menu items from the button items. Used in a window this should look something like this:
A complete working example can be found in the toolbar2.zip file.
Note: The menu control also has a style called MIS_BREAKSEPARATOR. Using this style, the rows or columns separated by this style should be separated by a line. I found that this worked perfectly with columns, but it didn't work with rows! Maybe this is a bug, maybe my RC compiler is buggy? Who knows?
That was simple enough, but what are the drawbacks?
- There isn't a line drawn between the buttonbar and the menubar. Of course this is a cosmetic effect, but I think it should be there. MIS_BREAKSEPARATOR should work, but it doesn't. I haven't fixed this yet, but it should be possible with an owner drawn menuitem (MIS_OWNERDRAWN).
- This is just one menu. That means it can't be split (buttons at the bottom or side of the frame window, normal menu on top).
- This also means the buttonbar and the normal menu can't be given different colors.
- Adding two toolbars, one on top, one at the bottom or side of the window is impossible
Of course, this method hasn't the flexibility of a toolbar as it was described in "Building Custom Controls", let alone the flexibility of a (great) package like UCMENU (see OS/2 Developer in the January/February 1995 issue). But if you can live with these drawbacks there are a number of pro's.
- It's very simple
- No extra programming needed, everything can be done with a resource editor.
- No subclassing required
A working example of a buttonbar created with this method is found in the file toolbar2.zip. This example is created and compiled with Borland C++ 2.0.
Feel free to use the code any way you like and send me your comments.