An explanation about HMG …

An explanation about Harbour, HMG and HMG-IDE

By Sri  Rathinagiri » Mon Sep 08, 2014 12:44 pm

Clipper programmers sometimes find it difficult to accommodate with HMG. The reason is the difference between TUI (Text User Interface) and GUI. In GUI, the program control is in the hands of the user and it is event driven. User can click on anything (say minimize button, maximize button, even another program running behind or any controls). So, it is our duty to design the whole window and wait for user’s action and write procedures for each and every action of the user.

GUI offers many innovative controls like Grid, Combobox, Button, Spinner etc., as against only textbox in TUI. So, we have to eventually accommodate events for all these controls.

Now, coming to HMG as not only a GUI library but a bundle of all. Even though HMG is directly based on the latest Harbour versions, HMG comes as a bundle. You need not install any other software to build a windows application. Full stop. 🙂 It contains the GUI library, PRG compiler, C Compiler and all the supporting software products to successfully build an application.

People (at least me) sometimes misunderstand GUI and OOP as one and the same. GUI and OOP are different and independent to each other. GUI can be made to work with or without OOP and vice versa. HMG is based on Win32 API system. Win32 API system works on handles and hooks. Every window/control in HMG is provided with a handle (like the file handle in clipper) and events are hooked on that particular handle. Once any hooked event is fired by the user (say a click of a button) immediately Win32 API searches for a CallBack function which is provided by the developer via HMG. The beauty of HMG would be, the developer is made free from handling all these internal affairs, handles, hooks and callback procedures. Instead he can concentrate on what is to be done if the event is fired.

You will be astonished to see how a ‘define window’ statement in HMG invokes 100s of lines of Harbour and C code. Please see the source folder of HMG if you want to know in detail.

Again, the advantage of HMG is, you need not include any dlls with your executable code as it is based on Win32 API. The application would run in XP to Windows version 8 (even in Windows 97 some cases).

Now coming to your questions.

1) How to get a lot of of source codes containing of samples to handle screen-menus ; from basic up to complex/advanced screen-menus?

To answer this questions, pls help us by showing links which permit us to download. And by sharing your source-code available for public.

Screenshoot attached herein, is a sample screen handle we need to implement on our application, ASAP. Being programmers for long time, we need any advanced skill in order to satisfy our users/clients currently still using our DOS-apps-versions.

You can start with Your HMG Directory\SAMPLES\Basics\TUTORIAL folder. It contains various tutorials for basic programmers. Then you can see basic and controls sub-folders of samples. I don’t think that any advanced skill set is required to satisfy our existing DOS clients. Actually ther will be happy to update their programs to Windows version as it is user friendly and more flexible.

2) How to avoid one app/EXE is double-run by users in the same computer?

This problem never arise under DOS who own a single window. I noticed when exercising HMG-ID (executing IDE.EXE) to build project, the RUN (F5) function fails to detect the problem. that’s way HMG-IDE made run-time error as if the mistake came from source program.

Yes, it is a valid point. In HMG-IDE previous version there was an error marking ‘Is the program still running?’. I don’t know what happened to that in the recent versions. I will request Claudio to look into this. Thanks for reporting.

3) Why stable version release from official Harbour-Project differ from this forum?

The project says the latest stable version is 3.0.0. while this forum says HMG 3.3.1. Any clarification in this matter is urgently needed to avoid confusion.

Because they are entirely different projects. As I have discussed earlier, HMG is based on Harbour. But it is a bundle by itself. Some major implementations have been made after the versions HMG 3.0. Introducing Unicode in 3.1. Made it to a stable version in 3.2. And the latest and significant achievement is HMG in 64 Bits, which made it to 3.3 series.

HMG Extended is also developed and released parallelly and they have their own version numbering system.

IMHO, we can use the latest stable versions for the development.

4) Pls help us describe what the differences between this 3 services you’ve been provided: Harbour Compiler, Harbour Mini GIU, Harbour-IDE. We need to know exactly when and why use them?

Harbour compiler is the core. Habour MiniGUI is the Win32 wrapper library to access the GUI aspects of the programs. HMG IDE is a tool to develop and build our software in Harbour MiniGUI.

You can use simply Harbour if you need only console mode. If you want GUI support, you can use Harbour MiniGUI and its build.bat ( even without using HMG IDE at all).

If you need Forms Designer and an easy build system, you can use HMG IDE which can co-ordinate your forms, database, resources (icons, pictures etc) and linking other third party libraries.

