Handles

Hi Everyone,
I have a Smart Window built as such:

1 - Smart Object called h_Toolbar.
1 - Smart Object called h_viewer1.
1 - Smart Object called h_browser1.

The browser currently is my query.

The Toolbar has some buttons created as such:
Code:
PROCEDURE ADDBUTTON:

  define input parameter piIndex   as integer no-undo.
  define input parameter pcKey     as character no-undo.
  define input parameter pcCaption as character no-undo.
  define input parameter piStyle   as integer no-undo.
  define input parameter pcImage   as character no-undo.
  define input parameter pcTooltip as character no-undo.

  define variable chButton as COM-HANDLE no-undo.

  if piStyle = 3 or piStyle = 4 then do:
    if piIndex = 0 then
      chButton = chToolbar:Buttons:Add(,pcKey,,piStyle) .
    else
      chButton = chToolbar:Buttons:Add(piIndex,pcKey,,piStyle) .
    RELEASE OBJECT chButton NO-ERROR.
    chButton = ?.
    return.
  end.
  
  if piIndex = 0 and pcKey = "":U and pcImage = "":U then
    chButton = chToolbar:Buttons:Add(,,pcCaption,piStyle) .
  else if piIndex = 0 and pcKey <> "":U  and pcImage = "":U then
    chButton = chToolbar:Buttons:Add(,pcKey,pcCaption,piStyle) .
  else if piIndex = 0 and pcKey <> "":U and pcImage <> "":U then 
    chButton = chToolbar:Buttons:Add(,pcKey,,piStyle,pcImage) .  
  else if piIndex <> 0 and pcKey = "":U and pcImage = "":U then
    chButton = chToolbar:Buttons:Add(piIndex,,pcCaption,piStyle) .
  else if piIndex <> 0 and pcKey <> "":U  and pcImage = "":U then
    chButton = chToolbar:Buttons:Add(piIndex,pcKey,pcCaption,piStyle) .
  else if piIndex <> 0 and pcKey <> "":U and pcImage <> "":U then 
    chButton = chToolbar:Buttons:Add(,pcKey,,piStyle,pcImage) .     
 
  ASSIGN
   chButton:ToolTipText = pcToolTip 
   chButton:DESCRIPTION = pcTooltip
  NO-ERROR.
 
RELEASE OBJECT chButton NO-ERROR.
 chButton = ?.
END PROCEDURE.

I was wandering, since i know the PCKEY of the button, how do you think i can call the button from my Smartwindow?

How do i call that specific button? I know there is a Trigger called OCX.ButtonClick that does the job but it needs the handle of the button and i don't know how to get that Handle from my smartwindow.

Here is the OCX.ButtonClick OF Frame CTRLFrameTB:

Code:
/*------------------------------------------------------------------------------
  Purpose:     
  Parameters:  Required for OCX.
    Button
  Notes:       
------------------------------------------------------------------------------*/

DEFINE INPUT PARAMETER p-Button AS COM-HANDLE NO-UNDO.

define variable cKeyName as character no-undo.

DEFINE VARIABLE hTempFocus AS HANDLE NO-UNDO.

if glHelpMode then do:
    if valid-handle(ghHelpWaitFor) then
      apply "U1":u to ghHelpWaitFor.
      RELEASE OBJECT p-Button NO-ERROR.
    return no-apply.
end.
else do:
  cKeyName = p-button:KEY NO-ERROR.

  IF cKeyName <> "":U then DO:
    IF cKeyName = "Save":u THEN DO:
      ASSIGN hTempFocus = FOCUS:PARENT no-error.
      IF VALID-EVENT(hTempFocus,"ROW-LEAVE":U) THEN DO:
        APPLY "ROW-LEAVE":U TO hTempFocus.
      END.     
    END.
    run execute-toolOCX in ghroutines (THIS-PROCEDURE, cKeyName, ?).
  END.
end.
RELEASE OBJECT p-Button NO-ERROR.
p-Button = ?.
END PROCEDURE.



Thanks.

(Progress 10.2a).
 
If you're running ADM2 ( you are not talking about the ADM version you are running ) and depending on the version of ADM2 you're running different properties may hold the information you need.

The SDV should have properties like AllFieldNames and AllFieldHandles which are both CSV lists. The first holds the names while the latter holds the handles. You just need to lookup the name list and extract the handle from the second list with the position you got. Additionally, as this is text, you need to convert the number with the WIDGET-HANDLE function. Now you should have the handle to the button if it was on the name list ...

HTH, RealHeavyDude.
 
I have no idea what ADM version i am running. how can i know that?
I haven't used handle so this part is quite new to me.... Been doing CHUI for 10 years so my GUI is pretty bad!
How do i use these properties?

What is an SDV?
 
