CHAPTER 15

HOW TO CREATE TOOLBARS.

TOOLBARS OVERVIEW:

There are two possible ways in which you can create a toolbar, with its toolbar buttons.

The first way is to use child windows of the main window, and the second is to use your own code to create a custom toolbar and buttons from scratch.

I much prefer the second method, despite the extra code involved, because it gives much greater programming control over the toolbar, and its operation. The use of child windows requires working with relationships between the child window and parent window that are implemented within the system. There are aspects of these relationships over

which you have no control. This creates the possibility of getting unpredictable results, which then requires an effort to work out what mistake has been made in relating the windows to one another. In general, as a matter of policy, I see it as preferable to make as little use as possible of system-provided features that become involved in the working of your code, if you can code them yourself, since you then have full access to, and control over, the working of the code involved.

I shall therefore only briefly refer to the creation of a toolbar, using child windows, and concentrate on the creation of a custom toolbar, and its buttons.

CREATING A TOOLBAR, USING CHILD WINDOWS:

A toolbar can be a child window of the main window, which is called its 'parent'. The buttons in a toolbar are child windows of the toolbar, and not of the main window. If you make them child windows of the main window, they won't appear on the screen in the toolbar. A child window always appears within the client area of its parent window, and the program code specifies the location, width, and height of the child window in the client area. In the case of a toolbar, of course, the window is specified to be at the top left corner of the client area of the main window, having the same width as the client area, and a height sufficient to accommodate the toolbar button heights. The buttons, in turn, are specified to start at the top left corner of the toolbar, if it is just high enough to accommodate them, with each button's horizontal position starting just beyond the previous button's right hand edge.

To create a child window, you use the normal

CreateWindowEx API function with, however, a WS_CHILD flag, and a handle to its parent, whether this is the main window, or another child window of the main window. Toolbar buttons can be created, in the same way, as child windows of the toolbar child window, i.e. as grandchildren of the main window. The buttons will thus appear in the client area of the toolbar, and their locations are specified by coordinates entered as parameters in the CreateWindowEx function that creates them. A toolbar and toolbar buttons can thus be created as shown below.

Creating a series of toolbar buttons means using the second and subsequent API functions, shown below, however many times might be necessary, once for each button, and changing the coordinates of the button each time, so that one button appears next to the previous one.

api CreateWindowEx,0,WND.Class,0,WS_CHILD,0,0,[Wth],[Ht],[WINDOW.Handle],1,[hInst],0
mov [TOOLBAR.Handle], eax

api CreateWindowEx,0,WND.Class.b,0,WS_CHILD,0,0,[Wth],[Ht],[TOOLBAR.Handle],1,[hInst],0
mov [BUTTON1.Handle], eax
api CreateWindowEx,0,WND.Class.b,0,WS_CHILD,0,0,[Wth],[Ht],[TOOLBAR.Handle],1,[hInst],0
mov [BUTTON2.Handle], eax
etc.

CREATING AND USING A CUSTOM TOOLBAR, WITHOUT USING CHILD WINDOWS:

To create a custom toolbar, you simply assign a region at the top of the client area of your window as the toolbar region. If, as I recommend, you also have a bitmap that corresponds to the screen client area, which acts as a virtual screen that can always be immediately printed to the screen, whenever required, you will also have the corresponding top portion of the bitmap assigned to the toolbar. You can then exclude this region of the screen from all non-toolbar operations

The principle of dividing up a screen into different areas assigned to different uses can be required for purposes other than a toolbar, and the same technique applies in all cases.

It is a good idea to organise and name the different sections of the screen at the start of your program, and locate their positions (i.e. starting memory addresses) within the virtual screen bitmap.

LOCATING THE TOOLBAR AND TOOLBAR BUTTONS:

There are two methods of specifying the location of an area of the screen.

The first is to use the horizontal and vertical coordinates of the top left corner of the area, and the second is to compute the address, within the bitmap memory block, of the top left corner pixel.

The coordinates of an area are used to test whether or not the mouse cursor is currently within the particular area of the screen, and the starting address of the memory block is used to start printing or updating the data within an area.

Any area of the screen is fully specified by its

horizontal and vertical coordinates, together with its width and height, and its memory block starting address can be computed from these values.

The locations of the different areas can be specified as a response to the WM_CREATE message, at the initial creation of the main window. This message is intercepted by the program code. The main screen bitmap can be created, and all the bitmal memory block starting addresses of the toolbar and button areas can then be computed, as well as other special areas, if required. The WM_CREATE message is then returned to Windows to be used by the operating system to continue with the creation of the window.

PAINTING THE TOOLBAR BUTTON BITMAPS:

Once you have the starting addresses of the toolbar and its buttons, you can begin painting them into the bitmap memory block. The question that naturally arises here is: how do I specify the pictures or icons that will appear in the toolbar buttons?

There are different ways in which button icons can be specified. Since each button is relatively small, I prefer the method that directly specifies them, on a pixel by pixel basis, in the program's data in memory. This involves creating a colour table for the icon, and specifying the offset into this colour table for each pixel in the toolbar button.

To initially create the button pictures, which will probably be 16x16 pixels in size, you can draw them, as 16x16 icons. When you have created an icon that you are satisfied with, make a record of all the colours you have used, and construct a colour table by listing them one after the other.