Sri Rathinagiri
Sivakasi, India

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Courtesy of author, this article borrowed from here.

Un-Touchable Window

#include "hmg.ch"
PROCEDURE Main()
   nWindWidth := 500
   nWindHeight := 400
 
   nUnMWinCol := ( GetDesktopWidth() - nWindWidth ) / 2
   nUnMWinRow := ( GetDesktopHeight() - nWindHeight ) / 2
 
   DEFINE WINDOW frmUnTouchable ;
      AT 0,0 ;
      WIDTH nWindWidth ;
      HEIGHT nWindHeight ;
      TITle "UnTouchable Window" ;
      MAIN 
 
      ON KEY ESCAPE ACTION thisWindow.Release 
 
      DEFINE TIMER Timer_1 INTERVAL 1000 ACTION DontTouchMyWindow()
 
   END WINDOW
   frmUnTouchable.CENTER
   ACTIVATE WINDOW frmUnTouchable
RETURN // UTW.Main()
*.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
PROCEDURE DontTouchMyWindow()
   thisWindow.Row := nUnMWinRow 
   thisWindow.Col := nUnMWinCol 
   thisWindow.HEIGHT := nWindHeight
   thisWindow.WIDTH := nWindWidth
RETURN // DontTouchMyWindow()
*.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._

Basic Controls – 3

( Status Bar, Check Box )

We are continuing with Viva_HMG.hbp, Main.prg and Main.fmg.

While using a table and while navigating between its records, we need some extra info to show to user: Name of table, current record and record count in the table. So user always feels comfortable by knowing where is he / she; which table, which record?

The status bar control is convenient for this purpose and though this is a quite simple control, IDE has a builder for it: Status bar builder.

When you choose this builder ( after open the .fmg file by IDE of course ), a dialog box will open:

By using this dialog box we can define a status bar. We can prefer define status bar manually too:

    DEFINE STATUSBAR FONT "Tahoma" SIZE 9
        STATUSITEM "" WIDTH 300
        STATUSITEM "" WIDTH 40
        DATE         WIDTH 90
        CLOCK             WIDTH 90
    END STATUSBAR

After define status bar, we need assign values to its items. We don’t need assign values to DATE and CLOCK items, because these items will be updated by system (HMG) automatically.

First a little procedure :

PROCEDURE InitEdit()

EditReco.StatusBar.Item( 1 ) := cTableFNam

ReadData()

RETURN // InitEdit()

