Fundamentos

Fundamentos de Harbour MiniGUI

Nota Importante: Estos fundamentos, fueron creados al principio del desarrollo de HMG, con código puro y duro y sin gran cantidad de funciones que hoy existen en las últimas versiones. Además hoy en día con el IDE que trae integrado el mismo genera la mayoría de código para los programas. Pero sirva el primer original para comprender el motor principal de esta gran librería para generar programas para Windows tanto en 32 como 64 bits. con código xBase y recordando el gran Clipper, hoy en día sustituido por Harbour. 


Harbour MiniGUI implementa un modelo semi-oop.

En mi humilde opinión, este modelo se ajusta perfectamente a xBase ya que la meta de los creadores del dBase original fue la de obtener el máximo poder con el mínimo de esfuerzo. Esta fue la clave de su enorme éxito.

En la mayoría de los casos, los productos xBase para Windows consisten en un compilador xBase "atado" a un motor GUI OOP estándar, resultando en lenguajes "esquizoides", extremadamente fácil de usar en todos los aspectos, excepto la interfase de usuario.

He tratado de crear un sistema GUI consistente con la filosofía xBase, sin apegarme a estrictamente a ningún paradigma estándar.

Algunas ideas del modelo semi-oop usado en Harbour MiniGUI, fueron inspiradas por el compilador RAPID-Q creado por William Yu, cuyas brillantes ideas me inspiraron.

El Primer Programa

No sere muy original, este programa desplegará el mensaje 'Hola Mundo' :)

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 01 - Hola Mundo!' ;
        MAIN

    END WINDOW

    ACTIVATE WINDOW Win_1

Return

El comando DEFINE WINDOW: Creará la ventana principal para el programa

Win_1: Es el nombre de la ventana

At 0,0: Indica la posición de la ventana (row=0,col=0)

WIDTH 400: Significa que la ventana tendrá 400 pixels de ancho.

HEIGHT 200:Significa que la ventana tendrá 200 pixels de alto.

TITLE 'Hola el Mundo! ': Indica el texto en la barra de título de la ventana.

MAIN: Indica que estamos definiendo la ventana principal de la aplicación (una ventana principal se requiere para todas las aplicaciones HMG)

ACTIVATE WINDOW Form_1: Muestrará la ventana e iniciará el ciclo de eventos.


La Forma Tradicional


El comportamiento o apariencia de una ventana o control, podría cambiarse con un comando al estilo xBase (MODIFY)

En el siguiente ejemplo, si quiere cambiarse el título de la ventana, podría usarse el siguiente comando:

MODIFY WINDOW Win_1 TITLE 'New Title'

Para obtener el título de la ventana:

FETCH WINDOW Win_1 TITLE TO cVar


La Forma Semi-OOP


Para hacer lo mismo puede usarse la siguiente sintaxis semi-oop:

Win_1.Title := 'New Title'

cVar := Win_1.Title



Agregando El Menú Principal


Agregaremos un menú principal al programa:

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 02 - Property Test' ;
        MAIN

        DEFINE MAIN MENU
            POPUP "First Popup"
                ITEM 'Cambiar el Titulo de la Ventana' ACTION Win_1.Title := 'Nuevo Titulo'
                ITEM 'Recuperar el Titulo de la Ventana' ACTION MsgInfo ( Win_1.Title )
            END POPUP
        END MENU

    END WINDOW

    ACTIVATE WINDOW Win_1

Return

Como puede verse es bastante fácil e intuitivo.

Todo los comandos del menú principal estarán entre las declaraciones DEFINE MAIN MENU / END MENU.

Cada popup individual del menú estarán entre las declaraciones POPUP / END POPUP.

Cada ítem de menú se codificará vía la declaración ITEM.

Puede usarse cuantos popups sean necesrios y pueden anidarse sin ningún límite.



La función MsgInfo ()


Ésta es una función muy útil. Mostrará una pequeña ventana de mensaje (con el ícono de información del sistema) y un mensaje que se le pase como parámetro.

Puede agregar opcionalmente un título (como segundo parámetro)



El Control LABEL


