Statusbar and Progressbar common controls

Source by Todd Nist, Protech Systems Inc.
Modified by Simon Sweetman

The library COMCTL32.DLL contains common controls like the Status Bar control. This example, provided by Todd Nist, shows how to use the Status Bar control in a Progress window. Simon Sweetman added the progressbar. The example will produce a window that looks like this:


The Status Bar in this example is divided in three parts: the first part contains a progressbar which displays the value of the slider, the second part is shown with SBT_POPOUT style so it appears raised.
Button WriteStatusBar results in sending window-messages to the Status Bar control, in this case message SB_SETTEXT. The control also accepts other messages like SB_SETPARTS (to change the size or count of parts), SB_SETICON (to show an icon in a part) or SB_SETTIPTEXT (to set a tooltip for a part). However SB_SETICON and SB_SETTIPTEXT are only available in comctl32.dll version 4.71 or newer.

/*------------------------------------------------------------------------
  File: StatusExample.p
  Author: Todd Nist, Protech Systems Inc.
  Created: 5/19/98
  Modifications:
    28/11/00 Simon Sweetman - Added progress meter control
------------------------------------------------------------------------*/
&SCOP WINDOW-NAME C-Win
&SCOP FRAME-NAME DEFAULT-FRAME
 
CREATE WIDGET-POOL.
 
/* ***************************  Definitions  ************************** */
 
/* Local Variable Definitions ---                                       */
{windows.i}
 
&SCOPE WM_USER         1024
&SCOPE SB_SETPARTS     {&WM_USER} + 4
&SCOPE SB_SETTEXT      {&WM_USER} + 1
&SCOPE SB_GETRECT      {&WM_USER} + 10
&SCOPE PBM_SETRANGE    {&WM_USER} + 1
&SCOPE PBM_SETPOS      {&WM_USER} + 2
&SCOPE SBT_NORMAL      0
&SCOPE SBT_POPOUT      512
&SCOPE SBT_NOBORDERS   256
 
/* variables to hold handle control objects */
 
DEFINE VARIABLE hStatusBar AS  INTEGER NO-UNDO.
DEFINE VARIABLE progHWND   AS  INTEGER NO-UNDO.
 
PROCEDURE CreateStatusWindow EXTERNAL "comctl32.dll":
  DEFINE INPUT  PARAMETER lStyle      AS  LONG.
  DEFINE INPUT  PARAMETER lpctStr     AS  CHARACTER.
  DEFINE INPUT  PARAMETER hwndParent  AS  LONG.
  DEFINE INPUT  PARAMETER wId         AS  LONG.
  DEFINE RETURN PARAMETER hStatusArea AS  LONG.
END PROCEDURE.
 
PROCEDURE InitCommonControls EXTERNAL "comctl32.dll":
END PROCEDURE.
 
/* Standard preprocessor definitions */
&SCOPED-DEFINE PROCEDURE-TYPE WINDOW
&SCOPED-DEFINE ENABLED-OBJECTS BtnCreateStatus BtnWriteStatus SLIDER-1
 
/* ************************  Function Prototypes ********************** */
 
FUNCTION CreateProgressArea RETURNS INTEGER
  ( INPUT phStatusBar  AS INTEGER,
    INPUT piStatusArea AS INTEGER,
    INPUT piMaxValue AS INTEGER) FORWARD.
 
FUNCTION CreateStatusBar RETURNS INTEGER
  ( /* parameter-definitions */ )  FORWARD.
 
FUNCTION SetProgressArea RETURNS LOGICAL
  ( INPUT phProgressArea  AS INTEGER,
    INPUT piValue AS INTEGER ) FORWARD.
 
FUNCTION WriteStatusArea RETURNS LOGICAL
  ( INPUT phStatusBar  AS INTEGER,
    INPUT piStatusArea AS INTEGER,
    INPUT piSBTextMode AS INTEGER,
    INPUT pcText       AS CHARACTER )  FORWARD.
 
/* ***********************  Control Definitions  ********************** */
 
/* Define the widget handle for the window                              */
DEFINE VARIABLE C-Win AS WIDGET-HANDLE NO-UNDO.
 