Change ON INIT event of  EditReco form from ReadData() to InitEdit(.

And add this line at end of ReadData() procedure.

 EditReco.StatusBar.Item( 2 ) := LTRIM( STR( RECN() ) ) + "\" + ;
                                 LTRIM( STR( LASTREC() ) )

Let’s look at the result :

Whenever active record change, Item( 2 ) of Status Bar will be updated ( 5/25 ) in above picture.

In this step, user must use “Save” button every time current record edited.  Whereas “Read” process is different; whenever current record changed, values of text boxes automatically updated. What about automatic save? May be, we can do this; but user may don’t want such automation. Asking a question like “Do you want save?” every change doesn’t a good way.

The better way may be: put a control to form such “Auto save” with On / Off option.

Yes, fortunately we have such control: Check Box.

We can replace a Check Box control to EditReco form with chbAutoSave name and Auto Save caption:

Now, how we will implement Auto Save process?.

By adding a little IF clause to ACTION events of navigation buttons:

Top : (IF(EditReco. chbAutoSave.Value , SaveData(), ), DBGOTOP(), ReadData() )

Next : (IF(EditReco. chbAutoSave.Value , SaveData(), ), DBSKIP(), ReadData() )

Previous : ( IF(EditReco. chbAutoSave.Value , SaveData(), ), DBSKIP( -1 ), ReadData() )

Last : (IF(EditReco. chbAutoSave.Value , SaveData(), ), DBGOBOTTOM(), ReadData() )

To be continued …

Download source files

Basic Controls – 2


( Text Box  )

We are continuing with Viva_HMG.hbp, Main.prg and Main.fmg. We have assign real actions other than MsgBox() to our two buttons now : Open File and Edit Record. Open File not required GUI controls ( at least for now ), so we can begin with it: For Open File we need a file ( a table ) first: it’s here; a table with four field: Clients.dbf :

No:  Field Name Type Width Dec
---  ---------  ---- ----- ---
  1  CLI_ID       N      5   0
  2  CLI_SNAM     C     12   0
  3  CLI_NAME     C     12   0
  4  CLI_TLF      C     11   0

And then add a little routine to Main.prg for open (USE) it:

PROCEDURE OpenTable()
   IF FILE( "CLIENTS.DBF" )
      USE CLIENTS
   ELSE
      MsgStop( "Clients.dbf file not found !")
   ENDIF
RETURN // OpenTable()

And assign this procedure to ACTION of  Open File  button.

Now, we can begin Edit Record task. For this task we need a separate form, a sub form.  Then let’s begin. “New form” from tool-bar and assign a name : EditReco. Assign a title : “Edit Record”, a type : MODAL. Our table has four fields, so we need four LABEL first:

Names :  lblCLI_ID,  lblCLI_SNAM,  lblCLI_NAME, lblCLI_TLF;

Values ( Captions ) : ID,  Surname, Name, Tlf

Rows : 60, 100, 140, 180 Col : 60

Cols :  60, 60, 60, 60

Widths : 70, 70,  70, 70

Alignement : RIGHT, RIGHT, RIGHT, RIGHT

We can see our job at work:

Now we need a place  for display the current data and accept user input. The control for this purpose is text box. So we need to define four text boxes for each field in the table.

The button of text box in the IDE tool bar is :

Names :  txbCLI_ID,  txbCLI_SNAM,  txbCLI_NAME, txbCLI_TLF;

Rows : 55, 95, 135, 175

Col : 140

DataTypes : First : NUMERIC, others : CHARACTER

We can see our job at work:

Well …

But where are table data ?

To see table data we need assign field values to text boxes as values.

Again, a little procedure:

PROCEDURE ReadData()
   EditReco.txbCLI_ID.Value   := CLIENTS->CLI_ID
   EditReco.txbCLI_SNAM.Value := CLIENTS->CLI_SNAM
   EditReco.txbCLI_NAME.Value := CLIENTS->CLI_NAME
   EditReco.txbCLI_TLF.Value  := CLIENTS->CLI_TLF
RETURN // ReadData()

and a call command for this procedure to ON INIT event of  EditReco form.

The result :

Everything is OK ?

No !

This is only first record of table; how we will see others ?

Yes, we need now yet another feature: navigation; that is travelling between records of table.

But before navigation, we have a problem: Open Table must be processed before Edit Record.

Otherwise a run time error will occurs: Alias does not exist. 

What we can do?

–       Discard Open Table button, open the table automatically; at beginning of program or at beginning of editing.

–       Before editing, check the table, if doesn’t open,

–          a)  open automatically or

–          b)  warn user and don’t load Edit Table form.

Probably most convenient is : disable Edit Record button until table is open.

First a mini procedure :

PROCEDURE Initialize()
   Main.btnEditRec.Enabled := .F.
RETURN // Initialize()

And then add this procedure ON INIT event of form main:

Last point: enable it after USE table:

PROCEDURE OpenTable()
   IF FILE( "CLIENTS.DBF" )
      USE CLIENTS
      Main.btnEditRec.Enabled := .T.
   ELSE
      MsgStop( "Clients.dbf file not found !")
   ENDIF
RETURN // OpenTable()

Run and see:

Before Open File :

After Open File:

Now we can pass to navigation:

We need seven buttons: Go Top, Go Next, Go Previous, Go Last, Save, Discard, Exit.

Name: btnGoTop, Caption : Top,  Col : 50, Row: 220, Height: 28, Width: 60

Name: btnGoNext, Caption : Next,  Col : 130, Row: 220, Height: 28, Width: 60

Name: btnPrevious, Caption : Previous,  Col : 200, Row: 220, Height: 28, Width: 60

Name: btnGoLast, Caption : Last,  Col : 270, Row: 220, Height: 28, Width: 60

Name: btnSave Caption : Save,  Col : 380, Row: 60, Height: 28, Width: 100

Name: btnDiscard, Caption : Discard,  Col : 380, Row: 140, Height: 28, Width: 100

Name: btnExit, Caption : Exit,  Col : 380, Row: 220, Height: 28, Width: 100

Common: Font Name: Tahoma, Font Size: 9

Actions :

btnGoTop: ( DBGOTOP(), ReadData() )
btnGoNext: ( DBSKIP(), ReadData() )
btnPrevious: ( DBSKIP( -1 ), ReadData() )
btnGoLast: ( DBGOBOTTOM(), ReadData() )
btnSave: SaveData()
btnDiscard: ReadData()

