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 Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

this.addgroup() 1

Status
Not open for further replies.

Rick C. Hodgin

Programmer
Oct 15, 2021
172
US
Concept:

Code:
* For any container object:
lo = this.AddGroup("input", this.txtDate, this.txtDesc, this.txtQty, this.txtAmt)

* Access as the returned object
lo.BackColor = RGB(255,255,128)
WAIT WINDOW "Pausing..."

* Or as the object off its parent, by name
this.input.BackColor = RGB(255,255,128)

It would not error when properties which do not exist on the group objects are attempted to be set. It would just skip that object.

It the "this.input.BackColor = RGB(255,255,128)" line would effectively do the equivalent of:

Code:
* The objects that would've been in the input group, it works on each one individually
this.txtDate.BackColor = RGB(255,255,128)
this.txtDesc.BackColor = RGB(255,255,128)
this.txtQty.BackColor  = RGB(255,255,128)
this.txtAmt.BackColor  = RGB(255,255,128)

--
Rick C. Hodgin
 
So are you saying that txtDate, txtDesc, etc. already exist as objects within the container? And your new "input" object would provide a way of accessing their PEMs all at once? For properties, you could do something vaguely similar with SetAll(). But your method would allow you to do that for any arbitrary objects in the container, not necessarily of the same class.

And are you creating "input" as a new container, which then inserts itself in the containership hierarchy between the outer container and the txtDate, etc?

Or have I completely misunderstood (which would be no surprise)?

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Rick,

I think you wanted to post this as answer/continuation to an already closed thread, but started a new one instead.
Maybe the one where I suggested using This_Access to automatically add properties?

Is the concept to add the properties txtDate, txtDesc, txtQty, txtAmt and instead of adding them to THIS directly, to create a property "input" which has these four txt properties?
Like the concept I know from VB for some properties like Font, where VB has a Font object with properties Name, Size, etc. while VFP has several properties FontName, FontSize etc. and thus keeps a flat property structure with several property names starting with "Font" to "group" them instead of having a hierarchical structure.

This could help designing a hierarchy faster and I can still imagine you could also do this by hand with the help of Addproperty. Just first create such an object and then add it as property "input".

I once briefly worked with a framework that did use something you can now create with SCATTER NAME, and then offered to use such an object to pass as one parameter having multiple properties, to bind controls to the object properties or to pass a "record object" even to another form, not only within the same ddata session. It was called record or parameter object. And it had a form class that would store the passed in object to a form property and either - in modal mode returns it in Unload and/or you simply get those changed values back as the caller since you created this object and kept it in scope, so you still have the modified properties in this object and at any time could access them in the calling form, too, not just in the called form. So this parameter is an inout parameter.

Given, of course, that you don't use a local variable to create and pas the object and let it go out of scope. That's an option, too, as the called form keeps it's own object reference in its Init(), but as caller you then could only access the changed object when it's returned in Unload. Or you don't care for the changes. A bit like the difference of calling something as a procedure - that does something with the passed in value(s) instead of a function, that also returns a result (by using the nature of the passed in object as reference, ie as inout parameter).



Chriss
 
Mike Lewis said:
So are you saying that txtDate, txtDesc, etc. already exist as objects within the container? And your new "input" object would provide a way of accessing their PEMs all at once?

Yes. The group would be created as a first-class class member, like a POEM. It would allow multiple groupings to be created and referenced as an object, allowing the operation specified to be conducted on each one in turn.

--
Rick C. Hodgin
 
Chris Miller said:
I think you wanted to post this as answer/continuation to an already closed thread, but started a new one instead. Maybe the one where I suggested using This_Access to automatically add properties?

Nope. I had this come up yesterday. A user had a form with old values on the left, new values on the right, and they are supposed to change at least one to save the record. So, to highlight the fields they need to change on the condition when they click save and nothing has changed, I had to do:

Code:
WITH thisForm.pageframe.page2
    .txtField1.BackColor = RGB(255,255,128)
    .txtField2.BackColor = RGB(255,255,128)
    .txtField3.BackColor = RGB(255,255,128)
    .txtField4.BackColor = RGB(255,255,128)

    MESSAGEBOX("Oops, no good.  Fix it!")

    .txtField1.BackColor = RGB(255,255,255)
    .txtField2.BackColor = RGB(255,255,255)
    .txtField3.BackColor = RGB(255,255,255)
    .txtField4.BackColor = RGB(255,255,255)
