Tutorial

A little practice on HMG

 


 

This page is based upon HMG Offical Tutorial

 

Hello World - 2

In the our first example in Quick Start page, we wrote the "Hello World" clause on the title bar. Now,  let's put it on the form.

Build a new project with "HelloWorld2" name, copy HelloWord.prg to HelloWorld2.prg and change it as below:

#include <minigui.ch>

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Hello World-2' ;
        MAIN
       
        DEFINE LABEL lblHello
           ROW 75
           COL 125
           VALUE "Hello World !"
           FONTNAME "Lucida"
           FONTSIZE 16
        END LABEL
       
    END WINDOW

    ACTIVATE WINDOW Win_1

Return

Build and run project :

                                 

DEFINE LABEL and END LABEL statements are for "Label" definiton structure for the a window ( in this example Windows named as "Win_1" ). Label itself must have a name ("lblHello" in this example), and this name must be unique, such as a variable name. Beginning these names with a descriptive prefix ( "lbl" in the example) is a good programming practice.

Between DEFINE - END statements there are main properties of this label.  Row, col numbers ( in pixels of course), value (for labels, value is a string constant to write in the your form/window) and font properties (NAME and SIZE)

Almost every GUI control definitions HMG have two syntax : With DEFINE and END structure and with @ command. Thus in the above example instead of DEFINE LABEL and END LABEL structure, you can use alternate  @ syntax :

        @ 75, 125 LABEL lblHello ;
                  VALUE "Hello World !" ;
                  FONT "Lucida" ; 
                  SIZE 16

Don't worry, change anywhere in the example; without mistakes learning is impossible ! 

A last note for this example : place

    CENTER WINDOW Win_1

statement blove END WINDOW stament and notice that how much HMG is powerful.

Hello Word -  3

Don't worry ! This is the last; and important.

Extract DEFINE LABEL - END LABEL structure or @ ...,... LABEL command ( which one is currently exist) and then instead of them place this line :

    MsgBox( "Hello World !" )

There are a lot of message functions, with name prefixed by "Msg":

    MsgExclamation()

    MsgInfo()

    MsgStop()

    MsgOkCancel()

    MsgRetryCancel()

    MsgYesNo()

Like MsgBox(), all message functions accept first parameter as a string constant representing the message itself. All message functions also have a second parameter, again a string constant representing the title of message box.

The first three message funcitons returns NIL, and the last three returns a logical value.

Try and observe results.

After building and running, try a more important feature: reduce your program to these minimum size:

   #include <minigui.ch>

   Function Main
      MsgBox( "Hello World !" )
   Return

In fact, as a rule, every HMG project must have one and only one "Main" window. This message functions are exception of this rule . If you have only message function(s) you can build a program without main window.

 

Adding The Main Menu

We add a main menu to the program now:

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Main Menu' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change Window Title' ACTION  Win_1.Title := 'New Title'
             ITEM 'Retrieve Window Title' ACTION  MsgInfo ( Win_1.Title )
           END POPUP
        END MENU

    END WINDOW

    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

As you can see it is pretty easy and intuitive.

All the main menu stuff will be between DEFINE MAIN MENU / END MENU statements.
Each individual menu popup will be between POPUP / END POPUP statements.
Each individual menu item will be coded via the ITEM statement.

You can use as popups as you need and you can nest it without any limit.

 

Getting data from the user (The TextBox Control)

The TextBox control is the main way to obtain data from the user.

    @ 40 , 120 TEXTBOX Text_1

If you want to get numeric data, just add NUMERIC clause:

    @ 80 , 120 TEXTBOX Text_2 NUMERIC

If you want to indicate an editing mask, you can use the INPUTMASK clause.

    @ 120 , 120 TEXTBOX Text_2 NUMERIC INPUTMASK '9999.99'

#include "minigui.ch"

Function Main

  DEFINE WINDOW Win_1 ;
    AT 0,0 ;
    WIDTH 400 ;
    HEIGHT 300 ;
    TITLE 'TextBox' ;
    MAIN

    DEFINE MAIN MENU
      POPUP "First Popup"
        ITEM 'Change TextBox Content' ACTION  Win_1.Text_1.Value := ;

             'New TextBox Value'
        ITEM 'Retrieve TextBox Content' ACTION  MsgInfo ( Win_1.Text_1.Value)
        SEPARATOR
        ITEM 'Change Numeric TextBox Content' ACTION  Win_1.Text_2.Value := 100
        ITEM 'Retrieve Numeric TextBox Content' ACTION  ;

              MsgInfo( Str(Win_1.Text_2.Value))
        SEPARATOR
        ITEM 'Change Numeric (InputMask) TextBox Content' ACTION  ;

              Win_1.Text_3.Value := 1234.12
        ITEM 'Retrieve Numeric (InputMask) TextBox Content' ACTION  ;

              MsgInfo ( Str(Win_1.Text_3.Value))


      END POPUP
    END MENU

    @  40 , 120 TEXTBOX Text_1
    @  80 , 120 TEXTBOX Text_2 NUMERIC
    @ 120 , 120 TEXTBOX Text_3 NUMERIC INPUTMASK '9999.99'

  END WINDOW

  CENTER   WINDOW Win_1
  ACTIVATE WINDOW Win_1

