Home » Company » White Papers » A Prompt Button for DataFlex 3.x

A Prompt Button for DataFlex 3.x

  • by

Object Oriented Applications
A Data Access Worldwide White Paper by Vincent Oorsprong
Last Edited: August 12, 2001

Overview

The object oriented program language of DataFlex offers, even for the starting developer, a set of very powerful functions to create a list of records the user can select from. This is called a prompt list object. The class to create that kind of objects from is called SELECTION_LIST, or SELECTION_LIST0 when we refer to the DataFlex Application FrameWork (DAF).

When we add such a SELECTION_LIST(0) object to our application we have to connect this object to one or more ENTRY_ITEMs via either the iPROMPT entry option or the PROMPT_OBJECT property (See Figure 1).

Object Customer_Data Is An Entry_Form
  Set Server To (Customer_Dataset (Current_Object))
    Item_List
      Entry_Item Customer.Number { iPrompt = (Select_Customer (Current_Object)) }
      Entry_Item Customer.Name
        Set Prompt_Object To (Select_Customer (Current_Object))
              …
       …
  End_Item_List
End_Object

1. Sample for the prompt object connection

But when we’ve connected the prompt list object to the entry_item we don’t have anything to tell the user that a prompt list object was connected to choose from. We have to tell the user of the application that a list of records to choose from is available. In DataFlex 2.3b there is a de-facto standard that entry windows will be surrounded by a pair of ’<>’ characters to tell the users that they can press the find, the find next and the find previous search keys (See Figure 2).

/Customer_Form

Number.: ______________________________
Name…: ______________________________
Address: ______________________________
Zipcode: ______________________________
City…: ______________________________

2. Search indicator hooks on screens in 2.3b

With the release of the DataFlex 3.0 OO style programs we have to change these characters because the button objects will now be surrounded by a pair of ’<>’ characters. In my previous company we decided to take the ’””’ characters as a replacement for the characters to indicate that search facilities are available.

I don’t know if there is a chapter in IBM’s SAA/CUA books that tell us how we should tell the user that a prompt list is available, but in our company we decided to take the arrow up character (?) to indicate the presence of a prompt list. This is similar to the way that MS/Windows programs tell the user that there is a drop-down list available. But in Windows this is the arrow down character. Because of the difference between the drop-down lists and a selection list we choose to use the arrow up character.

For a long period of time we just entered the arrow up character in the screens when we drew them in the editor. But at a certain point we thought that it would be nice to be able to click on the arrow (with the mouse) and then get the selection list object. See Figure 3 for a sample of the screen.

To do this you can create a special ENTRY_FORM class which looks when the mouse_down message is received at what absolute location this was done. Then you have to find out if the absolute location on the screen is the same as the arrow up character. This requires a lot of programming, while a better way is available. I will show you one way of comparing the current mouse position with the arrow up character in the screen. Then you can judge for yourself.

/Customer_Form
Number.: ______________________________
Name…: ______________________________
Address: ______________________________
Zipcode: ______________________________
City…: ______________________________

3. Sample of the screen with arrow up indicator

We must augment the procedure MOUSE_DOWN. We do this by first cloning the ENTRY_FORM or ENTRY_FORM0 class to a new one called ENTRY_FORM1. This all is shown in Figure 4. The procedure MOUSE_DOWN takes two parameters. The first one is the windownumber where the mouse cursor is located above when the user presses the left mouse button. When the mouse cursor is not above a window, we will have a zero (0) in this parameter. We only need to test if the current absolute mouse position equals the position of arrow up character when the window is zero, because the arrow up character will never be in the window itself.