/* Menu Definitions                                              */
DEFINE SUB-MENU m_File
       MENU-ITEM m_Exit         LABEL "E&xit"         .
 
DEFINE MENU MENU-BAR-C-Win MENUBAR
       SUB-MENU  m_File         LABEL "File"          .
 
 
/* Definitions of the field level widgets                               */
DEFINE BUTTON BtnCreateStatus
     LABEL "Create Status Bar"
     SIZE 25 BY 1.
 
DEFINE BUTTON BtnWriteStatus
     LABEL "WriteStatusBar"
     SIZE 25 BY 1.
 
DEFINE VARIABLE SLIDER-1 AS INTEGER INITIAL 0 
     VIEW-AS SLIDER MIN-VALUE 0 MAX-VALUE 100 HORIZONTAL 
     SIZE 45 BY 2 NO-UNDO. 
 
/* ************************  Frame Definitions  *********************** */
 
DEFINE FRAME {&FRAME-NAME}
     SLIDER-1 AT ROW 1 COL 7 NO-LABEL
     BtnCreateStatus AT ROW 6 COL 6
     BtnWriteStatus AT ROW 6 COL 50
    WITH 1 DOWN NO-BOX KEEP-TAB-ORDER OVERLAY
         SIDE-LABELS NO-UNDERLINE THREE-D
         AT COL 1 ROW 1
         SIZE 80 BY 8.
 
 
/* *************************  Create Window  ************************** */
 
IF SESSION:DISPLAY-TYPE = "GUI":U THEN
  CREATE WINDOW C-Win ASSIGN
         HIDDEN             = YES
         TITLE              = "StatusBar Example"
         HEIGHT             = 8
         WIDTH              = 80
         MAX-HEIGHT         = 8
         MAX-WIDTH          = 80
         VIRTUAL-HEIGHT     = 8
         VIRTUAL-WIDTH      = 80
         RESIZE             = YES
         SCROLL-BARS        = NO
         STATUS-AREA        = NO
         BGCOLOR            = ?
         FGCOLOR            = ?
         KEEP-FRAME-Z-ORDER = YES
         THREE-D            = YES
         MESSAGE-AREA       = NO
         SENSITIVE          = YES.
ELSE {&WINDOW-NAME} = CURRENT-WINDOW.
 
ASSIGN {&WINDOW-NAME}:MENUBAR    = MENU MENU-BAR-C-Win:HANDLE.
 
/* ***************  Runtime Attributes and UIB Settings  ************** */
 
IF SESSION:DISPLAY-TYPE = "GUI":U AND VALID-HANDLE(C-Win)
THEN C-Win:HIDDEN = NO.
 
/* ************************  Control Triggers  ************************ */
 
ON END-ERROR OF C-Win /*  */
OR ENDKEY OF {&WINDOW-NAME} ANYWHERE DO:
  /* This case occurs when the user presses the "Esc" key.
     In a persistently run window, just ignore this.  If we did not, the
     application would exit. */
  IF THIS-PROCEDURE:PERSISTENT THEN RETURN NO-APPLY.
END.
 
ON WINDOW-CLOSE OF C-Win /*  */
DO:
  /* This event will close the window and terminate the procedure.  */
  APPLY "CLOSE":U TO THIS-PROCEDURE.
  RETURN NO-APPLY.
END.
 
ON VALUE-CHANGED OF SLIDER-1 IN FRAME {&FRAME-NAME} /* Create Status Bar */
DO:
  IF ProgHWND NE 0
  THEN SetProgressArea(progHWND, INT(SELF:SCREEN-VALUE) * 10).
END.
 
ON CHOOSE OF BtnCreateStatus IN FRAME {&FRAME-NAME} /* Create Status Bar */
DO:
  hStatusBar = CreateStatusBar().
END.
 
ON CHOOSE OF BtnWriteStatus IN FRAME {&FRAME-NAME} /* WriteStatusBar */
DO:
  DEFINE VARIABLE i AS i NO-UNDO.
 
  DO i = 1 TO 2.
    WriteStatusArea(hStatusBar,
                    i,
                    IF i = 1 THEN {&SBT_POPOUT} ELSE {&SBT_NORMAL},
                    SUBSTITUTE('Message &1 here...', STRING(i,'9'))).
  END.
  progHWND = CreateProgressArea(hStatusBar, 0, 1000).
 