btnExit: ThisWindow.Release

Note that actions of four first buttons include two actions, separated by comma and enclosed by parenthesis.  With this notation we can define more than one action together.

SaveData() is the inverse of  ReadData(): copy values of text boxes to table fields.

PROCEDURE SaveData()         // Save data from text boxes to table
   CLIENTS->CLI_ID   := EditReco.txbCLI_ID.Value
   CLIENTS->CLI_SNAM := EditReco.txbCLI_SNAM.Value
   CLIENTS->CLI_NAME := EditReco.txbCLI_NAME.Value
   CLIENTS->CLI_TLF  := EditReco.txbCLI_TLF.Value
RETURN // SaveData()

Discard is simply re-reading data from table.

The result:

To be continued …

Download source files

Basic Controls – 1

( Image, Label and Button )

We are continuing with Viva_HMG.hbp, Main.prg and Main.fmg. First, let’s enlarge our form: width: 650, height: 550; and then place an image: First click “image” button the toolbar of HMG-IDE, and then click anywhere in the form. This clicked point in the form, will be left upper corner of control; in this case : image. IDE always first places controls with its default values. Our image is 405 x 340 pixel size:

We need assign a size to image control so it can hold properly our image. We can manually set these values and assign name of image file:

Background color of our form didn’t well-matched with this image. Let’s change it to white:

In this step, if we run the program we will see like this :

The STRETCH option of IMAGE control allows assigning size values to the control other than original image sizes. In this case quality of image may decrease. We need also avoiding distortion too; that is keeping fixed aspect ratio of image.

By assigning same width / height values of form and image; we can use an image as back-ground image of form. But in this case we can’t place other control onto image: because controls must not be overlap to each other. Under certain circumstances system not obstructs this. But the beneath control can’t seen.

The LABEL control is an exception of this rule by TRANSPARENT option. If a label is transparent, the beneath control may be seen partially.

Let’s add a label to our form:

The big “A” symbol in the toolbar of IDE represent LABEL. First click this button and then top of our form:

The placeholder of LABEL is primitive situation for now. We have added a new and adjusted  both to our needs:


If we built and run our project after set these values, appearance will be like this:

Since two controls (labels) have been overlapped, constructing this “shadow” effect will be a few painful. You can edit .fmg file out of HMG, via any text editor when necessary.

Labels probably are most used controls in GUI programming. This control simply displays any text onto form. For xBase programmers we can say this is GUI counterpart of @ …,… SAY command. As all other GUI controls, we use coordinate system to indicate placement of control. In addition we can set size ( width, height ), back and fore color values, font properties and others as well as we need.

Labels also have ALIGNEMENT property with LEFT, RIGHT and CENTER option. In this sample used LEFT.

In addition, LABEL control supports ACTION event too. This means you can instruct a LABEL control to do an action when user clicked it; same as BUTTON.

Last control to use in this sample is button.

Beside menus, buttons are handy controls for doing an action when user clicked. Let’s see how :

The button for BUTTON in the IDE Tool Bar is this:

As precedents, one click to this button and another one to form, under image:

And two more :

Now we can tailor these buttons to our needs:

First let’s change names and captions given by IDE:

btnOpenFile, btnEditRec and btnExit to names and Open File, Edit Record and Exit to captions, consecutively:

It’s time to assign ACTIONs to this buttons.

MsgInfo( “Open File”) to ACTION of btnOpenFile

MsgInfo( “Edit Record”) to ACTION of , btnEditRec,

ThisWindow.Release to ACTION of btnExit.

And, RUN of course …

Test ACTIONs of buttons by clicking: first two will repeat the sentences in their captions via MsgInfo() function  and the last will terminate program. Yes, we are using RELEASE method to the main window for terminate running program, instead of QUIT or CANCEL commands.

That’s all for now !

Downloads source files

Directory List

Reinvention of wheel ?

Not quite …

Main difference is allowing file(s) and folder(s) selection together.

Another difference is implementing of <lNoChangeDir> parameter. Unlike GetFile(), GetDIRList() uses this value  for allowing change directory ability to user.

Furthermore sorting grid columns by three (not two) ways, GetVolumLabel(), List2Arry() and Arry2List()  functions may be useful.

Also, test program ( TestGDL.prg ) may be a sample for .fmg based application.

Download here ( source only ).

Hex View

Hexadecimal file viewer.

This is a experimental project with first intend of point out the power of Harbour and HMG. So, HexView is considerably slow on large files, please be patient.

