Chapter 5: Using a Button

Making the Button Do Something

Now that you are able to display a control on the screen, it's time to make that control perform an action if the user clicks on it.

In this chapter, I will introduce the ACTION property, which you can associate with many of the controls available in HMG, and introduce a set of standard "pop-up" messages and controls, which will be quite familiar to most computer users.

I will also introduce the concept of syntax and explain what this means, why it is important to understand and how to "use" it.

Using your chosen editor, enter the code below and save the file to the MySourceCode folder naming it HMGGuide-Ch5.prg then compile the program using the "..\build HMGGuide-Ch5" command.

  #include "hmg.ch"

  FUNCTION Main()

  LOCAL cMainWinTitle := "ePortfolio"
  LOCAL cBtn1Cap := "Button 1"
  LOCAL nBtn1Row := 32
  LOCAL nBtn1Col := 64
  LOCAL nBtn1Wide := 60
  LOCAL nBtn1High := 100

  DEFINE WINDOW Win_1 ;
    AT 0,0 ;
    WIDTH 760 ;
    HEIGHT 640 ;
    TITLE cMainWinTitle ;
    WINDOWTYPE MAIN

    DEFINE BUTTON btn1
      ROW nBtn1Row
      COL nBtn1Col
      WIDTH nBtn1Wide
      HEIGHT nBtn1High
      CAPTION cBtn1Cap
      PICTURE "c:\hmg.3.4.0\MySourceCode\Icons\IconCh4.bmp"
      ACTION MsgBox("The User has clicked on Button 1", ;
            "Pop-Up Message Box")
      END BUTTON

  END WINDOW

  CENTER WINDOW Win_1
  ACTIVATE WINDOW Win_1

  RETURN Nil

You can download a copy of the source code file from here - HMGGuide-Ch5.prg

The first thing you will notice is that the code above is little changed from the end of chapter 4 with one very notable exception! We have now added an ACTION property and an argument with the value MsgBox to the DEFINE BUTTON directive and it is this that will be executed if a user clicks on the picture button.

ACTION MsgBox("The User has clicked on Button 1", ;
    "Pop-Up Message Box")

As stated above, the ACTION property is used to specify which function or procedure you want the program to run if the user clicks on the picture button. In this example, a "standard function" called MsgBox() will be run and this is one of a number of standard functions included with HMG. It is also equally possible to call your own UDF that isn't included with HMG and we will explore that in the next chapter.

MsgBox("The User has clicked on Button 1", ;
    "Pop-Up Message Box")

This standard function, which you can think of as meaning "message box", instructs the program to display a pop-up message on the screen when the user clicks on the button. All functions, standard and UDF, are specified in your code by their name followed by opening and closing brackets (i.e. no space between the function name and the opening bracket). Within these brackets, certain information, known as parameters, might be included which may be needed by the function for it to work.

Some parameters must be included for the program to work properly and some might need to be specified if you need to customise or modify how the function works. Those parameters that must be included are known as mandatory parameters while those that might be included are known as optional parameters.

In this example we are "passing" two parameters to MsgBox() in the form of two text statements separated by a comma. The first parameter - "The User has clicked on Button 1" - tells MsgBox() what to say in the body of the pop-up message while the second parameter - "Pop-Up Message Box" - is the title to display on the title bar of the pop-up message.

Introducing Syntax

As already stated, HMG includes a range of standard pop-up messages and controls in addition to "message box". Before we look at these in further detail, it is a good time to explore syntax>, standard syntax and alternate syntax which you may have noticed in the HMG help (which you really should be exploring by now). Do not worry too much if the following sections don't make complete sense at first and if you don't fully understand every nuance of syntax. The more you use Harbour and HMG, the more intuitive and natural syntax becomes.

Syntax refers to "rules" that must be followed when you write code for it to work properly and to a set of "guidelines" used to make documenting and understanding functions, commands and other language capabilities easier to understand.

Syntax Rules

As you might expect, syntax rules are fairly rigid and, as such, must be followed for your code to work properly. These rules define the order in which you need to include parameters in functions, commands or other language capabilities, define if they are mandatory or optional, express the "form" in which the parameters must be constructed and, finally, define how that function or command might respond once it finishes running.

To explore these rules further, let's look at how the MsgInfo() standard message is documented in the HMG help;

The top section of the HMG help screen details the name of the function, command, or other language capability and gives a brief description of what its purpose is. The next section details the syntax rules and, finally, some examples of how to use the function, command, or other language capability are given. To understand this further, let's look at the first rule, the order in which parameters are included, and identify if the two in this example are mandatory or optional.

( <xData>, [<cTitle>] )

Firstly, the use of  < and > around the name of a parameter and the use of spaces before, in between and after each parameter are simply standard forms of documentation; in other words, their use is part of the guidelines most programmers follow in creating documentation. Neither of these two characters, <>, should actually be entered when you create a parameter and the use of spaces is not mandatory.

The first syntax rule in this example shows that a parameter, xData, must be passed to MsgInfo() to display in the body of the information box when you use it in your code. The 'x' and, for that matter, the  'c' in cTitle, which is separated from the first parameter by a comma which must be included if you use the second parameter, refer to the "form" of data which we explore shortly.