Class Prompt_Mixin Is A Message
  Procedure Mouse_Down Integer Win# Integer Pos#
    Local Integer Abs_Mouse_Pos# Obj_Loc# Image#
    Local Integer Line# Pos_X# Pos_Y# Obj# Sav_Obj# 
    Local String Data$

    If (Win# > 0) Begin
      Forward Send Mouse_Down Win# Pos#
    End
    Else Begin
      Get Absolute_Mouse_Location To Abs_Mouse_Pos#
      Get Location To Obj_Loc#
      Move (Hi (Abs_Mouse_Pos#) – Hi (Obj_Loc#)) To Pos_Y#
      Move (Low (Abs_Mouse_Pos#) – Low (Obj_Loc#)) To Pos_X#
      Move Current_Object To Sav_Obj#
      Move Current_Object To Obj#
      Repeat
        Get Image_Number Of Obj# To Image#
        If (Image# < 0) Begin
          Get Parent Of Obj# To Obj#
        End
      Until (Image# >= 0)

      Move Sav_Obj# To Current_Object
      If (Image# = 0) Begin
        Procedure_Return
      End
      Direct_Input (’IMAGE:’ + String (Image#))
      [~Seqeof] Begin
        For Line# From 1 To Pos_Y#
          Readln
        Loop
        Readln Data$
        If (Mid (Data$, 1, Pos_X# + 1) = Character (24)) Begin
          Set Absolute_Mouse_Location To (Hi (Abs_Mouse_Pos#)) Low (Abs_Mouse_Pos#) – 2) True
          Send Mouse_Down 0 0
          If (Prompt_Object (Current_Object, Current)) Begin
            Send Process_Key Kprompt
          End
        End
      End
      Close_Input
    End
  End_Procedure // Mouse_Down
End_Class // Prompt_Mixin

Class Entry_Form1 Is An Entry_Form
   Import_Class_Protocol Prompt_Mixin
End_Class // Entry_Form1

4. Procedure Mouse_Down

Then we will retrieve the absolute mouse location and then subtract the position of the image of the current object from this to get the Y and X values relative to this object.

Before we can open the image with a direct_input command we must find out which imagenumber the object uses. The function IMAGE_NUMBER will return this but when the image is not given or when the image is created with sub_page we need to find out which real image is used. Sub_Pages, as well as the constant NO_IMAGE will let the IMAGE_NUMBER function return a negative number, so we will step through a loop until the image number is zero or positive.

If the loop terminates and the imagenumber is zero, we will stop our testing immediately. If not we will open the image with the number returned in the above search activity. We will read the number of Y lines in the image without testing and then we have the correct line. We check with the MID function if the character at the X+1 position equals the arrow up character. If this is true we will change the absolute mouse location to a position that is above the window. Then we will execute another mouse down to make the window’s item the current one. After doing this we will look to see if the PROMPT_OBJECT property contains an object ID. If this is true we will execute/fake a PROMPT key. And YES, this all works! But this means a not-so-small procedure that reads the image each time the mouse is pressed next to an item to find out if a prompt list object should be popped up. This is a lot of I/O and therefore not desirable.

The reason why we didn’t put the procedure mouse_down in the ENYTRY_FORM1 class itself is that we now are able to override the procedure in every class we whish, by subclassing the original class and adding an IMPORT_CLASS_PROTOCOL command.

Here is a second (and better) way, the more OO way of creating a solution. For this we defined a class called PROMPT_BUTTON. An object of this class is one character high and one character wide. It doesn’t need an image because the PROMPT_BUTTON class is derived from the EDIT class. The object shows the arrow up sign; when the left mouse button is pressed down, we make the item that is connected to this object the current item. After that, the prompt message is sent.

For every ENTRY_ITEM where we want to have a prompt button, we need to define an object of this new class. The size and the contents are set automatically. We only need to set two properties in each of the prompt button objects. Both properties have to be set. The first property is called LINK_WINDOW. This property will help the object change the current item of the object to the item whose number is stored in this property. The second property is the BUTTON_OFFSET. This will place the prompt button object on a relative position to the window. See Figure 5 for a sample of the usage.

Object Customer_Data Is An Entry_Form
  Set Server To (Customer_Dataset (Current_Object))

  Item_List 
    Entry_Item Customer.Number { iPrompt = (Select_Customer (Current_Object)) }
    Entry_Item Customer.Name
      Set Prompt_Object To (Select_Customer (Current_Object))
    …
    …
  End_Item_List

  Object Customer_Prompt_Button1 Is A Prompt_Button
    Set Link_Window To 1
    Set Button_Offset To 7
  End_Object 

  Object Customer_Prompt_Button2 Is A Prompt_Button
    Set Link_Window To 2
    Set Button_Offset To 31
  End_Object 
End_Object

5. Sample of prompt_button usage

If it were possible to find out the length of the window and thus the position in which to place the prompt button object, it would be possible to create the objects automatically in the END_CONSTRUCT_OBJECT method, because the LINK_WINDOW can be found based on the PROMPT_OBJECT property. We can’t do this, yet, so the programmer must write the statements himself. We took the EDIT class as the superclass of our new class because it doesn’t need an image element and has a dynamic screen component. There is one part that I don’t like in our solution and that is the automatic creation of a scrollbar child object, whether this can be shown on the screen or not or whether you want it or not. We end this paper with Figure 6 which lists the code of the PROMPT_BUTTON class:

//****************************************************************************//
// $File name : PROMPTBT.CLS //
// $File title : // 
// Notice : Copyright Micro U.S. Nederland (c) 1993 // 
// $Author : VO // 
// $System : Micro U.S. Packages // 
// Created : 11-02-94 @ 11:03:19 // 
// $Last Rev : 18-02-94 @ 17:14:57 //
//                                //
// $Description                                                         // 
// This include file contains the CLASS defintion for the PROMPT_BUTTON // 
// class. This class will let you create a dynamic button which will // 
// present a list of records the user can select, like he/she pressed the // 
// F4 key. // 
//                                    //
// $Rev History                  //
// 11-02-94 File header created // //****************************************************************************//

//****************************************************************************//
// $Module type: CLASS //
// $Module name: Prompt_Button // 
// $Author : VO // 
// Created : 11-02-94 @ 12:54:08 // 
//                               // 
// Description                     // 
// By taking the EDIT class as superclass for this class we don’t need to //
// have a window as image which makes it all easier. // 
//                                                 // 
// $Rev History // 
// 11-02-94 Module header created                      // //**************************************************************************//
Class Prompt_Button Is An Edit
  //***********************************************************************// 
  // $Module type: PROCEDURE                    // 
  // $Module name: Construct_Object             // 
  // $Author : VO                               // 
  // Created : 11-02-94 @ 12:52:05              // 
  //                                           // 
  // Description                                // 
  // At object creation moment we set the FOCUS_MODE property of the prompt//
  // “button” object to POINTER_ONLY to avoid the user to rotate in. // 
  // Then two properties are defined and the size is set to one line and // 
  // one row because we only have to show the character.   // 
  //                                       // 
  // Properties                           //
  // BUTTON_OFFSET: This tells the object to be placed at a location which // 
  // is equal to the location of the parent object window // 
  // plus the value of this property. The value should be // 
  // at least equal to the size of the window (which we // 
  // can’t query ourselfs). //
  // LINK_WINDOW : The window number of the item to which the prompt // 
  // “button” object should be placed.      //
  //                                        // 
  // $Rev History                           // 
  // 11-02-94 Module header created         //     //*************************************************************************// 
  Procedure Construct_Object
    Local Integer Color_Complex#

    Forward Send Construct_Object

    Set Focus_Mode To Pointer_Only

    Property Integer Button_Offset Public 0
    Property Integer Link_Window Public 1

    Get Object_Color Of (Parent (Current_Object)) To Color_Complex#

    Set Size To 1 1
    Set Max_Lines To 1 
    Set Value Item 0 To (Character (24))
  End_Procedure // Construct_Object

  //********************************************************************// 
  // $Module type: PROCEDURE                 // 
  // $Module name: End_Construct_Object         // 
  // $Author : VO                    // 
  // Created : 11-02-94 @ 12:44:08            
//
  //                                               // 
  // Description                                 // 
  // When the object creation is almost finished we will correct/set the // 
  // location of the object. This is done in this method because the value //
  // of the BUTTON_OFFSET property will be set in the object and doesn’t //
  // contain the right value in the procedure CONSTRUCT_OBJECT. //
  //                                                           //
  // First we will determine the location of the window whose number is // 
  // stored in the property LINK_ITEM. The HI and LOW parts of this loca- // 
  // tion value are added to the location return values of the object // 
  // who is the parent object of this object to be able to position this //
  // prompt “button” object. //
  //                 // 
  // $Rev History //
  // 11-02-94 Module header created //   //******************************************************************//
   Procedure End_Construct_Object 
    Local Integer Location_Complex# Parent_Location#

    Forward Send End_Construct_Object

    Get Window_Location Of (Parent (Current_Object)) ;
      Item (Link_Window (Current_Object)) To Location_Complex#
    Get Location Of (Parent (Current_Object)) To Parent_Location#

    Set Location To (Hi (Location_Complex#) + Hi (Parent_Location#)) ;
      (Low (Location_Complex#) + Low (Parent_Location#) + ;
      Button_Offset (Current_Object)) Absolute
  End_Procedure // End_Construct_Object

  //********************************************************************//
  // $Module type: PROCEDURE                         //
  // $Module name: Mouse_Down                        // 
  // $Author : VO                                    //
  // Created : 11-02-94 @ 12:42:41                   //
  //                                                   // 
  // Description                                     //
  // When the mouse cursor was above this object and the mouse button was //
  // pressed down we will activate the parent object and send a prompt //
  // message to the parent object causing to popup its prompt_object. //
  //                                                                 //
  // $Rev History // 
  // 11-02-94 Module header created //
  //*************************************************************************//
   Procedure Mouse_Down Integer Line# Integer Pos#
     Forward Send Mouse_Down Line# Pos#
     Delegate Send Activate
     Set Current_Item Of (Parent (Current_Object)) To (Link_Window (Current_Object) – 1)
     Delegate Send Prompt
  End_Procedure // Mouse_Down
End_Class // Prompt_Button

6. Contents of the PROMPTBT.PKG file

Note This article – earlier published in Dutch in the DataFlex Echo (Magazine of the DataFlex Developers Group Holland) – is originally written a few years ago when DataFlex 3.01 was the current product. The techniques however does not limit you to this product release. The author was in that time working for Micro U.S. Nederland.