END.
 
ON CHOOSE OF MENU-ITEM m_Exit /* Exit */
DO:
  APPLY 'WINDOW-CLOSE':U TO {&WINDOW-NAME}.
END.
 
/* ***************************  Main Block  *************************** */
 
ASSIGN CURRENT-WINDOW                = {&WINDOW-NAME}
       THIS-PROCEDURE:CURRENT-WINDOW = {&WINDOW-NAME}.
 
ON CLOSE OF THIS-PROCEDURE
   RUN disable_UI.
 
PAUSE 0 BEFORE-HIDE.
 
MAIN-BLOCK:
DO ON ERROR   UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
   ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
  {win32/struct/rect.i} /* Used by CreateProgressArea function */
  RUN enable_UI.
  IF NOT THIS-PROCEDURE:PERSISTENT THEN
    WAIT-FOR CLOSE OF THIS-PROCEDURE.
END.
 
/* **********************  Internal Procedures  *********************** */
 
PROCEDURE disable_UI :
/*-----------------------------------------------------------------------------
  Purpose:     DISABLE the User Interface
  Parameters:  
  Notes:       Here we clean-up the user-interface by deleting
               dynamic widgets we have created and/or hide
               frames.  This procedure is usually called when
               we are ready to "clean-up" after running.
------------------------------------------------------------------------------*/
  /* Delete the WINDOW we created */
  IF SESSION:DISPLAY-TYPE = "GUI":U AND VALID-HANDLE(C-Win)
  THEN DELETE WIDGET C-Win.
  IF THIS-PROCEDURE:PERSISTENT THEN DELETE PROCEDURE THIS-PROCEDURE.
END PROCEDURE.
 
PROCEDURE enable_UI :
/*------------------------------------------------------------------------------
  Purpose:     ENABLE the User Interface
  Parameters:  none
  Notes:       Here we display/view/enable the widgets in the
               user-interface.  In addition, OPEN all queries
               associated with each FRAME and BROWSE.
               These statements here are based on the "Other
               Settings" section of the widget Property Sheets.
------------------------------------------------------------------------------*/
  ENABLE BtnCreateStatus BtnWriteStatus SLIDER-1
      WITH FRAME {&FRAME-NAME} IN WINDOW C-Win.
  {&OPEN-BROWSERS-IN-QUERY-{&FRAME-NAME}}
  VIEW C-Win.
END PROCEDURE.
 
FUNCTION CreateProgressArea RETURNS INTEGER
  (INPUT phStatusBar  AS INTEGER,
   INPUT piStatusArea AS INTEGER,
   INPUT piMaxValue   AS INTEGER):
/*------------------------------------------------------------------------------
  Purpose: Create status bar progress meter control
    Notes: Return value is window handle of control
------------------------------------------------------------------------------*/
 
  DEFINE VARIABLE hwndParent    AS  INTEGER NO-UNDO.
  DEFINE VARIABLE hInstance     AS  INTEGER NO-UNDO.
  DEFINE VARIABLE ReturnValue   AS  INTEGER NO-UNDO.
  DEFINE VARIABLE ReturnHwnd    AS  INTEGER NO-UNDO.
 
  SET-SIZE(lpRect) = 16. /* allocate space for rect object */
 
  /* Get screen postion of required status bar area */
  RUN SendMessageA IN hpApi(INPUT  phStatusBar,
                            INPUT  {&SB_GETRECT},
                            INPUT  piStatusArea,
                            INPUT  GET-POINTER-VALUE(lpRect),
                            OUTPUT ReturnValue).
  RUN mem2buf_lpRect.
 
  SET-SIZE(lpRect) = 0. /* release allocated space */
 
  RUN GetParent IN hpApi({&WINDOW-NAME}:HWND,
                         OUTPUT hwndParent).
 
  RUN GetWindowLongA IN hpApi(hwndParent,
                              -6,  /* GWL_HINSTANCE */
                              OUTPUT hInstance).
 
  /* Create the progress meter window control and parent it to status window */
  RUN CreateWindowExA IN hpApi(
    8,                              /* extended style */
    "msctls_progress32":U,          /* progress meter class name */
    "",                              /* window name */
    1073741824   /* = WS_CHILD   */
    + 1          /* = PBS_SMOOTH */
    + 268435456, /* = WS_VISIBLE */   /* window styles */
    lpRect.LEFT,
    lpRect.TOP,
    lpRect.RIGHT - lpRect.LEFT, 
    lpRect.BOTTOM - lpRect.TOP,     /* window position & size */
    phStatusBar,                    /* parent window */
    0,                              /* menu pointer */
    hInstance,                      /* instance */
    0,                              /* parameters */
    OUTPUT ReturnHwnd).
 
  /* set maximum value of progress meter control */
  RUN SendMessageA IN hpApi(INPUT  ReturnHwnd,
                            INPUT  {&PBM_SETRANGE},
                            INPUT  0,
                            INPUT  piMaxValue * 65536,
                            OUTPUT ReturnValue).
  RETURN ReturnHwnd.
 