Return


Getting Logical

Sometimes, you need to get logical data from the user. The easiest way to do that, is using a checkbox control.

@ 180, 120 CHECKBOX Check_1

We add it to the program, along with new menu options to set or retrieve its value

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 300 ;
        TITLE 'CheckBox Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change CheckBox Value'   ACTION  ;
                  Win_1.Check_1.Value := .T.
             ITEM 'Retrieve CheckBox Value' ACTION  ;
                  MsgInfo ( if(Win_1.Check_1.Value,'.T.','.F.'))
           END POPUP
        END MENU

        @ 100, 120 CHECKBOX Check_1 CAPTION 'Check Me!'

    END WINDOW

    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

Making a Choice

Sometimes, you need to get a choice from users, between a small group of options that are known at design time.

The best way to go is such cases is the RadioGroup control.

@ 80, 120 RADIOGROUP Radio_1 OPTIONS {'Option 1','Option 2','Option 3'}

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 300 ;
        TITLE 'RadioGroup Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change RadioGroup Value' ACTION  ;
                   Win_1.Radio_1.Value := 2
             ITEM 'Retrieve RadioGroup Value' ACTION  ;
                   MsgInfo ( Str(Win_1.Radio_1.Value))

           END POPUP
        END MENU

        @ 80, 120 RADIOGROUP Radio_1 OPTIONS {'Option 1','Option 2','Option 3'}

    END WINDOW

    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

 

 

More Choices

There is various alternatives to get an user's choice besides RadioGroup.

One of them is the ListBox Control

@ 10, 10 LISTBOX List_1 ITEMS {'Option 1','Option 2','Option 3'}

Using a Listbox, you can add, change or remove items at runtime.

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'ListBox Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change ListBox Value'   ACTION  ;
                  Win_1.List_1.Value := 2
             ITEM 'Retrieve ListBox Value' ACTION  ;
                  MsgInfo ( Str(Win_1.List_1.Value))
 
            SEPARATOR
             ITEM 'Add List Item'       ACTION ;
                  Win_1.List_1.AddItem ('New List Item')
             ITEM 'Remove List Item'    ACTION ;
                  Win_1.List_1.DeleteItem (2)
             ITEM 'Change List Item'    ACTION ;
                  Win_1.List_1.Item (1) := 'New Item Text'
             ITEM 'Get List Item Count' ACTION ;
                  MsgInfo (Str(Win_1.List_1.ItemCount))
           END POPUP
        END MENU

        @ 10, 175 LISTBOX List_1 ITEMS {'Option 1','Option 2','Option 3'}

    END WINDOW

    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

 

More Choices II

Another alternative to get an user's choice is the COMBOBOX.

@ 10, 10 COMBOBOX Combo_1 ITEMS {'Option 1','Option 2','Option 3'}

Using a Combobox, is similar to ListBox.

#include <minigui.ch>

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'ComboBox Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change ComboBox Value'   ACTION  ;
                  Win_1.Combo_1.Value := 2
             ITEM 'Retrieve ComboBox Value' ACTION  ;
                  MsgInfo ( Str(Win_1.Combo_1.Value))
             SEPARATOR
             ITEM 'Add Combo Item'       ACTION ;
                  Win_1.Combo_1.AddItem ('New List Item')
             ITEM 'Remove Combo Item'    ACTION ;
                  Win_1.Combo_1.DeleteItem (2)
             ITEM 'Change Combo Item'    ACTION ;
                  Win_1.Combo_1.Item (1) := 'New Item Text'
             ITEM 'Get Combo Item Count' ACTION ;
                  MsgInfo (Str(Win_1.Combo_1.ItemCount))
           END POPUP
        END MENU

        @ 10, 10 COMBOBOX Combo_1 ITEMS {'Option 1','Option 2','Option 3'}

    END WINDOW

    CENTER   WINDOW Win_1   
    ACTIVATE WINDOW Win_1

Return

 

 

 

Pushing Actions (Standard Buttons)

Another way for let the users to take an action (besides menus) are buttons.

@ 10,10 BUTTON Button_1 CAPTION 'Click Here!' ACTION MsgInfo('Button Clicked!')