The second rule of syntax refers to mandatory and optional parameters. Notice that cTitle is enclosed in square brackets, []? These square brackets are only used to identify optional parameters, which don't need to be used, and neither [ or ] should actually be entered when you create your code. When no square brackets are used, this identifies a parameter that is mandatory and must be used when you create your code.

xData and cTitle

The next rule relates to the "form" in which a parameter should be constructed and this touches on some of the guidelines you need to understand when exploring functions, commands and other language capabilities.

I have previously suggested that it is good practice to try and name variables, labels and buttons in an obvious way and the same applies to parameters. In this example, the x at the start of xData is used to identify a parameter that can accept any valid data type such as characters, a date, a time or a number. The second parameter, cTitle starts with c which tells you that any title you want to display in the MsgBox() should be entered as characters only.

Data types, including arrays which are constructed using curly brackets – {} – which you can see in one of the MsgBox() examples, are covered in detail in chapter 9. For now, I recommend that you stick to using characters enclosed in inverted commas such as "This is a message".

--> Nil

The final syntax rule defines how the function, command or other capability might respond once it finishes running. This is documented, in this example, as −−> followed by the type of data the function will return; in this case Nil which is actually a valid data type (see chapter 9 for more details). Other functions and controls return different types of data that can then be used by the section of code where they are called from and we'll explore that capability in the next chapter.

More on Syntax Guidelines

As the word would suggest, the "guidelines" in syntax are more flexible and, in reality, are often less clear or change according to personal preferences. In fact, there is not, as far as I know, a fully defined and agreed set of syntax guidelines that are rigidly followed!

An example of guideline flexibility is in the names I use for buttons or labels. My personal preference is to use 'btn'  and 'lbl' respectively but other programmers have their own preferences and, sometimes, don't consistently stick to these, myself included!

The final point to make on the guidelines is with respect to the use or upper and lower case in naming or using functions, commands and other language capabilities. There is no rule around which type case to use and when. Often, this is a matter of personal taste and I have seen code that is only written in lower case, some that is all uppercase and, more often, code that uses both! The main thing to understand is that any of these are equally valid and my personal preference, as you will have seen, is to use a mix of both upper and lower case.

Standard and Alternate Syntax Explained

If you have been browsing through the HMG help, may have noticed that some of the functions, commands and other language capabilities can be used in two ways; with "standard syntax (xBase style)" or with an "alternate syntax". In a nutshell, both are equally effective styles of writing your code, you can even use both styles to define exactly the same types of function or capability in the same code files, and there is no hard and fast rule or guidance to use when deciding which of the two styles to should adopt.

The standard xBase syntax has its roots in the original xBase language and was widely used by the more advanced Clipper programming language. It is therefore more intuitive and natural for former xBase or Clipper programmers.

The alternate syntax is a newer style adopted by the developers of both the Harbour language and by the HMG developers (remember that Harbour is the "base" language and HMG is an addition to Harbour which principally focuses on providing graphical user interface (GUI) capabilities for windows type operating systems).

In writing the code used in the chapters of this guide, I have employed both styles and, personally speaking, I have no distinct preference for either. As the learning project, ePortfolio, progresses, I will focus on using the alternate style to be consistent in my approach.

The first of two things to be aware of is that some of the properties of some of the functions, commands and other language capabilities are implemented differently by the standard or alternate syntax methods. For example, when you define a label and wish to associate an action to execute if the user clicks on the label, under standard syntax you can define an ACTION, or an ONCLICK or an ON CLICK property. With alternate syntax you can only define an ONCLICK property.

The second thing to be aware of is that standard syntax expects the full definition to appear on a single line unless semi-colons are used to break that up over several lines. With alternate syntax, each property should be defined on separate lines which are not separated by semi-colons and each property needs a value. The following sample code demonstrates how to define a label using both the standard and the alternate syntax methods.

  #include "hmg.ch"

  FUNCTION SyntaxDemo()

  DEFINE WINDOW Test_Syntax ;
    AT 0,0 ;
    WIDTH 350 ;
    HEIGHT 150 ;
    TITLE "Two Different Syntax Styles" ;
    WINDOWTYPE MAIN

    // Standard syntax, lines separated with a semi-colon
    @ 32, 32 LABEL lblStdSyntax ;
      VALUE "Standard Syntax Label" ;
      ACTION MsgInfo("Clicked Label 1", "Test") ;
      AUTOSIZE ;     // No value needed
      FONT "Arial" SIZE 16 ;
      ITALIC       // No value needed

    // Alternate Syntax. Each property on a separate line
    DEFINE LABEL altStdSyntax
      ROW 64
      COL 32
      VALUE "Alternate Syntax Label"
      ONCLICK MsgInfo("Clicked Label 2", "Test")
      AUTOSIZE .T.     // A LOGICAL value IS needed
      FONTNAME "Arial"
      FONTSIZE 16
      FONTITALIC .T.     // A LOGICAL value IS needed
      END LABEL

  END WINDOW

  CENTER WINDOW Test_Syntax
  ACTIVATE WINDOW Test_Syntax

  RETURN Nil