END FUNCTION.
 
FUNCTION CreateStatusBar RETURNS INTEGER
  ( /* parameter-definitions */ ) :
/*------------------------------------------------------------------------------
  Purpose:
    Notes:
------------------------------------------------------------------------------*/
  DEFINE VARIABLE hwndMenu      AS  INTEGER NO-UNDO.
  DEFINE VARIABLE hwndParent    AS  INTEGER NO-UNDO.
  DEFINE VARIABLE hInstance     AS  INTEGER NO-UNDO.
  DEFINE VARIABLE hWindowMenu   AS  INTEGER NO-UNDO.
  DEFINE VARIABLE hStatusArea   AS  INTEGER NO-UNDO.
  DEFINE VARIABLE lpParam       AS  MEMPTR  NO-UNDO.
  DEFINE VARIABLE ReturnValue   AS  INTEGER NO-UNDO.
 
  /*---------------------------------------------------------------------
    Allocate memory and define the array to support the segments of the
    status area.
  -----------------------------------------------------------------------*/
  ASSIGN
    SET-SIZE(lpParam)    = 256
    PUT-LONG(lpParam,1)  = 120
    PUT-BYTE(lpParam,5)  = 240
    PUT-LONG(lpParam,9)  = -1.  /* extend to the right edge of the window */
 
  /* find handle to the Parent handle of the Window */
  RUN GetParent IN hpApi({&WINDOW-NAME}:HWND,
                         OUTPUT hwndParent).
 
  RUN GetWindowLongA IN hpApi(hwndParent,
                              -6,  /* GWL_HINSTANCE */
                              OUTPUT hInstance).
 
 
  /* Call InitCommonControls to ensure that the comctl32.dll is loaded */
  RUN InitCommonControls.
 /* hwndParent */
 
  /* Create the status window control and parent it to the window */
  RUN CreateStatusWindow
    (   1073741824 /* = WS_CHILD         */
      + 268435456  /* = WS_VISIBLE       */  /* window styles */
      + 8388608,   /* = WS_BORDER        */
     '',                                         /* default text */
     hwndParent,                                 /* parent window */
     101,                                        /* ID_STATUS */
     OUTPUT hStatusArea).
 
  IF hStatusArea = 0 THEN
    MESSAGE 'Unable to create the status bar...' VIEW-AS ALERT-BOX.
  ELSE
    /* create the multiple segments based on the data in lpParam */
    RUN SendMessageA IN hpApi( INPUT  hStatusArea,
                               INPUT  {&SB_SETPARTS},
                               INPUT  3,         /* number of parts */
                               INPUT GET-POINTER-VALUE(lpParam),
                               OUTPUT ReturnValue).
 
  /* deallocate the memory */
  ASSIGN
    SET-SIZE(lpParam)  = 0.
 
  RETURN hStatusArea.   /* Function return value. */
 
END FUNCTION.
 
FUNCTION SetProgressArea RETURNS LOGICAL
  ( INPUT phProgressArea  AS INTEGER,
    INPUT piValue AS INTEGER ) :