#include <minigui.ch>

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Button Test' ;
        MAIN

        @ 10,10 BUTTON Button_1 ;
            CAPTION 'Click Here!' ;
                    ACTION MsgInfo('Button Clicked!')

    END WINDOW
   
    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

Being More Graphical (Picture Buttons)

Instead a text caption you can use a picture.

@ 10,10 BUTTON PictureButton_1 ;
    PICTURE 'button.bmp' ;
    ACTION MsgInfo('Picture Button Clicked!!') ;
    WIDTH 27 ;
    HEIGHT 27 ;
    TOOLTIP 'Picture Button Tooltip'

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Picture Button Test' ;
        MAIN

            @ 10,10 BUTTON PictureButton_1 ;
                PICTURE 'button.bmp' ;
                ACTION MsgInfo('Picture Button Clicked!!') ;
                WIDTH 27 ;
                HEIGHT 27 ;
                TOOLTIP 'Picture Button Tooltip'

    END WINDOW

    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

The optional tooltip clause, causes that a small window with an explanatory text be displayed when the mouse pointer stays over the control for a few seconds. You can use this clause with most MiniGUI controls.

 

CheckButton = Button + CheckBox

The CheckButton control, acts like a checkbox, but looks like a button. Like buttons, It comes in two flavors: Text and Graphical.

    @ 10,10 CHECKBUTTON CheckButton_1 ;
        CAPTION 'CheckButton' ;
        VALUE .F.

    @ 50,10 CHECKBUTTON CheckButton_2 ;
        PICTURE 'Open.Bmp' ;
        WIDTH 27 ;
        HEIGHT 27 ;
        VALUE .F. ;
        TOOLTIP 'Graphical CheckButton'

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'CheckButton Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change Text CheckButton Value'      ACTION  ;
                  Win_1.CheckButton_1.Value := .T.
             ITEM 'Retrieve Text CheckButton Value'    ACTION  ;
                  MsgInfo ( if(Win_1.CheckButton_1.Value,'.T.','.F.'))
             SEPARATOR
             ITEM 'Change Picture CheckButton Value'   ACTION  ;
                  Win_1.CheckButton_2.Value := .T.
             ITEM 'Retrieve Picture CheckButton Value' ACTION  ;
                  MsgInfo ( if(Win_1.CheckButton_2.Value,'.T.','.F.'))
           END POPUP
        END MENU

            @ 10,10 CHECKBUTTON CheckButton_1 ;
                CAPTION 'CheckButton' ;
                VALUE .F.

            @ 50,10 CHECKBUTTON CheckButton_2 ;
                PICTURE 'Open.Bmp' ;
                WIDTH 27 ;
                HEIGHT 27 ;
                VALUE .F. ;
                TOOLTIP 'Graphical CheckButton'

    END WINDOW
   
    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

 

 

Getting Dates (The DatePicker Control)


The easiest way to get dates from user is the datepicker control.

    @ 10,10 DATEPICKER Date_1


#include <minigui.ch>

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'DatePicker Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change DatePicker Value'   ACTION ;
                  Win_1.date_1.Value := Date()
             ITEM 'Retrieve DatePicker Value' ACTION ;
                  MsgInfo ( dtoc(Win_1.Date_1.Value))
           END POPUP
        END MENU

        @ 10,10 DATEPICKER Date_1

    END WINDOW

    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

DatePicker is very handy, clever and useful control. For it's details look by buildig and running C:\hmg\SAMPLES\DATEPICKER\Demo.prg.

 

 

Getting Large Text (The EditBox Control)


The EditBox control allows to handle large (multiline) text data.

        @ 10,10 EDITBOX Edit_1 ;
            WIDTH 300 ;
            HEIGHT 150


#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 300 ;
        TITLE 'EditBox Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change EditBox Content'   ACTION  ;
                Win_1.Edit_1.Value := 'New EditBox Value'
             ITEM 'Retrieve EditBox Content' ACTION  ;
                MsgInfo ( Win_1.Edit_1.Value)
           END POPUP
        END MENU

        @ 10,10 EDITBOX Edit_1 ;
            WIDTH 300 ;
            HEIGHT 150

    END WINDOW

    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

Displaying Images (The Image Control)


The image control allows to show image files in your program.

    @ 10,10 IMAGE Image_1 ;
        PICTURE 'Demo.Bmp' ;
        WIDTH 90 ;
        HEIGHT 90

 

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Image Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change Image Content'   ACTION ;
                  Win_1.Image_1.Picture := 'Open.Bmp'
             ITEM 'Retrieve Image Content' ACTION ;
                  MsgInfo ( Win_1.Image_1.Picture)
           END POPUP
        END MENU

        @ 10,10 IMAGE Image_1 ;
            PICTURE 'Demo.Bmp' ;
            WIDTH 90 ;
            HEIGHT 90

    END WINDOW

    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

 