In most cases the version of ADM you are running is directly related with the Progress/OpenEdge version you are running, but not necessarily ...

In Progress V8 there is only ADM1 which is so old that I can't remember much ...

In Progress V9 ADM2 was introduced which is internally completely different then the ADM1. While the ADM1 used include file technique to include common behavior into the objects, the ADM2 uses super procedures to inherit common behavior from the classes from which the objects are derived.

In order to develop ADM applications you need to have the OpenEdge studio license. If you install that license then you will find a adm and adm2 folder beneath the src folder in the installation directory. If you don't have another path to these directories in your PROPATH then you are using the version that comes with the Progress installation - that much to the version. I think that should give you an idea how to know what you're dealing with ...

SDV means smart data viewer. In ADM1 the object was called smart viewer whereas in ADM2 the equivalent to it was called smart data viewer. The reason of the name change is because the objects itself may look the same from the UI point of view, but under the hood they have nothing in common. Whereas the ADM1 smart viewer directly accesses the database, the ADM2 smart data viewer does not have any database access - it needs a smart data object ( SDO ) linked to it to get data.

How do you know whether you're running ADM1 or ADM2 - I would check the include file references in the objects whether they point to adm or adm2, then you should know.

I know that's bad for you, but, IMHO of course, you won't really be able to do much "the right way" - where "the right way" means with the frame work instead fighting against it - without proper training. And, unfortunately, I have to admit, the learning curve for, especially, ADM2 is rather steep. That's - again IMHO of course - one of the reason these frame works were never widely accepted with Progress developers because they found out pretty soon that this is not about 4GL knowledge, instead it's about knowing the frame work, and, in the case of ADM2, being familiar with some OO terminology.

HTH, RealHeavyDude.
 
ADM2 it is...
I have SDO's everywhere with links.

I was wandering how to use the properties you mention. Progress is not giving up a lot of info on it in the Help files :(

Other then using these, there are no way to run a adm-get-something to get the com-handle?
 
Most properties, but not all, have a get and a set functions which you can invoke when you have the handle to the object ( which is a persistent procedure ).

Option 1, using the dynamic function syntax:

ASSIGN cAllFieldNames = DYNAMIC-FUNCTION ( 'getAllFieldNames':U IN hObject ).
Option 2, using the pseudo syntax:

{get AllFieldNames cAllFieldNames hObject}.

Advantage of option 1 is that you can integrated error handling with it ( in case the function does not exist or your procedure handle is not valid ). The disadvantage is, that it's an expensive function call.

Advantage of option 2 is that it directly access the field in the ADMProps Temp-Table which lives in each smart object associated with the property - therefore it's very fast. The disadvantage is, that you can't have error handling which might lead to unexpected behavior in the application if the operation fails.


HTH, RealHeavyDude.
 
Both didn't work.

First one used as such gave me a runtime error:
User-defined Function 'AllFieldNames' invoked dynamically but could not be found. (5639)

Code:
ASSIGN cAllFieldNames = DYNAMIC-FUNCTION ( 'getAllFieldNames':U IN h_Toolbar ).
MESSAGE cAllFieldNames
    VIEW-AS ALERT-BOX INFO BUTTONS OK.
ASSIGN cAllFieldHandle = DYNAMIC-FUNCTION ( 'getAllFieldHandles':U IN h_Toolbar ).
MESSAGE cAllFieldHandle
    VIEW-AS ALERT-BOX INFO BUTTONS OK.

and the other gives an error message at the compile:
Code:
{get AllFieldNames cAllFieldNames h_Toolbar}.
FOR EACH ADMProps:
    DISP ADMProps.
END.
Gives me:
Unknow of Ambiguous table ADMProps. (725)
 
The AllFieldNames and AllFieldhandles properties come from the data visual class. Therefore they won't exist in a toolbar object. Somewhere along the way I did lose the information where the button was for which you tried to get the handle.

If it's a button on a smart toolbar then it's a completely different story. Usually, if they are implemented the ADM2 way, buttons just publish an event which is then picked up by another smart object linked to the toolbar and that actually does something when it receives the event.

If you know the event that get's published when the button is pressed you can just publish the event in the name of the toolbar and everything will work as if the button on the toolbar was pressed.

PUBLISH "myEvent" FROM hToolbar ( parameter1, parameter2, ... ).

HTH, RealHeavyDude.
 
Alright... the publish event didn't work...
But this worked:
Code:
RUN notify in h_ToolBar (zzTool.NotifySelect) NO-ERROR.

unfortunatly, this does not fix my problem....

My problem is that whenever i call a click on this button, the lookup opens, then the lookup's Define Search window (So now i have 3 windows open, this is the client's request).
So everything is fine, until i close my 3rd window... the the focus of the lookup is lost and the Main window comes back in front...
So i was wandering if i could put something like :

