Example of Passing Window and List References to Another Thread

Special thank you to Mark Goldberg!

I wanted to know how to pass a reference to a LIST control to another thread. I wanted to access the List’s properties in the new thread. For example, the maximum number of columns the list has:

?SomList{PROPLIST:Exists,0}

With Mark’s help I was able to make it work.

In my case I created a global TYPE’d GROUP to ease the passing of parameters to the new thread:

ThreadGroupType			Group,TYPE
WindowRef				&Window
ListRef					Long
						End

Then, on a button’s EVENT:Accepted embed:

ThreadGrp.WindowRef &= Window
ThreadGrp.ListRef = ?List{PROP:FEQ}
Resume(Start(WindowAsParam,,ThreadGrp))

I used Resume since I am calling a source procedure.

The called procedure looks like this:
WindowAsParam        PROCEDURE  (string pParams)           ! Declare Procedure
ThreadGrp		LIKE(ThreadGroupType)
WindowWidth		Long
MaxCols			Long

  CODE
	ThreadGrp    =  pParams
	WindowWidth  =  ThreadGrp.WindowRef{PROP:Width}
	MaxCols      =  ThreadGrp.WindowRef $ ThreadGrp.ListRef{PROPLIST:Exists,0}
	Trace('WindowAsParam')
	Trace('<9>WindowWidth['& WindowWidth &']')
	Trace('<9>ListMaxRows['& MaxCols &']')

The output to Debugview++ looks like this:

WindowAsParam
	WindowWidth[457]
	ListMaxRows[2]
4 Likes

Thank you for mentioning me :blush:

Congrats on taking the little information I mentioned about passing the window and FEQ and also the xWindow $ xFEQ {PROP:Yada} notation, and using that info to implement what you desired


I would make some very minor tweaks to what you posted:

I’d replace ThreadGrp.ListRef = ?List{PROP:FEQ}
with ThreadGrp.ListRef = ?List

Quite frankly I never saw the point of PROP:FEQ as you need it’s value to get it’s value.


I would replace

WindowAsParam        PROCEDURE  (string pParams)           ! Declare Procedure
ThreadGrp		LIKE(ThreadGroupType)
WindowWidth		Long
MaxCols			Long

  CODE
	ThreadGrp    =  pParams

with

WindowAsParam        PROCEDURE  (string pParams)           ! Declare Procedure
ThreadGrp		GROUP(ThreadGroupType),OVER(pParams)
                END
WindowWidth		Long,AUTO
MaxCols			LongAUTO

  CODE

Notice how the OVER eliminates the need for the assign ThreadGrp = pParams
Note: both approaches do rely on the correct string being passed, there is no strong typing here to help us.

If you weren’t planning on calling this directly as part of a START() (which requires all parameters to be STRINGS), then I would prototype as
WindowAsParam PROCEDURE(*Window xWindow, SIGNED xFEQ)


This is just a matter of style and convention, but personally I would rename
ListRef to ListFEQ or even just FEQ
where FEQ means Field EQuate , as we see in PROP:FEQ


I would consider renaming the group to say more about it’s contents
something like gtWinFEQ or WinFEQGroupType

Could check
IF SIZE(pParams) <> SIZE(ThreadGroupType) THEN STOP('Bug xxxx')
to have an idea that the parameter passed is not what was expected.

It’s cool that you’re learning new stuff and thinking outside the box, but the accessing of properties of controls across threads seems like it’s approaching the edge of thread instability. Maybe not with the properties you’re currently reading, but if you want to go a whole lot further you might want to try a different path.

This kind of stuff that you’re doing sounds like it could be a good candidate for a class using the Capesoft GUTS interface that can chat back and forth beween objects.

JAT

I completely understand.

I know of the risks involved with threads and you’re absolutely correct.

However, there’s only 2 or 3 list properties that need and it’s read only.

Yeah, GUTS is pretty cool.

Thank you everyone for your feedback!!!

See Help [ Property Access Syntax ]

My guess is that It’s most often used for Reports
as in Report$?SomeFEQ{PROP:Hide} = TRUE

1 Like

If you have multiple windows and/or reports open, this is how you specify which one you’re talking about.
Its use is almost the same as calling SETTARGET before setting/getting properties.

True. FWIW I prefer Target $ FEQ{PROP:Yada} over SETTARGET because

  • there’s no need to save/restore the current target
  • you can see the entire meaning in one line, vs. having read surrounding lines for context
    • which has the added benefit of helping when copying code

The amount of typing can vary, it’s less when using one or two property syntaxes, but at some point it becomes more typing

Sometimes you gotta use SETTARGET, especially if you use functions that receive FEQ, that don’t also have a WINDOW param.

A caveat to using these target related prefixes though:

You have to be careful with how you name your window/report variables, keeping in mind that a FEQ is simply a field number. Be cognizant of which FEQ belong to which window, or else you could be referring to the incorrect control.

1 Like

A way I use to Save and Restore the current Target using the lightly documented SYSTEM{PROP:Target}

WindowControlENum PROCEDURE(Window W)  !Can also take REPORT or APPLICATIOPN
SaveTarget &Window,AUTO  !Current Active Target
FEQ        LONG,AUTO
   CODE 
    SaveTarget &= SYSTEM{PROP:Target}   !Save Current Target
    SETTARGET(W)
    LOOP
       FEQ=0{PROP:NextField,FEQ}
       IF ~Feq THEN BREAK.
       !Debug info on FEQ
    END
    SETTARGET(SaveTarget)   !Restore Target
    RETURN

This is useful when wanting to work on a Window behind the currently active Window. E.g. you might use PROP:NextField to enumerate all the Controls.


For Reports in your embed code its ok to SETTARGET(Report) ; Feq{PROP:xxx}... ; SETTARGET(). I also tend to limit the scope of SetTarget() to one embed or a small range of lines.

I’m often moving things on the Report and find using PROP:XPos :YPos :Width :Height a bit verbose. I prefer to use GETPOSITION() and SETPOSITION() for 4x smaller code. They cannot use Report$ syntax so SetTarget() is required. It would be easy to create a Get/Set that passes REPORT so Report $ PROP’s can be used.

IMO its a bad idea to SETTARGET in Template inserted code as you may change a SETTARGET(Report) from the embed code. Another reason to follow Mark’s suggestion to use Report $ FEQ syntax. The reason I limit the scope of SetTarget() to one embed.

It’s important to know SETTARGET()with no parameter:

Resets TARGET to the topmost Window in the execution thread with the currently active ACCEPT loop.