Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Macro's 1

Status
Not open for further replies.

D-Ward

IS-IT--Management
Sep 6, 2022
32
GB
Happy New Year to all

I am creating different sets of dynamic shape objects on an image in a container, firstly a load of squares that represent physical objects on a floor plan drawing. I then create a load of line objects (which are really shapes, that messed with me for a bit) that link some of the squares to show that they are in a group. When the line is created the TAG property is set to the 'sequential' part of the shape name when it was created.

I can get all this working but it is really ugly code and am sure there is a more elegant, easier way to manage the code. What I want to do is something like;

FOR ox = thisform.CONTAINER.ConrtrolCount TO 1 STEP -1
IF LEFT(thisform.CONTAINER.Objects(ox).Name, 7) = "LINE"
_Macro = "WITH thisform.Container.SHAPE" + thisform.CONTAINER.Objects(ox).Tag
&Macro
thisform.CONTAINER.Objects(ox).Left = .Left + (.Width / 2)
thisform.CONTAINER.Objects(ox).Top = .Top + (.Height / 2)
ENDIF
NEXT

It doesn't like the &Macro command as throw a 'WITH/ENDWITH mismatch' error, so guess you can not use a Macro to instigate a WITH, FOR, SCAN or other such command.

I have done similar projects in the past in other languages, but you were able to create object as arrays thisform.SHAPE(1) so it was easier to reference them using an integer for the array name, but as I have to build the sequential identifier into the object name it make things a little different.

I'm not sure if the above makes sense, but would appreciate any ideas how to best handle this.

Regards,

Darren





 
One little aspect. You may have expected collections to solve the problem to need macros at all. Well, you still have to create controls on the form first and they have to have unique names, so you do still typically do create names like you do with cName = "lneGroup" + ALLTRIM(STR(dnPGroups.NodeID)), a base name and a number from some ID or just a sequence.

And then you know the name used in AddObject or Newobject, but need to get the reference with a maro like cComm = "thisform.conArea." + cName.

There are two alternatives to that. So instead of setting CCOMM = "thisform.conArea." + CNAME and then use the macro substitution &CCOMM, you can use...

1. ...GETPEM():
Code:
o = GETPEM(thisform.conArea,CNAME)

2. ...Evaluate:
Code:
o = Evaluate("thisform.conArea." + CNAME)

Both are not needing the line compilation a macro substitution means. So that's removing the need for macro, too. The collection is just organizing your controls in groups easy to iterate. Notice I used CNODEID as a key when adding a line object, that key must be a string type value, so that needs the conversion of integer ids to string, but that's not as bad as a macro. The key makes it easy to get at one very specific collection item, just like a primary key of a table makes it easy to access the record with a specific key. And I used that in the line With .colLines.Item(CNODEID).

The improvement that can be made in my code is to use GETPEM instead of macro substitution:
Code:
.colLines.Add([s]&CCOMM[/s][highlight #FCE94F]GETPEM(thisform.conArea,CNAME)[/highlight],CNODEID) && adding the line object reference to the collection

It's not something that you'll notice in performance difference with just 10 or even 100 lines. But it's good to know there are also alternatives to macro usage when you know the name of an object only, but can reference the parent object. You could also use that recursive, if you only know the complete object name path (for example, that could be form->pageframe->page->container->object) and the only actual parent object you have at hand is THISFORM. Then you need a GETPEM per nesting level. But typically you will have a reference to the level you're using to add objects at runtime, as you use its .AddObject() or .NewObject() method, so a single GETPEM usually is enough.

And before the discussion comes up that EVAL is evil: The only aspect that could inject something evil is if user input is involved. In your case, the nodeid of a record is involved. And that is a number, no chance to be evil code. Not any data source is harmless, though. User input can also be user input from the past, like something stored into a memo for a description. GETPEM has the advantage that you don't need to care for such possible harm. Assume that CNAME contains evil code, GETPEM won't just find a member of that name. That's a reason to prefer GETPEM over EVAL.

Chriss
 
Good point Chris
Not all the people knows that EXECSCRIPT() is an implicit EVAL().

Or in other words, no one ever posted... EXECSCRIPT() is evil

okarl
 
Well,

the evilness always has to do with not using it safely. And therefore it's still part of the language. And not only in VFP. In the end, as I said in my thread about using a COM server for parallel processing, it's all about trust. If you have something that could execute any user input that is a security gap. If you pay attention about that, you can also use EVAL or EXECSCRIPT. The point about when and how to use it is often not discussed at all, because it's called evil and therefore it's considered to be strictly avoided. There's good reason to use it, I always wonder how macro substitutions never are discussed that way, because they are also a string that in theory in some wild construct could be user input you then could execute. But everybody uses it anyway. Well, in the same situation in which you feel safe about macro substitution when you're under full control of what you substitute you can also evaluate or execute it. Otherwise, you will also need to remove macro substitution from your toolset, as it's even mightier than eval().

Some people then like to come up with touring tests and how you never can be sure about anything, but that's an exaggeration of what this lesson has to teach. You can write perfectly good code that's provable to only do what you intend it to do and can't be misused. Just because not all code can be proven to work, that's not telling you never can prove anything to be working or safe against injections.

I always like to compare it that way: If I sell you a kitchen knife I am not legally bound to also force a police officer upon you watching out in a 24/7 duty you only use that knife for what it's intended. And I'm not even talking about guns.

Chriss
 
Hahahah Rear Window , an excellent movie Alfred Hitchcock / Grace Kelly / James Stewart.

You are suspected to have a knife in your house !!
In real life accusations should be based on facts/evidences , not suspicions, otherwise they would skip the law of presumption of innocence and attacks against honor, which is more illegal than having a knife in your kitchen hahahaha

okarl
 
Tamar,

Sincere apologies, I have a feeling I read some of your articles in Code Magazine some time ago, so have no excuses. I live in the South West of the UK, and used to drive over the Tamar River on a daily basis, no real relevance but an interesting fact maybe, if you were not aware of it's existence.

Chris, thank you for your generous posts over the weekend, will go through them.

Happy Monday all,

Darren
 
I think I had one or two pieces in Code Magazine, but my main publishing venues were FoxPro Advisor and then FoxRockX.

As for the Tamar River, yes, I'm aware of it and I believe it's pronounced rather differently than my name. It's like TAY-mar, right? I'm tuh-MAR, which is closer to the Hebrew pronunciation.

Tamar
 
Hi Tarmar,

You are correct, it is pronounced Tay-mar. Had not heard of FoxRockX, but Googled it and see that it is what FoxTalk became, just looked in an old filing cabinet here and found some copied of FoxTalk 2.0 which I think date back to 2005 when I attended the DevUK.

Have also just found a link to VFPX and geekgatherings videos on YouTube of the recent FoxFest, so will work my way through them as well.

Am implementing the collections today from Chris' code example and looking further into moving the data handling into the business classes.

Regards,

Darren
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top