Code:
RUN notify in h_ToolBar (zzTool.NotifySelect) NO-ERROR
WAIT-FOR WINDOW-CLOSE OF  SomeKindOfChildGettingFunction.

Thing is, if i manually (With a mouse) click that button, then it does not behave as such.
Is there anyway to remove the focus from the main window upon leaving? or can i do something with the wait for?
 
Now I am pretty surprised that something like "notify" works in the ADM2. As far as I know this were one of the two ADM1 mechanisms to notify other objects to do something. But the last time I had something to do with is more than 15 years ago ...

Neither does a notify procedure exist in toolbar.p ( which is the class super procedure for the toolbar ) nor in one of the other class super procedures a toolbar has loaded. To me that looks like if your toolbar class is customized with a functionality of notify. If that's the case you should have a toolbarcustom.p procedure in the PROPATH which should contain the customization, an internal procedure called notify ...

You focus problem - but here I have to speculate - most likely comes from the fact that you don't use the same technique which is used in the createObjects sequence to start the other windows but to just run them with a RUN statement. If that's the case the parenting of the windows get screwed up and you will experience what you experience.

How are all these windows started?

Regards, RealHeavyDude.
 
The one in the Initialise section is called as i previously said.
The other one is called using this procedure:
(Look for the zztool.notifyselect variable.

thing is, i tried this methode before and it still messes up the parenting....


Code:
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE execute-toolOCX Method-Library 
PROCEDURE execute-toolOCX :
/*------------------------------------------------------------------------
  Procedure   : execute-toolOCX
  Purpose     : execute the function requested by the object activated in toolbar

  Description :
    Whenever an object (combo or button) is "clicked" this function will execute
    the appropriate procedure (file, name, state, etc.).

  Parameters  : phToolBar    Handle of toolbar
                pcKeyName    Unique key of tool (ToolId)
                phTool       Handle of Combo-box 

------------------------------------------------------------------------*/
  define input parameter phToolBar  as handle    no-undo.
  define input parameter pcKeyName  as character no-undo.
  define input parameter phTool     as handle    no-undo.

  define variable hContainer        as handle  no-undo.
  define variable cContainer        as char    no-undo.
  define variable cObjectName       as character no-undo.
  define variable lmethod           as logical no-undo.
  define variable iToolID           as integer no-undo.
  define variable lFromMenu         as logical no-undo.
  define variable lToggled          as logical no-undo.

  IF TRANSACTION AND 
     (LASTKEY = KEYCODE("RETURN":U) OR 
      LASTKEY = KEYCODE("F2":U)) THEN
     RETURN NO-APPLY.

  run get-link-handle in adm-broker-hdl (phToolBar, "CONTAINER-SOURCE":u, output cContainer).

  hContainer = widget-handle(entry(1, cContainer)).

  if not valid-handle(hContainer) then do:
      message "Error finding hContainer in execute-tool":T100 view-as alert-box error.
      return.
  end.

  IF phTool <> ? then do:                /* coming from Combo-Box */
    run get-private(phTool, "ToolID":u).
    iToolID = integer(return-val).
    find first zzTool
       where zzTool.ToolID = iToolID no-lock no-error.
  end.
  else if pcKeyName = "":u and phTool = ? then  do:  /* Coming from the menu */
    run get-private(self,"ToolID":u).
    assign
      iToolID     = if return-value = ? then 0 else integer(return-value)
      lFromMenu   = Yes
    NO-ERROR.
    Find First zzTool WHERE zzTool.ToolID = iToolID NO-LOCK NO-WAIT NO-ERROR.
  end.
  else
    find first zzTool
       where zzTool.KeyName = pcKeyName no-lock no-error.

  if not available zzTool then
    return.

  /* start processing */
  if zzTool.ProcedureFile <> "":u then do:            /* EXTERNAL PROCEDURE FILE */
    ASSIGN
      File-Info:File-Name = zzTool.ProcedureFile
      cObjectName = File-Info:Full-PathName  .
      if cObjectName = ? then
         run message in this-procedure ("SYS":u, "MENU":u, 001, zzTool.ProcedureFile).
      else do:
       if zzTool.WidgetType = "BUTTON":u then
          run value(cObjectName) no-error.
       else
          run value(cObjectName) (INPUT phTool, INPUT phToolBar) no-error.
      end.
  end.
  else if zzTool.ProcedureName <> "":u then do:        /* PROCEDURE NAME */
    if lookup(zzTool.ProcedureName, this-procedure:internal-entries) > 0 then do:
      if zzTool.WidgetType = "BUTTON":u then
        run value(zzTool.ProcedureName) no-error.
      else
        run value(zzTool.ProcedureName)  (INPUT phTool, INPUT phToolBar) no-error.
    end.
    else if lookup(zzTool.ProcedureName, phToolBar:internal-entries) > 0 then do:
      if zzTool.WidgetType = "BUTTON":u then
        run value(zzTool.ProcedureName) in phToolBar no-error.
      else
        run value(zzTool.ProcedureName) in phToolBar  (INPUT phTool, INPUT phToolBar) no-error.
    end.
    else if valid-handle(hContainer) and lookup(zzTool.ProcedureName, hContainer:internal-entries) > 0 then do:
      if zzTool.WidgetType = "BUTTON":u then
        run value(zzTool.ProcedureName) in hContainer no-error.
      else
        run value(zzTool.ProcedureName) in hContainer (INPUT phTool, INPUT phToolBar) no-error.
    end.
    else
      run message in ghRoutines ("SYS":u, "MENU":u, 003, zzTool.ProcedureName).
  end.
  
  else if zzTool.FunctionID <> 0 then                /* FUNCTION */
    run execute-function (zzTool.FunctionID).
    
  else if zzTool.NotifySelect <> "":U then do:             /* NOTIFY via ADM */
    run notify in phToolBar (zzTool.NotifySelect) no-error.
    if RETURN-VALUE = "ERROR":U then do:
      /* There is no ToolBar.  The "{1}" procedure can not be "notified". */
      run message in ghRoutines ("SYS":u, "MENU":u, 005, zzTool.NotifySelect).
    end.
  end.
  
  else if zzTool.NotifyOn <> "":U OR zzTool.NotifyOff <> "":U then do:      /* TOGGLE TOOLS */
    /* finds handle of container to see if we must update the corresponding menu */
    run get-link-handle in adm-broker-hdl (phToolBar, "CONTAINER-SOURCE":u, output cContainer).
    hContainer = widget-handle(entry(1, cContainer)).
    if not valid-handle(hContainer) then do:
      message "Error finding hContainer in execute-tool":T100 view-as alert-box error.
      return.
    end.
    for each tmpToolHandle
        where tmpToolHandle.ToolID    = zzTool.ToolID
          and tmpToolHandle.Procedure = hContainer:

      /* 1 = DOWN and 2 = UP (default) */
      tmpToolHandle.Toggled = if tmpToolHandle.Toggled = 1 then 2 else 1.
      if valid-handle(tmpToolhandle.Handle) and tmpToolHandle.Handle:type = "MENU-ITEM":u then
        assign
          tmpToolHandle.Handle:checked = if tmpToolHandle.Toggled = 1 then YES else NO NO-ERROR.
      else    
        run SetButton in phToolbar 
           (zzTool.KeyName,"VALUE":U,if tmpToolHandle.Toggled = 1 then STRING(1) else STRING(0) ).  
      lToggled =  if tmpToolHandle.Toggled = 1 then Yes else no.
    end.
    run notify in phToolBar (if lToggled then zzTool.NotifyOn else zzTool.NotifyOff).
  end.
  
  IF zzTool.GroupButton Then DO: /* Remove the check from all other Grouped tools */
     IF NOT VALID-HANDLE(hContainer) THEN do:
       run get-link-handle in adm-broker-hdl (phToolBar, "CONTAINER-SOURCE":u, output cContainer).
       hContainer = widget-handle(entry(1, cContainer)).
     End.
     IF lFromMenu then
       RUN SetButton in phToolbar (zzTool.KeyName,"VALUE":U,STRING(1) ). 

     for each tmpToolHandle
          where tmpToolHandle.Procedure = hContainer
            and Grouped                 = yes:

        /*Set to down  */
       if tmpToolHandle.ToolID <> zzTool.ToolID then
          tmpToolHandle.Toggled =  2 .
       else
         tmpToolHandle.Toggled =  1.
       if valid-handle(tmpToolhandle.Handle) and tmpToolHandle.Handle:type = "MENU-ITEM":u then
         if  tmpToolHandle.ToolID    <> zzTool.ToolID then
            tmpToolHandle.Handle:checked =  NO.
         else
            tmpToolHandle.Handle:checked =  YES.
       else if lFromMenu and tmpToolHandle.ToolID <> zzTool.ToolID then  
         RUN SetButton in phToolbar (tmpToolHandle.KeyName,"VALUE":U,STRING(0) ). 
     end.
  END.
 

END PROCEDURE.
 
The code

run get-link-handle in adm-broker-hdl (phToolBar, "CONTAINER-SOURCE":u, output cContainer).
is ADM1 code.

Therefore this code references ADM1 code. If you use smart data objects too, then I would say your application mixes and matches ADM1 and ADM2 functionality. Never have seen this before though ...

It's hard to say where your focus problem comes from. But I know that I had to fix something back then in ADM1. Don't know if I can find the solution to that - it's more than 15 years ago that I had to fiddle with this ...

Regards, RealHeavyDude.
 
Back
Top