Download here ( source only ).

Message multiple values

MsgMulti ( aka MsM) is a message function accept multiple and any type of data.

Download here ( source only ).

Data entry boxes

HMG Tutor 21 — Data-Controls II:

TEXTBOX, DATEPICKER, CHECKBOX, EDITBOX

The ‘data-version’ of these controls required the use of the following properties / methods to bound them to a database field:

Field Property: Stablishes the field that control is bounded to.
Refresh Method: Updates control content based on current field content.
Save method: Updates database file according control content.

#include "hmg.ch"

Function Main
DEFINE WINDOW Win_1 ;
   AT 0,0 ;
   WIDTH 640 ;
   HEIGHT 480 ;
   TITLE 'Tutor 21: Data-Bound Controls Test' ;
   MAIN ;
   ON INIT OpenTables() ;
   ON RELEASE CloseTables()

   DEFINE TOOLBAR ToolBar_1 BUTTONSIZE 100,30 FLAT RIGHTTEXT BORDER

      BUTTON TOP ;
         CAPTION '&Top' ;
         PICTURE 'primero.bmp' ;
         ACTION ( DbGoTop() , Refresh() )

      BUTTON PREVIOUS ;
         CAPTION '&Previous';
         PICTURE 'anterior.bmp' ;
         ACTION ( DbSkip(-1) , Refresh() )

      BUTTON NEXT ;
         CAPTION '&Next';
         PICTURE 'siguiente.bmp' ;
         ACTION ( DbSkip(1) , if ( eof() , DbGoBottom() , Nil ) , Refresh() )

      BUTTON BOTTOM ;
         CAPTION '&Bottom' ;
         PICTURE 'ultimo.bmp' ;
         ACTION ( DbGoBottom() , Refresh() )

      BUTTON SAVE ;
         CAPTION '&Save' ;
         PICTURE 'guardar.bmp' ;
         ACTION ( Save() , Refresh() )

      BUTTON UNDO ;
         CAPTION '&Undo' ;
         PICTURE 'deshacer.bmp' ;
         ACTION ( Refresh() )

   END TOOLBAR

   @  50,10 LABEL LABEL_1 VALUE 'Code:'
   @  80,10 LABEL LABEL_2 VALUE 'First Name'
   @ 110,10 LABEL LABEL_3 VALUE 'Last Name'
   @ 140,10 LABEL LABEL_4 VALUE 'Birth Date:'
   @ 170,10 LABEL LABEL_5 VALUE 'Married:'
   @ 200,10 LABEL LABEL_6 VALUE 'Bio:'

   @ 50,200 TEXTBOX TEXT_1;
            FIELD TEST->CODE ;
            NUMERIC ;
            MAXLENGTH 10

   @ 80,200 TEXTBOX TEXT_2;
            FIELD TEST->FIRST ;
            MAXLENGTH 30

   @ 110,200 TEXTBOX TEXT_3;
             FIELD TEST->LAST ;
             MAXLENGTH 30

   @ 140,200 DATEPICKER DATE_4 ;
             FIELD Test->Birth

   @ 170,200 CHECKBOX CHECK_5 ;
             CAPTION '' ;
             FIELD Test->Married

   @ 200,200 EDITBOX EDIT_6 ;
             FIELD Test->Bio ;
             HEIGHT 100

END WINDOW

Win_1.Text_1.SetFocus

ACTIVATE WINDOW Win_1

Return Nil

Procedure Refresh
   Win_1.Text_1.Refresh
   Win_1.Text_2.Refresh
   Win_1.Text_3.Refresh
   Win_1.Date_4.Refresh
   Win_1.Check_5.Refresh
   Win_1.Edit_6.Refresh
   Win_1.Text_1.SetFocus
Return

Procedure Save
   Win_1.Text_1.Save
   Win_1.Text_2.Save
   Win_1.Text_3.Save
   Win_1.Date_4.Save
   Win_1.Check_5.Save
   Win_1.Edit_6.Save
Return

Procedure OpenTables
   USE TEST
Return
Procedure CloseTables
   USE
Return

StatusBar Control

HMG Tutor 19

Showing Status (Statusbar Control)

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

#include "hmg.ch"
Function Main
DEFINE WINDOW Win_1 ;
   AT 0,0 ;
   WIDTH 400 ;
   HEIGHT 200 ;
   TITLE 'Tutor 19 StatusBar 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

ACTIVATE WINDOW Win_1

Return