/*------------------------------------------------------------------------------
  Purpose:  Update progress indicator value and redisplay
    Notes:
------------------------------------------------------------------------------*/
  DEFINE VARIABLE ReturnValue AS INTEGER NO-UNDO.
 
  RUN SendMessageA IN hpApi(INPUT  phProgressArea,
                            INPUT  {&PBM_SETPOS},
                            INPUT  piValue,
                            INPUT  0,
                            OUTPUT ReturnValue).
  RETURN TRUE.
 
END FUNCTION.
 
FUNCTION WriteStatusArea RETURNS LOGICAL
  ( INPUT phStatusBar  AS INTEGER,
    INPUT piStatusArea AS INTEGER,
    INPUT piSBTextMode AS INTEGER,
    INPUT pcText       AS CHARACTER ) :
/*------------------------------------------------------------------------------
  Purpose:  Write the text in the appropriat format to the appropriate area
    Notes:
------------------------------------------------------------------------------*/
  DEFINE VARIABLE lpParam     AS MEMPTR  NO-UNDO.
  DEFINE VARIABLE ReturnValue AS INTEGER NO-UNDO.
 
  ASSIGN
    SET-SIZE(lpParam)     = 256
    PUT-STRING(lpParam,1) = pcText.
 
  RUN SendMessageA IN hpApi(INPUT  phStatusBar,
                            INPUT  {&SB_SETTEXT},
                            INPUT  piStatusArea + piSBTextMode,
                            INPUT  GET-POINTER-VALUE(lpParam),
                            OUTPUT ReturnValue).
 
  /* deallocate the memory */
  ASSIGN
    SET-SIZE(lpParam)  = 0.
 
  RETURN TRUE.
 
END FUNCTION.

Explanations

message SB_SETTEXT has the following parameters:
* wParam = iPart + uType
* lParam = text. The text for each part is limited to 127 characters.
* iPart is the index of the part to set. If iPart=255 you will get a 'simple' status bar with only one part.

uType can be:
* {&SBT_NORMAL} : border, appears lower
* {&SBT_NOBORDERS} : no border, no 3D effect
* {&SBT_POPOUT} : border, appears higher

Note

The Status Bar has a sizing grip because it is parented to the resizable window. It will not have a sizing grip when you parent it to the frame :

/* Create the status window control and parent it to the frame */
  RUN CreateStatusWindow
    (   1073741824   /* = WS_CHILD           */
      +  268435456   /* = WS_VISIBLE         */  /* window styles */
      +    8388608,  /* = WS_BORDER          */
     '',                                         /* default text */
     FRAME {&frame-name}:HWND,                   /* parent       */
     101,                                        /* ID_STATUS    */
     OUTPUT hStatusArea).

This also solves the repaint problem: if the status bar is parented to the window, it will appear to be invisible after the window is repainted.

Note

There's another way to solve the repaint problem, and to keep the StatusBar parented to the window (and therefore keep the "sizing grip").
Simply run:

   RUN SendMessageA IN hpApi(INPUT  phStatusBar,
                             INPUT  5, /* WM_SIZE */
                             INPUT  0,
                             INPUT  0,
                             OUTPUT ReturnValue).

For instance, at the end of a WINDOW-RESIZED event (or after a "ShowScrollBar")


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Can I add Panels to the Progress Status Area?

I just looked at this example, which in itself is great and very useful :) I was however wondering whether it is possible to add "panels" to the existing Progress Status area of a window. If that is possible one would not loose the existing "help" functionality offered by the Status Area while also being able to offer some additional information to the user.

Any help/information is appreciated!

Paul


Progress Status Area

Paul,

It is not possible to add panel to the progress status area. I looked at the example provided at OEhieve but decided to use window's MSCOMCTL OCX control. I found it easy to implement. The ProTools com control API can be used to implement this statusbar control.

Thanks
Shanker


Hi Shanker, Thanks for your

Hi Shanker,

Thanks for your reply. Yes, I know I can use that specific ActiveX control. However, using an ActiveX control means we'd loose the information that is normally shown in the Progress status area (for instance "help" defined on widgets would no longer be visible).

Paul


fifino14's picture

How can i create status bar using graphical object /ocx.

How can i create status bar using graphical object /oxc?
any one who can help me?
tnx.