Home Step1 Step2 Step3 Step4 Step5
So you want to be a programmer... Part 3
Making a Great Circle Map program for Windows.


Adding a toolbar and statusbar

A toolbar duplicates the menu (not all items). Looks nice, but some more artistic person than me, could have made a more beatiful bitmap.

The statusbar gives information to the user. Here divided into 4 parts.

Code changed from part 2 on Yellow background.

Source is here.

#include <windows.h>
#include <commctrl.h>
#include "resource.h"


/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void HandleMenu (HWND hwnd, UINT Command);
HWND CreateStatusbar (HWND hwnd);
HWND CreateToolbar (HWND hwnd);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";
HWND hWndMain; /* This is the handle for our window */
HWND hWndStatusbar, hWndToolbar;

int WINAPI 
WinMain (HINSTANCE hThisInstance, 
        HINSTANCE hPrevInstance, 
        LPSTR lpszArgument, 
        int cmdShow)
{
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */
    HMENU hMenu;             /* Handle for the menu */
    HACCEL hAccKeys;

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);
    wincl.hIcon = LoadIcon (hThisInstance, MAKEINTRESOURCE (IDI_GCM));
    wincl.hIconSm = LoadIcon (hThisInstance, MAKEINTRESOURCE (IDI_GCM));
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hWndMain = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "GcmWin",            /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Load the menu */
      hMenu = LoadMenu (hThisInstance, "MAINMENU");
      SetMenu (hWndMain, hMenu);

    /* Load accelerator keys (ex. Ctrl-N) */
    hAccKeys = LoadAccelerators (hThisInstance, "IDR_ACCKEYS");

    /* Make the window visible on the screen */
    ShowWindow (hWndMain, cmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
		if (!TranslateAccelerator(hWndMain, hAccKeys, &messages))
		{
            TranslateMessage(&messages);
            /* Send message to WindowProcedure */
            DispatchMessage(&messages);
        }
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK
WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int iStatus[4]; // Number of fields in statusbar
    HWND hWndTT;
    LPTOOLTIPTEXT lpToolTipText;
    TOOLINFO lpToolInfo;
    char text[80];
    
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            hWndStatusbar = CreateStatusbar (hwnd);
            hWndToolbar = CreateToolbar (hwnd);
        break;
        
        case WM_COMMAND:
            HandleMenu (hwnd, LOWORD (wParam));
          break;

        case WM_SIZE:
            RECT rcFrame ,rc, rcClient;
            // get size of frame window
            GetClientRect(hwnd, &rcFrame);

            GetWindowRect(hWndToolbar, &rc);
            ScreenToClient(hwnd, (LPPOINT)&rc + 1);
            rcClient.top = rc.bottom;

            GetWindowRect(hWndStatusbar, &rc);
            ScreenToClient(hwnd, (LPPOINT)&rc);

            rcClient.bottom = rc.top - rcClient.top;

              SendMessage (hWndStatusbar, WM_SIZE, wParam, lParam);

              iStatus[3] = -1;
              iStatus[2] = LOWORD (lParam) - 70;
              iStatus[1] = LOWORD (lParam) - 140;
              iStatus[0] = LOWORD (lParam) - 210;

              SendMessage (hWndStatusbar, SB_SETPARTS, 4, (LPARAM) iStatus);
              SendMessage (hWndStatusbar, SB_SETTEXT, 0, (LPARAM) "Field 0");
              SendMessage (hWndStatusbar, SB_SETTEXT, 1, (LPARAM) "Field 1");
              SendMessage (hWndStatusbar, SB_SETTEXT, 2, (LPARAM) "Field 2");
              SendMessage (hWndStatusbar, SB_SETTEXT, 3, (LPARAM) "Field 3");

              SendMessage (hWndToolbar, TB_AUTOSIZE, 0L, 0L);
              InvalidateRgn (hWndMain, NULL, TRUE);
              break;
    
        case WM_NOTIFY:
          // Show tooltips
            if ((((LPNMHDR) lParam)->code) == TTN_NEEDTEXT)
            {
    	       lpToolTipText = (LPTOOLTIPTEXT) lParam;
    	  // load from resources
    	  LoadString ((HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
    		      lpToolTipText->hdr.idFrom,	// what menu command?
    		      text,	// the text
    		      sizeof (text));
    	  // Set the tooltip text
    	  lpToolTipText->lpszText = text;
    	}
          break;
    
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

void HandleMenu (HWND hwnd, UINT Command)
{

    switch (Command)
    {
        case IDM_NEW:
      	  MessageBox (NULL, "New Map", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_SAVEBMP:
      	  MessageBox (NULL, "Save Bitmap", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_SAVEBMPAS:
      	  MessageBox (NULL, "Save Bitmap AS", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_OPTIONS:
      	  MessageBox (NULL, "Options", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_DXPOS:
      	  MessageBox (NULL, "DxPos", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_ABOUT:
      	  MessageBox (NULL, "About", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_HELP:
      	  MessageBox (NULL, "Help", "Menu", MB_OK | MB_ICONINFORMATION);
        break;

        case IDM_EXIT:
          PostQuitMessage (0);
        break;
    }
  return;
}

HWND CreateStatusbar (HWND hwnd)
{
  HWND hWndFields;

  hWndFields = CreateStatusWindow (WS_CHILD | WS_VISIBLE |
		   CCS_ADJUSTABLE | SBARS_SIZEGRIP, NULL, hwnd, IDR_STATUS);
  return hWndFields;
}

HWND CreateToolbar (HWND hwnd)
{
  const int NUMBUTTS = 8; // Number of buttons

  TBBUTTON tbButtns[NUMBUTTS];
  HBITMAP hbPict;

  HINSTANCE hInst = (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE);
  int i;

  hbPict = LoadBitmap (hInst, MAKEINTRESOURCE (IDB_TOOL));

  for (i = 0; i < NUMBUTTS; i++)
    {
      tbButtns[i].idCommand = 0;
      tbButtns[i].fsState = TBSTATE_ENABLED;
//    if ((i >= 1) && (i <= 4))  // If you want to group together some btns
//	     tbButtns[i].fsStyle = TBSTYLE_BUTTON | TBSTYLE_CHECKGROUP;
//      else
	   tbButtns[i].fsStyle = TBSTYLE_BUTTON;
	   tbButtns[i].dwData = 0;
	   tbButtns[i].iString = 0;
    }

  tbButtns[0].iBitmap = 0;  // Number in bitmap
  tbButtns[0].idCommand = IDM_NEW; // Menu command
  tbButtns[1].iBitmap = 1;
  tbButtns[1].idCommand = IDM_SAVEBMP;

  tbButtns[2].iBitmap = -1; // Separator
  tbButtns[2].fsStyle = TBSTYLE_SEP;

  tbButtns[3].iBitmap = 3;
  tbButtns[3].idCommand = IDM_EXIT;
  tbButtns[4].iBitmap = 4;
  tbButtns[4].idCommand = IDM_OPTIONS;
  tbButtns[5].iBitmap = 5;
  tbButtns[5].idCommand = IDM_DXPOS;

  tbButtns[6].iBitmap = -1; // Separator
  tbButtns[6].fsStyle = TBSTYLE_SEP;

  tbButtns[7].iBitmap = 6;
  tbButtns[7].idCommand = IDM_HELP;


  // buttons and icons 16x16 pixels
  return CreateToolbarEx (hwnd, WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS, IDR_TOOLB,
            NUMBUTTS, NULL, (UINT) hbPict, tbButtns, NUMBUTTS, 16, 16,
            16, 16, sizeof (TBBUTTON));
}

resource.h

#define	IDB_TOOL 60
#define	IDI_GCM	120

#define	IDR_TOOLB	         800
#define	IDR_STATUS	900

#define	IDM_NEW	       10001
#define	IDM_SAVEBMP     10002
#define	IDM_SAVEBMPAS   10003
#define	IDM_EXIT        10005
#define	IDM_OPTIONS     10006
#define	IDM_DXPOS       10007
#define	IDM_ABOUT       10008
#define	IDM_HELP        10009

step3.rc

#include <windows.h>
#include "resource.h"

IDB_TOOL BITMAP "toolbar.bmp"
IDI_GCM  ICON "gcmw.ico"

MAINMENU MENU
BEGIN
    POPUP "&File"
        BEGIN
        MENUITEM "&New Map",        IDM_NEW
        MENUITEM SEPARATOR
        MENUITEM "&Save Bitmap",    IDM_SAVEBMP
        MENUITEM "Save Bitmap &As", IDM_SAVEBMPAS
        MENUITEM SEPARATOR
        MENUITEM "&Exit",           IDM_EXIT
        END
    MENUITEM "&Options",            IDM_OPTIONS
    MENUITEM "&DxPos" ,             IDM_DXPOS
    POPUP "&Help"
        BEGIN
        MENUITEM "&Help",           IDM_HELP
        MENUITEM SEPARATOR
        MENUITEM "About &GcmWin	",  IDM_ABOUT
        END
END


STRINGTABLE // tooltip text
BEGIN
    IDM_NEW, "Create a new map"
    IDM_SAVEBMP, "Save the map as a bmp"
    IDM_EXIT, "Exit Program"
    IDM_OPTIONS, "Set your preferences"
    IDM_DXPOS, "Show the DXpos dialog"
    IDM_HELP, "Helpfile!"
END



In this part of the series you have to add a library. This library comes in different versions with Internet Explorer. If you are going to use more advanced functions you might want to check the version of this library on the client first!

The library added is actually libcomctl32.a but the starting "lib" and the ".a" is stripped.

Both the status bar and the toolbar are parts of this library!

Select "Project" -> "Build Options..." -> Select "Step3" (both Debug and Release nedd this lib) -> Click on the tab "Linker settings" -> Click "Add" -> type "comctl32" (without quotes) -> Ok -> Ok

Still doesn't do much, but looking nicer!

Step 2 _ Step4