Once you have the colour table, you can write down the offset into the table of each pixel colour, by hand, and create the pixel colour specification array for the button bitmap. Since the bitmaps are small, this is an easy task, and can be completed relatively quickly and, of course, you have to create the button icon bitmap sources only once for any particular program. The following is an example of a single button created in this way:

BTN.SRC.ColourTable
dd 0,0ffh,0ffffffh,0,0ff0000h,0e0e0e0h
;
BTN1.SRC
db 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
db 5,0,0,0,0,0,0,1,1,0,0,0,0,0,0,5,
db 5,0,0,0,0,0,0,1,1,0,0,0,0,0,0,5,
db 5,0,0,0,0,0,0,1,1,0,0,0,0,0,0,5,
db 5,0,0,0,0,0,0,1,1,0,0,0,0,0,0,5,
db 5,0,0,0,1,1,1,1,1,1,1,1,0,0,0,5,
db 5,0,0,0,1,1,1,1,1,1,1,1,0,0,0,5,
db 5,0,0,0,2,2,2,2,2,2,2,2,0,0,0,5,
db 5,0,0,3,3,3,3,3,3,3,3,3,0,0,0,5,
db 5,0,0,3,3,3,3,3,3,3,3,0,0,0,0,5,
db 5,0,0,3,3,3,3,3,3,3,0,0,0,0,0,5,
db 5,0,0,3,3,3,3,3,3,0,0,0,0,0,0,5,
db 5,4,4,3,4,3,4,3,4,4,4,4,4,4,4,5,
db 5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,
db 5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,
db 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
;
BTN1.SRC.Pushed
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
db 3,0,0,0,0,0,0,0,1,1,0,0,0,0,0,2,
db 3,0,0,0,0,0,0,0,1,1,0,0,0,0,0,2,
db 3,0,0,0,0,0,0,0,1,1,0,0,0,0,0,2,
db 3,0,0,0,0,0,0,0,1,1,0,0,0,0,0,2,
db 3,0,0,0,0,0,0,0,1,1,0,0,0,0,0,2,
db 3,0,0,0,0,1,1,1,1,1,1,1,1,0,0,2,
db 3,0,0,0,0,1,1,1,1,1,1,1,1,0,0,2,
db 3,0,0,0,0,2,2,2,2,2,2,2,2,0,0,2,
db 3,0,0,0,3,3,3,3,3,3,3,3,3,0,0,2,
db 3,0,0,0,3,3,3,3,3,3,3,3,0,0,0,2,
db 3,0,0,0,3,3,3,3,3,3,3,0,0,0,0,2,
db 3,0,0,0,3,3,3,3,3,3,0,0,0,0,0,2,
db 3,4,4,4,3,4,3,4,3,4,4,4,4,4,4,2,
db 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,
db 3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2

The first array of numbers is the source of the left hand button shown above, and the second array is the source of the right hand button. Each number is an offset into the colour table. For example, colour no 2 is the colour 0ffffffh, which is the colour white. There are two zero colours (black), but the first zero is used by the code as a transparent colour, so that only colour no. 3 is actually black.

If the user presses the left mouse button when the mouse is over the left hand button, this sends a WM_LEFTBUTTONDOWN message (which also contains the coordinates of the mouse cursor) to the program code. The program examines the coordinates and, if these are within the button rectangle on the screen, it calls a procedure to replace the left hand button bitmap in the screen bitmap with the right hand button, by reading the pixel colours, one by one, into the screen bitmap, in the correct positions, and then printing this rectangle to the visible screen. The user will thus see the button replaced by the pressed version of the button, so that the left mouse button appears to push the screen button inwards.

In order to create a pushed button effect, you will notice that the top and left hand sides of the button become dark, and the bottom and right hand sides of the button bitmap become white. This gives the effect of an illumination of the button recess by a light somewhere beyond the top left corner of the button. Also, the button picture is moved one pixel diagonally to the right and downward, which gives an effect as if the whole button has been moved, or pushed, inwards.

This, in general, is a very easy way to create any number of buttons, which can be placed wherever you want to place them on your program screen.

Of course, if pressing a button is to create some effect in addition to replacing the button with the pressed version (or vice versa), the code will identify which button is pressed and select the code response for that particular button.

                  Part I: Part I Introduction
                  Chapter 1: Binary numbers, code, and procedures
                  Chapter 3: Assembly Language
                  Chapter 4: Assembly Language Code example
                  Chapter 5: Macros and HLA
                  Chapter 6: HLA code example
                  Chapter 7: The Windows operating system
                  Chapter 8: Data Structures
                  Chapter 9: How to Create a Windows Program
                  Chapter 10: How to Create an Exe File
                  Chapter 11: Structured Programming and OOP
                  Part II: Part II Introduction
                  Chapter 12: Debugging a Windows Program Code
                  Chapter 13: Painting the Window Client Area
                  Chapter 14: Creating Window Menus
                  Chapter 15: How to Create Toolbars
                  Chapter 16: How to Create Popup Menus
                  Chapter 17: About the Windows Clipboard
                  Chapter 18: How to Create Bitmaps
                  Chapter 19: Icons and the Ico Format
                  Chapter 20: Common Dialog Boxes
                  Chapter 21: Working with Files
                  Chapter 22: Scrollbars and Scrolling
                  Chapter 23: How to Send Data to the Printer
                  Chapter 24: Miscellaneous Topics

© Alen, June 2014
alen@alenspage.net


Material on this page may be reproduced
for personal use only.