ENDWITH

And I was thinking it would be nice to have this instead:

Code:
* Init()
WITH thisForm.pageframe.page2
    thisForm.AddGroup("input", .txtField1, .txtField2, .txtField3, .txtField4)
ENDWITH

* On the save code:
thisForm.input.BackColor = RGB(255,255,128)

MESSAGEBOX("Oops, no good.  Fix it!")

thisForm.input.BackColor = RGB(255,255,255)

I think I'll add this to Visual FreePro, so if I ever get a chance to get it finished it will be there waiting for me.

--
Rick C. Hodgin
 
SetAll() has the option of a class, which is kind of like an IIF() on which ones to set. However, if you have a case where there are multiple of a particular class but only some of them need to be highlighted, the grouping is required. Another option might be to include an IIF() component as the 4th parameter expression:

Code:
this.SetAllIf("BackColor", RGB(255,255,128), NULL, "input" $ comment)
this.SetAllIf("BackColor", RGB(255,255,128), NULL, lInput)
this.SetAllIf("BackColor", RGB(255,255,128), NULL, value = c.value)

In this example, if you added the keyword "input" to each object's comment, or if it had the member lInput and it was set to .t., or if the txtBox.value equaled the related control's txtbox.value, then it would be impacted.

I think AddGroup() / DeleteGroup() would have more utility.

--
Rick C. Hodgin
 
Yes, the class also only works for that exact class, not the class and all subclasses of the class.

There's another technique to group several controls with their reference in arrays and collections. I think Mike and Toni Feltman have a good session with ideas using these in ways usually not thought of.

But I see why you think in this direction, it could make sense in several situations, not only validating inputs.

If I generalize this even more I think it's a case for the mediator pattern a mediator mediates between input/data validation on one side and controls on the other side. To abstract the whole process to a usage of the validation telling the mediator which fields have wrong/incomplete/contradiction data and the mediator knowing which controls are responsible for these fields and knows what to do to these controls, ie. setting their background color or setting a red border. And that could also be driven one step further by the mediator only sending the "message" to the controls, that they should set themselves to the state of "wrong input", for example by setting a common property "invalid" to .T. and then act in each individual control in its invalid_assign method.

Which means combining the subscribe/publish pattern with the mediator pattern.


Chriss
 
I think we're evolving into a new Group class, which is like a collection, but is designed explicitly to hold controls and interact with their properties, events, and methods, in a controlled and known way, so that unnecessary errors don't occur.

Would be an interesting addition.

--
Rick C. Hodgin
 
What would be another purpose for it? We can already store generic objects in Collections, or to create an Empty class and add them in various forms.

I'm still thinking this.AddGroup("name", ...), this.DeleteGroup("name"), and also CREATEOBJECT("name", "group", ...), though maybe CREATEGROUP("name", ...) would make more sense.

--
Rick C. Hodgin
 
I just said it's not limited to controls because any object has properties that you could wish to set for some group of them.

A concrete example, let's see...

Sending mails to groups of addressees (mail merge), triggering any action in a group of anything.

I don't know where exactly I'd have a literal usage of creategroup. Well, at least not in the sense of creating a bunch of checkboxes or buttons or any controls, the power of a group as you defined it is to be inhomogenous or heterogenous in their composition, just all having similar interface to make use of via a mediator. In that sense I'd expect CreateGroup() to not only shorten several CreateObject()s to one, but also create a parent mediator object "caring" (mediating) between the group members or between the group and any outside object.



Chriss
 
Rick said:
A user had a form with old values on the left, new values on the right, and they are supposed to change at least one to save the record. So, to highlight the fields they need to change on the condition when they click save and nothing has changed, I had to do:

Another option might be to add a logical flag, as a custom property, to the base textbox class. Set it to .T. for those controls that need to be highlighted. Then loop though the controls collection on the form, looking for those that have the flag set.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Good observation, Mike, I didn't thought about it that way, but I assume the Interactivechange event writes "input" to the comment property.

So you'd actually look whether any control on the right side has input in the comment and then it's okay or none has input and then all need to be highlighted? The logic might differ a bit. I think the Foxpro included application framework that uses an edit mode also has a "changed" property that's set to .t. whenever any control value was modified. You don't really catch the corner case of a modifcation done and then cancelled, but that way you just need to check a global property, not any single control. The condition of modifying something isn't really about the controls, is it, it's about the data. It could also be detected by no change of a checksum value, which then covers the case of a manually cancelled modification (like Space + Backspace).