Showing Progress


The progressbar control allows to show the completion status of an operation.

    @ 10,10 PROGRESSBAR Progress_1 ;
        RANGE 0 , 65535


#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Progressbar Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'ProgressBar Test' ACTION  DoTest()
           END POPUP
        END MENU

        @ 10,10 PROGRESSBAR Progress_1 ;
            RANGE 0 , 65535

    END WINDOW
   
    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

Procedure DoTest()
Local i

    For i = 0 To 65535 Step 25
        Win_1.Progress_1.Value := i
    Next i

Return

 

Spinning Around


An alternate way to get numeric data is the spinner control. It consist of a textbox with two arrows that allows to change control's value using the mouse.

    @ 10,10 SPINNER Spinner_1 ;
        RANGE 0,10 ;
        VALUE 5 ;
        WIDTH 100

 

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Spinner Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change Spinner Value'   ACTION ;
                   Win_1.Spinner_1.Value := 8
             ITEM 'Retrieve Spinner Value' ACTION ;
                    MsgInfo ( Str(Win_1.Spinner_1.Value))
           END POPUP
        END MENU

        @ 10,10 SPINNER Spinner_1 ;
                RANGE 0,10 ;
                VALUE 5 ;
                WIDTH 100

    END WINDOW
   
    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

Getting Organized (TAB Control)


A TAB control lets organize controls and save form space, grouping the controls in folders.

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 250 ;
        TITLE 'Tab Test' ;
        MAIN

        DEFINE MAIN MENU
           POPUP "First Popup"
             ITEM 'Change Tab Value'   ACTION ;
                  Win_1.Tab_1.Value := 2
             ITEM 'Retrieve Tab Value' ACTION ;
                  MsgInfo ( Str(Win_1.Tab_1.Value))
           END POPUP
        END MENU

        DEFINE TAB Tab_1 ;
            AT 10,10 ;
            WIDTH 350 ;
            HEIGHT 150

            PAGE 'Page 1'
                @ 50,50 LABEL Label_1 VALUE 'This Is The Page 1'
            END PAGE

            PAGE 'Page 2'
                @ 50,50 LABEL Label_2 VALUE 'This Is The Page 2'
            END PAGE

        END TAB

    END WINDOW
   
    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return

 

More Organization (TOOLBAR Control)


Toolbars are used to group command buttons in a bar located (usually) at window top (under main menu bar).

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 640 HEIGHT 480 ;
        TITLE 'ToolBar Test' ;
        MAIN

        DEFINE MAIN MENU
            POPUP '&File'
                ITEM '&Disable ToolBar Button' ACTION ;
                      Win_1.Button_1.Enabled := .F.
                ITEM '&Enable ToolBar Button'  ACTION ;
                      Win_1.Button_1.Enabled := .T.
                ITEM '&Exit' ACTION Win_1.Release
            END POPUP
        END MENU

        DEFINE TOOLBAR ToolBar_1 BUTTONSIZE 40,40 FLAT BORDER

            BUTTON Button_1 ;
                CAPTION '&New' ;
                PICTURE 'edit_new.bmp' ;
                ACTION MsgInfo('Click! New')

            BUTTON Button_2 ;
                CAPTION '&Edit' ;
                PICTURE 'edit_edit.bmp' ;
                ACTION MsgInfo('Click! Edit')

            BUTTON Button_3 ;
                CAPTION '&Find' ;
                PICTURE 'edit_find.bmp' ;
                ACTION MsgInfo('Click! Find') ;
                SEPARATOR

        END TOOLBAR

    END WINDOW

    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return Nil

 

Showing Status (Statusbar Control)


This control creates a bar at window's bottom, used to show information (usually status information)

#include "minigui.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Status Bar Test' ;
        MAIN

        DEFINE MAIN MENU
            POPUP '&StatusBar Test'
                ITEM 'Set Status Item 1' ACTION ;
                     Win_1.StatusBar.Item(1) := "New value 1"
                ITEM 'Set Status Item 2' ACTION ;
                     Win_1.StatusBar.Item(2) := "New value 2"
            END POPUP
        END MENU

        DEFINE STATUSBAR
            STATUSITEM "Item 1" ACTION MsgInfo('Click! 1')
            STATUSITEM "Item 2" WIDTH 100 ACTION MsgInfo('Click! 2')
            CLOCK
            DATE
            STATUSITEM "Item 5" WIDTH 100
        END STATUSBAR

    END WINDOW
   
    CENTER   WINDOW Win_1
    ACTIVATE WINDOW Win_1

Return