Get label of USE variable of REPORT control at runtime

Tags: #<Tag:0x00007fc0dafa0ad0>

At runtime, I would like to iterate through the controls of a REPORT structure and do something with the controls. But I need a generic mechanism to identify the controls by name or label. Is there a way, without going to the template level, to retrieve the field names and/or local variables USEd by REPORT controls at runtime?

I have tried using Cla$FIELDNAME on Reports but it never worked for me. Even if I did a SetTarget(Report). Maybe someone else has the secret. When I look at the binary I see what appears to be the Report field names in the DABDUMP resource.

ClaFieldNameRTL PROCEDURE(LONG pFEQ),CSTRING,RAW,NAME('Cla$FIELDNAME'),DLL(dll_mode)

An approach that would work is to write a Template to iterate the %Report controls and place them in a Queue.

I wrote this “Report Test” that is a tiny project for testing Report code and PROP setting. You may find it useful for experimenting. It’s not an APP so cannot help with writing a template, to write the template I would make a similar very small APP that just had the Report.

Carl, to change some of those FONT attributes then are you having to look at recreating the report dynamically by iterating through the original report controls and CREATEing them onto a new report? I was going to suggest saving the properties of the report control and using DESTROY() on it and the CREATE(), but the online help doesn’t say that DESTROY() will work with REPORT structure / targets.

Rich,

I’m not sure the labels are available. (There’s no reason they should be.) Labels are used by the compiler, and typically discarded after that (although of course there are exceptions like for WHO usage and so on.)

If you wanted to append a property to each control then you’d probably use a template to do that. (well, you could do it by hand, but a template would be faster and easier.)

Perhaps you might like to expand on why you want the label?

Ain’t pretty, but you can use CLONE()

  MAP
      RptFieldName(LONG pFEQ, WINDOW pSourceTarget),STRING
  END

Usage: MyFieldName = RptFieldName(?MyControl,REPORT)

RptFieldName PROCEDURE(LONG pFEQ, WINDOW pSourceTarget)!,STRING

DummyWindow WINDOW,AT(-10,-10,1,1)
            END
FEQ         LONG            
ReturnVal   CSTRING(100)            
  CODE
  
  OPEN(DummyWindow)
  FEQ = CLONE(0,pFEQ,,,pSourceTarget)  
  ReturnVal = ClaFieldNameRTL(FEQ)
  CLOSE(DummyWindow)
  RETURN ReturnVal
2 Likes

Also, if you want to process a lot of FEQs, I’d probably pass a queue of FEQs to receive the results in between the OPEN/CLOSE. Or process the controls on the report and fill the queue within the function.

1 Like

Amazing Jeff! I built a test and it works great!

Now can you think of a way to get the FEQ Name (or Label) of HEADER DETAIL FOOTER and FORM that are not supported on a WINDOW ? Really just the DETAIL and BREAK since the others appear once max.

What I want to do is Reflection of the Report like I do for a Window in my Window Preview class so I can see a list of report controls and then view all the properties for each control.

The Control FEQ name is the most important so your code will make it work very. I can just name the DETAIL’s as ?Detail_1, _2, _3 etc. Usually there are 3 with a max of 10.

I’ll post back when I have more done. Thanks!

Yes, “reflecting” the controls of a REPORT structure is what I want to do, Bruce. Ultimately, I’d want to show the user information about the controls on a report band and let them re-arrange the controls, remove controls and add other controls to display data from the same table(s) as controls that we initially placed onto that report band in the REPORT designer.

I was trying to find a way to add information about a control (like the NAME() attribute does for a field in group) that could be read a runtime. The only thing I have found so far is the “EXTEND()” attribute on a report control, but I need to look more into what that does to the temporary page files. I know that pursing a template approach is probably the way to go. But, I’m going to see what Jeff’s ClaFieldNameRTL(FEQ) can do.

Jeff,
Is “ClaFieldNameRTL” only a Clarion 11.1 thing?
If not, where do I find it for C11?