You can download a copy of the source code file from here -  SyntaxDemo.prg

The bottom line is that both styles work as long as you structure the definition of the command, function or other language capability properly. Any preference for one syntax style over the other is simply a matter of personal choice.

Documentation 'Problems'

The HMG documentation is not infallible and should only be used as an aid to understanding parts of the language rather than being a strict expression of "the law". Two examples of this can be found with the help documentation for MsgInfo().

Firstly, xData is documented as being a mandatory parameter however it will still work even if no value is passed! This is because MsgInfo will interpret xData  as having a value of Nil if nothing is passed to it because Nil is actually a completely valid data type!

Secondly, the cTitle parameter suggests that a character value is required. However, MsgInfo will still work even if a different type of value such as a number is passed! This is because MsgInfo has been designed to handle all data types which is another example of "good design" in that the code has been developed to handle unexpected types of data.

This is "good design" is by no means guaranteed with all of the other HMG functions, commands and other language capabilities. The best advice I can offer is to try and follow the help guidelines as closely as possible by passing the expected type of value but also ensure you test your code as thoroughly and as often as possible.

Exploring Standard Pop-Op Messages and Controls

Enough theory! Let's get back to writing some actual code and explore some of the other standard messages and controls included in HMG.

As mentioned earlier, HMG contains a number of "pop-up" messages in addition to MsgBox() used earlier. These messages and controls display basic information to the user of the program and accept a user response which can be used to control how the program acts depending on the response. We will explore this type of control in more detail in the next chapter.

To explore each of these standard messages and controls, use your chosen editor, to enter the code below and save the file to the MySourceCode folder naming it StdControls.prg then compile the program using the "..\build StdControls" command. I have created this as a "self documenting" program file so, I hope, no further explanation should be needed!

  #include "hmg.ch"

  FUNCTION StdControls()

  DEFINE WINDOW Test_Controls ;
    AT 0,0 ;
    WIDTH 325 ;
    HEIGHT 280 ;
    TITLE "Demo - HMG Standard Messages and Controls" ;
    WINDOWTYPE MAIN

    // Alternate Syntax used. Note that text to display in each
    // controls is broken up over several lines using a semi-colon.
    // This is ONLY needed when you want to break the line up for
    // readability purposes.
    DEFINE BUTTON btnMsgInfo
      ROW 32
      COL 32
      CAPTION "MsgInfo"
      ONCLICK MsgInfo("This pop-up displays a message next to " + ;
           "a blue Windows Information Icon. The " + ;
           "user can only respond by clicking 'Ok'.", ;
           "Info Message Box")
    END BUTTON

    DEFINE BUTTON btnMsgBox
      ROW 32
      COL 160
      CAPTION "MsgBox"
      ONCLICK MsgBox("This pop-up displays a message without " + ;
           "any Windows Icon. The user can only " + ;
           "respond by clicking 'Ok'.", ;
           "Plain Message Box")
    END BUTTON

    DEFINE BUTTON btnMsgExclamation
      ROW 80
      COL 32
      CAPTION "MsgExclamation"
      ONCLICK MsgExclamation("This pop-up displays a message next " + ;
           "to a yellow Windows Exclamation Icon. The " + ;
           "user can only respond by clicking 'Ok'.", ;
           "Exclamation Box")
    END BUTTON

    DEFINE BUTTON btnMsgStop
      ROW 80
      COL 160
      CAPTION "MsgStop"
      ONCLICK MsgStop("This pop-up displays a warning message " + ;
           "next to a red Windows Stop Icon. The user " + ;
           "can only respond by clicking 'Ok'.", ;
           "Stop Box")
    END BUTTON

    DEFINE BUTTON btnMsgOkCancel
      ROW 128
      COL 32
      CAPTION "MsgOkCancel"
      ONCLICK MsgOkCancel("This pop-up displays a message next to " + ;
           "a blue Windows Question Icon. The user can" + ;
           " respond by choosing 'Ok' or 'Cancel.", ;
           "Ok or Cancel Box")
    END BUTTON

    DEFINE BUTTON btnMsgRetryCancel
      ROW 128
      COL 160
      CAPTION "MsgRetryCancel"
      ONCLICK MsgRetryCancel("This pop-up displays a message next " + ;
           "to a blue Windows Question Icon. The user " + ;
           "can respond by choosing 'Retry' or " + ;
           "'Cancel'.", "Retry or Cancel Box")
    END BUTTON

    DEFINE BUTTON btnMsgYesNo
      ROW 176
      COL 32
      CAPTION "MsgYesNo"
      ONCLICK MsgYesNo("This pop-up displays a question next to " + ;
           "a blue Windows Question Icon. The user can " + ;
           "respond by either choosing 'Yes' or 'No'.", ;
           "Yes or No Box")
    END BUTTON
    // The last three buttons with two responses are covered in chapter 6

  END WINDOW

  CENTER WINDOW Test_Controls
  ACTIVATE WINDOW Test_Controls

  RETURN Nil

You can download a copy of the source code file  from here - StdControls.prg

Chapter 4: Display a Button <<     >> Chapter 6: Acting on User Responses