El control LABEL permite mostrar texto y es muy fácil de utilizar también.

@ 100,10 LABEL Label_1 VALUE 'Este es un Label!'

@ 100,10 significa que el texto sera mostrado en la fila 100 , columna 10 (recordar que la unidad de medida es el pixel)

Label_1 es el nombre del control (lo identificaremos por este nombre)

La cláusula VALUE indica el valor inicial del control cuando es creado.

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 03 - Label Test' ;
        MAIN

        @ 100,10 LABEL Label_1 VALUE 'Este es un Label!'

    END WINDOW

    ACTIVATE WINDOW Win_1

Return



Obteniendo datos del usuario (el control TextBox)


El control TextBox es el medio más usado para obtener datos del usuario.

@ 40, 120 TEXTBOX Text_1,

Para ingresar datos numéricos, solo agregarse la cláusula NUMERIC:

@ 80, 120 TEXTBOX Text_2 NUMERIC

Para indicar un máscara de edición, debe usarse la cláusula INPUTMASK.

@ 120, 120 TEXTBOX Text_2 INPUTMASK 9999.99 NUMERIC'

#include "hmg.ch"

Function Main

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

        DEFINE MAIN MENU
            POPUP "First Popup"
                ITEM 'Cambiar el contenido del TextBox ' ACTION Win_1.Text_1.Value := 'nuevo valor del TextBox'
                ITEM 'Recuperar el contenido del TextBox ' ACTION MsgInfo ( Win_1.Text_1.Value)
                SEPARATOR
                ITEM 'Cambiar el contenido numérico del TextBox' ACTION Win_1.Text_2.Value := 100
                ITEM 'Recuperar el contenido numérico del TextBox' ACTION MsgInfo ( Str(Win_1.Text_2.Value))
                SEPARATOR
                ITEM 'Cambiar el contenido numérico del TextBox(InputMask)' ACTION Win_1.Text_3.Value := 1234.12
                ITEM 'Recuperar el contenido numérico del TextBox(InputMask)' 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

    ACTIVATE WINDOW Win_1

Return



Obteniendo Datos Lógicos


A veces, es necesario obtener datos de tipo lógico del usuario. La manera más fácil de hacerlo es utilizando el control checkbox.

@ 180, 120 CHECKBOX Check_1

Lo agregamos al programa, junto con nuevas opciones de menú para poder asignar o recuperar su valor

#include "hmg.ch"

Function Main

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

        DEFINE MAIN MENU
            POPUP "First Popup"
                ITEM 'Cambiar el Valor del CheckBox ' ACTION Win_1.Check_1.Value := .T.
                ITEM 'Recuperar el Valor del CheckBox ' ACTION MsgInfo ( if(Win_1.Check_1.Value,'.T.','.F.'))
            END POPUP
        END MENU

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

    END WINDOW

    ACTIVATE WINDOW Win_1

Return



Seleccionando Opciones


A veces, es necesario obtener el valor de una elección de los usuarios, entre un grupo pequeño de opciones que son conocidos en el momento del diseño.

La mejor manera de proceder en tales casos es usar el control RadioGroup.

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

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 06 - 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

ACTIVATE WINDOW Win_1

Return



Otras Formas de Selección de Opciones


Hay varias alternativas para obtener la opción de un usuario además de RadioGroup.

Uno de ellos es el control ListBox

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

Usando un Listbox, puede agregarse, cambiar o quitar items en tiempo de ejecución.

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 07 - 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))
                ITEM 'Agregar List Item' ACTION Win_1.List_1.AddItem ('New List Item')
                ITEM 'Sacar List Item' ACTION Win_1.List_1.DeleteItem (2)
                ITEM 'Cambiar List Item' ACTION Win_1.List_1.Item (1) := 'New Item Text'
                ITEM 'Mostrar Cantidad de List Item' ACTION MsgInfo (Str(Win_1.List_1.ItemCount))

            END POPUP
        END MENU

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

    END WINDOW

    ACTIVATE WINDOW Win_1

Return



Otras Formas de Selección de Opciones II