Rick, is it perhaps, that you display oldval and curval of a record after save caused a conflict and the user is asked to decide what to finally save? I think not, because in that case the decision could be for one of the record states, left or right, unchanged, so either keep another users edit or override with your own. It's not necessarily best to take in all changes in comparison to the original oldvals. Like the case there are three persons

Jesse James, James Dean, and Dean Martin
the data has
Jesse Dean, James Martin, and Dean James

one user changes Jesse Dean to Jesse James.
the other user has loaded the original wrong data and edits Jesse Dean to James Dean.

Merging both changes which are actually not colliding because one change is modifying Lastname of person1, the other change is modifying Firstname of person1, but you'd end up with James James.

Chriss

PS: It's a very constructed case, but it can be quite a real pain with fields that are boolean or choosen from a short picklist so an overlap and switch like this can easily happen, seems technically collilsion free and mergable but overall still is a wrong data state.
 
Mike Lewis said:
Another option might be to add a logical flag, as a custom property, to the base textbox class. Set it to .T. for those controls that need to be highlighted. Then loop though the controls collection on the form, looking for those that have the flag set.

I have done that very thing in the past, though I often use keywords in the comment and do a $ found in to see if that's one. I do this for "sticky" controls which save and restore their values between form / process instances.

It gets more tricky with container objects and hierarchies. It's doable, but groups would be better. They're just like a macro or shorthand notation for multiple ops.

--
Rick C. Hodgin
 
Chris Miller said:
Rick, is it perhaps, that you display oldval and curval of a record after save caused a conflict and the user is asked to decide what to finally save?

In this particular case, it was an inventory item. The old supplier item is being updated with a new supplier. On the edit form it has old info on the left, new info on the right.

The business logic says in order to save the new item, something has to have changed in key fields. And those fields are highlighted when the user fails to change them, so as to give a visual cue.

These records are all on the same page in the pageframe, but I can see use cases for things that are not, and even not on the same form.

Oh to dream.

--
Rick C. Hodgin
 
Rick,

I think I begin to understand what you're after. Pardon for hijacking the idea and making something overcomplicated of it. Taking your description of a collection with added features like shared properties or internal knowledge about all group members. I think it's then up to a developer to make use of it in some way or another. Just like I think MS VFP developers didn't think of using assign methods as a way to have a messaging system and only thought of the major intent to implement getter/setter in a kind of reverse fashion were the usual simple getter/setter is the default and you only implement something like validation and accepting or rejecting assigned values, not as something that a SetAll can trigger for all controls inside a hierarchy and react individually.

Chriss
 
Rick,

I love this idea, and while I am Not sure if accessing a property in this case should skip the line or maybe even create that as a new property where it doesn't exist (maybe have an app setting for that - and allow 3rd option of giving an error), I have been following your Visual FreePro project for quite some time now.

Unfortunately, as of a couple months ago, your latest dedicated URL(s) for Visual FreePro were quite outdated / Not updated in at least 2 or 3 years, and now when I check, there aren't any dedicated URLs for it whatsoever (at least from what I can find on Google).
-- So might you get one of your previous Visual FreePro dedicated URLs back up and running (or else new URL running) with prominently displayed updated date thru current day or at least per the last most recent date you have actually worked on or made any updates for it?

Lastly, for any other Visual FreePro functionality input, if or where possible, please include me via my email address (4444DR@GMail.com).

Thanks,

Dan Ross
 
Hi Dan. I have emailed you some Visual FreePro info.

Thank you for following my project. It's broken my heart it never got completed. I tried every way I knew to drum up interest and get people to help me. It just wasn't meant to be.

--
Rick C. Hodgin
 
Dan,

I strongly advise you to edit your last post, to remove your email address. Posting email addresses is not only against forum rules, it can - and probably will - result in your receiving a big increase in spam.

If it is too late for you to edit your post, I will ask the forum management to do it for youi.

The email address is the only problem. The rest of your post is fine.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Like many other people, I would occasionally like to communicate (politely) with other members of the forum.

I appreciate that you publish your contact email on your website - and I am grateful for the support you have provided. But how do those of us who who do not have a website manage this.

sincerely - Andrew

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top