Hi Rich - That was from Carl’s previous message. It’s a Clarion RTL function. Here’s the prototype:

ClaFieldNameRTL PROCEDURE(LONG pFEQ),CSTRING,RAW,NAME('Cla$FIELDNAME'),DLL(dll_mode)

Rich, it is undocumented but has been around and know about forever.

nice work Jeff - I have never used Clone()

one possibility:

  MAP
      RptFieldNames(stringTheory pSt, WINDOW pSourceTarget)
  END

Usage: RptFieldNames(st,REPORT)

where st has FEQ’s in a delimited list (any delimiter is OK eg. comma, space, pipe etc)
the fieldnames are returned in the ST lines queue.

!---------
RptFieldNames PROCEDURE(stringTheory pSt, WINDOW pSourceTarget)

DummyWindow WINDOW,AT(-10,-10,1,1)
            END
FEQ         LONG
x           LONG            

  CODE
  pSt.KeepChars('0123456789',' ')
  pSt.split(' ')
  pSt.removeLines()

  OPEN(DummyWindow)
  loop x = 1 to pSt.records()
    FEQ = CLONE(0,pSt.getLine(x),,,pSourceTarget)  
    pSt.SetLine(x,ClaFieldNameRTL(FEQ))
  end
  CLOSE(DummyWindow)

!----------

Use st.getLine(x) to get the field names from the lines queue

eg. for the name of the 5th FEQ: st.GetLine(5)

Could it be that having to CLONE a REPORT control before using the “Cla$FIELDNAME” function on it is similar to what happens with the {PROP:Use} and {PROP:UseAddress} properties of a control?

If you either CREATE or CLONE a report control at runtime, the value shown on the report is always the original value; it won’t pick up any changes in the USE variable unless you issue a PROP:Use or PROP:UseAddress everytime the variable’s value changes.

Thanks Geoff. I love ST, but not sure how that’s better than passing a queue. One field communicates the FEQ. Other field receives the label.

I think it’s just that the fieldname function just works on windows and not reports.

Thanks everybody for all the help on this.
That “Cla$FIELDNAME” function is pretty interesting, but just to clarify what it returns:
It returns the upper-cased version of the specifically entered EQUATE from the USE attribute or the calculated EQUATE if you did not enter a specific equate. For example, given this REPORT structure control:
STRING(@s20),AT(167,156),USE(MyString1,?Equate01)
The Cla$FIELDNAME function, when used like Jeff discussed above, will return:
?EQUATE01

I have also found the FieldName() function always returns UPPER text. I think it was UpLow back in C5 or C6.

I hacked my Control Property Viewer to look at a Report STRING and see all of its PROPs which show below in below capture. It is interesting the PROP:Use returns the Value 12345.67 I put in STUB:Amt, that also appears in 7C8Ah which is not in Property.CLW. Maybe you could use PROP:UseAddress

That looks small to me, here it is in parts:

Somewhere on the ngs I posted an example of using the tufo.address() to get the actual address from prop:useaddress.

Not at my personal development machine atm.

yes fair enough Jeff.

Probably not a big deal in this case but I was thinking that it saves you having to define and pass a queue. ST has a built-in queue mainly used for splitting but it can be handy for other things as well. And the strings in a ST lines queue are not of an arbitary predefined size - they can be as big (well within the limits of 32 bit available memory) or small as needed. IOW flexible.

Again in this case your field labels are probably not going to be more than 50 chars so you might choose that or 100 chars or whatever. Or you could use an ANY or have a pointer to an allocated string (as ST does) - but these have pitfalls like potential memory leaks waiting to trap the unwary and (heaven forbid!) you have to write code. The code with the fewest bugs is the code you don’t write. (Admittedly that assumes the underlying technology is sound.)

Anyway it just seems prudent to avoid those potential bugs and use something simple, fast and solid.

But again in this case probably not an issue as you might just use STRING(100) or whatever for the name label. And besides, Jeff, you are not one of those “unwary travellers” likely to make a mistake anyway!

cheers / season’s greetings / happy holidays!