Otro alternativa para obtener la opción de un usuario es el COMBOBOX.

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

Usar un Combobox, es similar al ListBox.

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 08 - 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 'Agragar Combo Item' ACTION Win_1.Combo_1.AddItem ('New List Item')
                ITEM 'Sacar Combo Item' ACTION Win_1.Combo_1.DeleteItem (2)
                ITEM 'Cambiar Combo Item' ACTION Win_1.Combo_1.Item (1) := 'New Item Text'
                ITEM 'Mostar cantidad de Combo Item ' 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

    ACTIVATE WINDOW Win_1

Return



Botones


Otra manera para permitir que los usuarios tomen una acción (además de los menús) es por medio de botones.

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

#include "hmg.ch"

Function Main

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

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

    END WI NDOW

    ACTIVATE WINDOW Win_1

Return



Botones con Imagen


En lugar de un texto puede usarse una imagen.

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

#include "hmg.ch"

Function Main

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

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

    END WINDOW

    ACTIVATE WINDOW Win_1

Return

La cláusula tooltip (optativa) causa que una ventana pequeña con un texto explicativo se despliegue cuando el indicador del ratón se queda encima del control por unos segundos. Puede usarse esta cláusula con la mayoría de los comandos HMG.



Button + Checkbox = CheckButton


El control CheckButton, actua como un checkbox, pero se ve como un botón. Al igual que los botones, pueden ser de texto o gráficos.

@ 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 "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 11 - 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

    ACTIVATE WINDOW Win_1

Return



El Control DatePicker


La manera más fácil de obtener una fecha del usuario es mediante el control datepicker.

@ 10,10 DATEPICKER Date_1

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 12 - 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

    ACTIVATE WINDOW Win_1

Return



El control EditBox


El control EditBox permite manejar datos de texto de múltiples líneas.

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

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 300 ;
        TITLE 'Tutor 13 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

    ACTIVATE WINDOW Win_1

Return


El Control IMAGE



El control Image permite mostrar imágenes desde archivos .bmp .ico .gif .jpg o .emf

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

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 14 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

    ACTIVATE WINDOW Win_1

Return


El Control ProgressBar



El control ProgressBar permite mostrar el estado de ejecución de una operación

@ 10,10 PROGRESSBAR Progress_1;
    RANGE 0 , 65535

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400;
        HEIGHT 200 ;
        TITLE 'Tutor 15 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

    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



El Control Spinner


Una manera alternada de obtener datos numéricos es mediante el control Spinner. Consiste en un textbox con dos flechas que permiten cambiar el valor de los controles usando el ratón.

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

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 16 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

    ACTIVATE WINDOW Win_1

Return


El Control TAB



Usar TABs permite organizar los controles y ahorar espacio agrupándolos en carpetas.

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 250 ;
        TITLE 'Tutor 17 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

    ACTIVATE WINDOW Win_1

Return



El Control TOOLBAR


