Button actions created at runtime

Hello Devs
I have this code in Clarion 10 that creates buttons at run time, is it possible to assign events to them?
Where when clicking calls a function?

LOOP I# = 1 TO 5
	CREATE (I#, CREATE:button)
	I#{PROP:Use} = I# & 'MENU_CONTROL'
	I#{PROP:Height} = 23 
	I#{PROP:Width} = 75 
	I#{PROP:Xpos} = 166
	I#{PROP:Ypos} = POS# 
	 I#{PROP:Text} = 'Exemplo'
	I#{PROP:Tip} = 'Exemplo'
	I#{PROP:Hide} = false
	POS# +=25
		
END

Rather than using a throwaway FEQ, you should keep track of your button FEQs so you know what the behavior should be.

You can let the RTL create the FEQ for you, so you don’t clash:

  MyQ.FEQ = CREATE(0,CREATE:Button)
  MyQ.ButtonID = 'MySpecialButton'
  ADD(MyQ)

Then, you could ether REGISTER an event handler or put code in the ACCEPT loop to act on the button presses.

This would be on EVENT:Accepted:

  MyQ.FEQ = FIELD()
  GET(MyQ,MyQ.FEQ)
  IF NOT ERRORCODE()
    CASE MyQ.ButtonID 
    OF 'MySpecialButton'
       Woohoo()
    END
  END
2 Likes

Also, PROP:Use is not meant to accept text. That’s how you assign a variable.

Variables/fields of the reference-to-function type are available… So, a function/method to invoke on pressing the button can be associated with that button’s FEQ.

That’s really cool. Is there an example anywhere?

Thanks

Thank you all, I managed to reach a conclusion here on my project.

Reference variables of procedural types were introduced in C11.

  1. Declare an event handler function type:

EventHandler PROCEDURE(SIGNED ev),BYTE,TYPE

or, if it’s desirable to have such handler as a method of some class:

EventHandler PROCEDURE(*SomeClass, SIGNED ev),BYTE,TYPE

  1. If a QUEUE is using for mapping:
FeqQueue  QUEUE
feq         SIGNED
handler     &EventHandler
          END
...
  FeqQueue,feq = <control FEQ>
  FeqQueue.handler &= <handler function for this control>
  ADD (FeqQueue, +FeqQueue.feq)
  ...
  ACCEPT
    FeqQueue.feq = FIELD()
    GET (FeqQueue, +FeqQueue.feq)
    IF ERRORCODE() = 0
      CASE FeqQueue.handler (EVENT())
      OF LevelBenign
      OF LevelFatal
        BREAK
      OF LevelNotify
        CYCLE
      END
    ELSE
      <other processing>
    END
  END

  1. If TIE function is using for mapping:
EventHandlerAS  ASTRING('EventHandler')
handler         &EventHandler,AUTO
...
  TIE (EventHandlerAS, feq, ADDRESS (<event handler function for this control>)
  ...
  ACCEPT
    handler &= TIED (EventHandlerAS, FIELD())
    IF NOT hander &= NULL
      CASE handler (EVENT())
      OF LevelBenign
      OF LevelFatal
        BREAK
      OF LevelNotify
        CYCLE
      END
    ELSE
      <other processing>
    END
  END
  • If user-defined property is using for mapping:
EventHandlerProp  STRING('EventHandler')
handler           &EventHandler,AUTO
...
  feq {EventHandlerProp} = ADDRESS (<event handler function for this control>)
  ...
  ACCEPT
    handler &= 0 + FIELD(){EventHandlerProp}
    IF NOT hander &= NULL
      CASE handler (EVENT())
      OF LevelBenign
      OF LevelFatal
        BREAK
      OF LevelNotify
        CYCLE
      END
    ELSE
      <other processing>
    END
  END

Off-topic. If someone is missing possibility to associate some values with QUEUEs or not likes the NAME attribute for association, look at TIE/TIED and INSTANCE.

5 Likes

Thanks so very much, @also!