Los Toolbars se usan para agrupar botones de comando en una barra que se localiza generalmente en la parte superior de la ventana (debajo de la barra de menu.

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 640 HEIGHT 480 ;
        TITLE 'Tutor 18: ToolBar Test' ;
        MAIN ;
        FONT 'Arial' SIZE 10

        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 80,80 FLAT BORDER

            BUTTON Button_1 ;
                CAPTION '&Button &1' ;
                PICTURE 'button1.bmp' ;
                ACTION MsgInfo('Click! 1')

            BUTTON Button_2 ;
                CAPTION '&Button 2' ;
                PICTURE 'button2.bmp' ;
                ACTION MsgInfo('Click! 2') ;
                SEPARATOR

            BUTTON Button_3 ;
                CAPTION 'Button &3' ;
                PICTURE 'button3.bmp' ;
                ACTION MsgInfo('Click! 3')

        END TOOLBAR

    END WINDOW

    CENTER WINDOW Win_1

    ACTIVATE WINDOW Win_1

Return Nil



El Control Statusbar


Este control crea una barra en la parte inferior de la ventana, usada generalmente para mostrar información de estado.

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 400 ;
        HEIGHT 200 ;
        TITLE 'Tutor 19 Tab Test' ;
        MAIN

        DEFINE MAIN MENU
            POPUP '&StatusBar Test'
                ITEM 'Set Status Item 1' ACTION Form_1.StatusBar.Item(1) := "New value 1"
                ITEM 'Set Status Item 2' ACTION Form_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



Controles de Datos I: BROWSE


Los controles de datos están diseñados para trabajar con datos en archivos .dbf directamente.

El control Browse, permite mostrar o editar registros de bases de datos en forma tabular. La propiedad 'value' se usa para establecer u obtener el número de registro seleccionado (recno()).
Por defecto, el control Browse, no cambia el puntero de registro en su área de trabajo.

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 640 HEIGHT 480 ;
        TITLE 'Tutor 20: BROWSE Test' ;
        MAIN NOMAXIMIZE ;
        ON INIT OpenTables() ;
        ON RELEASE CloseTables()

        DEFINE MAIN MENU
            POPUP 'File'
                ITEM 'Set Browse Value' ACTION Win_1.Browse_1.Value := Val ( InputBox ('Set Browse Value','') )
                ITEM 'Get Browse Value' ACTION MsgInfo ( Str ( Win_1.Browse_1.Value ) )
                SEPARATOR
                ITEM 'Exit' ACTION Win_1.Release
            END POPUP
            POPUP 'Help'
                ITEM 'About' ACTION MsgInfo ("Tutor 20: BROWSE Test")
            END POPUP
        END MENU

        @ 10,10 BROWSE Browse_1 ;
            WIDTH 610 ;
            HEIGHT 390 ;
            HEADERS { 'Code' , 'First Name' , 'Last Name', 'Birth Date', 'Married' , 'Biography' } ;
            WIDTHS { 150 , 150 , 150 , 150 , 150 , 150 } ;
            WORKAREA Test ;
            FIELDS { 'Test->Code' , 'Test->First' , 'Test->Last' , 'Test->Birth' , 'Test->Married' , 'Test->Bio' } ;
            DELETE ;
            LOCK ;
            EDIT INPLACE

    END WINDOW

    CENTER WINDOW Win_1

    ACTIVATE WINDOW Win_1

Return Nil

Procedure OpenTables()
    Use Test
    Win_1.Browse_1.Value := RecNo()
Return Nil

Procedure CloseTables()
    Use
Return Nil

(*) Para cambiar este comportamiento debe usarse el comando 'Set BrowseSync On'.



Controles de Datos II: TEXTBOX, DATEPICKER, CHECKBOX, EDITBOX


Las versiones de estos controles para el manejo directo de datos almacenados en archivos .dbf, requiere el uso de las siguientes propiedades y métodos:

    Propiedad "Field":Establece el campo al cual el control está enlazado.
    Método "Refresh" : Actualiza el contenido del control basándose en el contenido actual del campo.
    Método "Save": Actualiza el archivo de base de datos de acuerdo al contenido del control.

#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



El Control SPLITBOX


Los controles o ventanas definidos como parte de este contenedor pueden ser ordenados por el usuario usando una "barra de arrastre" ubicada su izquierda. Debe omitirse  '@ <row>,<col>' en la definición del control.

#include "hmg.ch"

Function Main

    DEFINE WINDOW Win_1 ;
        AT 0,0 ;
        WIDTH 640 HEIGHT 450 ;
        TITLE 'Tutor 22: SplitBox Test' ;
        MAIN

        DEFINE SPLITBOX

            LISTBOX List_1 ;
                WIDTH 200 ;
                HEIGHT 400 ;
                ITEMS {'Item 1','Item 2','Item 3','Item 4','Item 5'} ;
                VALUE 3 ;
                TOOLTIP 'ListBox 1'

            EDITBOX Edit_1 ;
                WIDTH 200 ;
                HEIGHT 400 ;
                VALUE 'EditBox!!' ;
                TOOLTIP 'EditBox' ;
                MAXLENGTH 255

        END SPLITBOX

    END WINDOW

    CENTER WINDOW Win_1

    ACTIVATE WINDOW Win_1

Return Nil