[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.vb.general.discussion

Working With Parent Controls

Rick Raisley

9/3/2011 4:58:00 PM

I have a bunch of controls to enable/disable and make other changes
to, and need to Refresh the parent controls to them when I'm done. I
want to avoid refreshing multiple times, or refreshing if not
necessary, so thought I could keep track of the Parent controls, then
run a routine to refresh them. I've got something like this:

'This keeps track of all the Parents that need updating
Global Parents(50), NumParents As Integer

'This is the routine called to enable/disable each control, and keep
track of parents
Sub SetEnabled(ByVal Ctrl as Control, ByVal Enab as Integer)
If Ctrl.Enabled <> Enab Then
Ctrl.Enabled = Enab
NumParents = NumParents +1
Parents(NumParents) = Ctrl.Parent ' <== This is the area
there's a problem with.
End If
End Sub

'This routine is intended to Refresh only parents found above to need
so:
Sub RefreshParents()
Dim x as Integer
For x = 1 To NumParents
Parents(x).Refresh
Next x
NumParents = 0
End Sub

I also intend to add code to include each parent in the list only
once. Anyhow, it's the line above:

Parents(NumParents) = Ctrl.Parent

that errs out, with Run-time error 91, Object variable or With block
variable not set. I'm probably not working with the control "names"
correctly.

Can someone point out my error, or give a suggestion?

Thanks!
45 Answers

MikeD

9/4/2011 1:31:00 AM

0



<rraisley@bellsouth.net> wrote in message
news:67ee1b99-cbcb-4e91-a127-06f41f79e9bb@g31g2000yqh.googlegroups.com...
> I have a bunch of controls to enable/disable and make other changes
> to, and need to Refresh the parent controls to them when I'm done. I
> want to avoid refreshing multiple times, or refreshing if not
> necessary, so thought I could keep track of the Parent controls, then
> run a routine to refresh them. I've got something like this:
>
> 'This keeps track of all the Parents that need updating
> Global Parents(50), NumParents As Integer
>
> 'This is the routine called to enable/disable each control, and keep
> track of parents
> Sub SetEnabled(ByVal Ctrl as Control, ByVal Enab as Integer)
> If Ctrl.Enabled <> Enab Then
> Ctrl.Enabled = Enab
> NumParents = NumParents +1
> Parents(NumParents) = Ctrl.Parent ' <== This is the area
> there's a problem with.
> End If
> End Sub
>
> 'This routine is intended to Refresh only parents found above to need
> so:
> Sub RefreshParents()
> Dim x as Integer
> For x = 1 To NumParents
> Parents(x).Refresh
> Next x
> NumParents = 0
> End Sub
>
> I also intend to add code to include each parent in the list only
> once. Anyhow, it's the line above:
>
> Parents(NumParents) = Ctrl.Parent
>
> that errs out, with Run-time error 91, Object variable or With block
> variable not set. I'm probably not working with the control "names"
> correctly.
>
> Can someone point out my error, or give a suggestion?

Just a guess without having looked at your code in more depth (i.e. actually
trying it), but you probably want the control's container, NOT it's parent.
So, try the Container property. Also, you're dealing with objects, you need
to use the Set keyword (I am assuming this is VB6 as I didn't see anything
obvious that stood out as .NET code).

Also, you might want your Parents() array to be declared As Object and your
Enab parameter should probably be a Boolean.

--
Mike




Rick Raisley

9/6/2011 12:31:00 AM

0

>
> Just a guess without having looked at your code in more depth (i.e. actually
> trying it), but you probably want the control's container, NOT it's parent.
> So, try the Container property.  Also, you're dealing with objects, you need
> to use the Set keyword (I am assuming this is VB6 as I didn't see anything
> obvious that stood out as .NET code).
>

I now dimension the array as Object, rather than As Control, as
suggested. I think you're right about using Container, not Parent. I
can read the control's name with:

Ctrl.Container.Name

But when I try to set the Parent array to it:

Parents(NumParents) = Ctrl.Container.Name

I still get the same error message. I'm using VB6, but have always
been confused about when I have to use Set, and where and how. How
would I do that in the above?

> Also, you might want your Parents() array to be declared As Object and your
> Enab parameter should probably be a Boolean.
>

I think either would work, but yeah, it should probably be Boolean.

MikeD

9/6/2011 1:09:00 AM

0



<rraisley@bellsouth.net> wrote in message
news:ae2ec5d6-a8fa-4815-af45-12bdea15c00b@l4g2000vbz.googlegroups.com...
>>
>> Just a guess without having looked at your code in more depth (i.e.
>> actually
>> trying it), but you probably want the control's container, NOT it's
>> parent.
>> So, try the Container property. Also, you're dealing with objects, you
>> need
>> to use the Set keyword (I am assuming this is VB6 as I didn't see
>> anything
>> obvious that stood out as .NET code).
>>
>
> I now dimension the array as Object, rather than As Control, as
> suggested. I think you're right about using Container, not Parent. I
> can read the control's name with:
>
> Ctrl.Container.Name
>
> But when I try to set the Parent array to it:
>
> Parents(NumParents) = Ctrl.Container.Name
>
> I still get the same error message. I'm using VB6, but have always
> been confused about when I have to use Set, and where and how. How
> would I do that in the above?
>

You've still got a problem because you're trying to assign a string to an
object variable. If you want the container name assigned to your Parents
array, then that array should be declared As String. Otherwise, you need to
do this to assign an object reference:

Set Parents(NumParents) = Ctrl.Container

It's very simple in regards as to when you need to use the Set keyword. You
must use Set if you're assigning a reference to an object. If you DON'T use
Set, then what you're actually doing is assigning a value to the object's
default property (assuming it has one).

--
Mike


Bob Butler

9/6/2011 1:16:00 AM

0

<rraisley@bellsouth.net> wrote in message
news:ae2ec5d6-a8fa-4815-af45-12bdea15c00b@l4g2000vbz.googlegroups.com...
>>
>> Just a guess without having looked at your code in more depth (i.e.
>> actually
>> trying it), but you probably want the control's container, NOT it's
>> parent.
>> So, try the Container property. Also, you're dealing with objects, you
>> need
>> to use the Set keyword (I am assuming this is VB6 as I didn't see
>> anything
>> obvious that stood out as .NET code).
>>
>
>I now dimension the array as Object, rather than As Control, as
>suggested. I think you're right about using Container, not Parent. I
>can read the control's name with:
>
>Ctrl.Container.Name
>
>But when I try to set the Parent array to it:
>
>Parents(NumParents) = Ctrl.Container.Name
>
>I still get the same error message. I'm using VB6, but have always
>been confused about when I have to use Set, and where and how. How
>would I do that in the above?

Ctrl.Container is an object reference
Ctrl.Container.Name is a string

If Parents() is declared "As Object" or "As Control" then you need to store
the object reference:
Set Parents(NumParents)=Ctrl.Container ' use "set" to handle an object
reference

If Parents() is declared "As String" then you can place the Name property
values there:
Parents(NumParents)=Ctrl.Container.Name ' no "set" for simple types like
string

If you use the former you may need to Erase the array or loop through it and
"Set Parents(x)=Nothing" to release each copy of the object reference so
that your app can terminate cleanly. That may not be needed depending on
the structure of the app. I would probably do it anyway just for
completeness. While you have the array you can get the names using
"Parents(x).Name" since with the object reference you can access any
available property of the object.

If you use the latter you can get the object reference from the name using
"<form>.Controls(Parents(x))" or "Me.Controls(Parents(x))" from code inside
the form. If any of the controls are part of a control array that gets
trickier since you'd need to store the index as well.


Rick Raisley

9/6/2011 1:49:00 AM

0

Thanks, Bob and Mike! That worked great. Yep, using Set when I assign
the object prevents the error. I can use .Name to see if the container
is already in the list to be refreshed, and as suggested, set each
item of the array = Nothing after doing the refresh.

One other quick question: I notice the name of the control does not
include the form name, and these routines are run from a BAS module,
and can be updating several different forms. Does the Parents array
keep track of the form name, I presume, as well, so it knows exactly
what to update? I haven't yet made the routine work across multiple
forms, but that was my intent, and I just wanted to be sure it
shouldn't be a problem.

Thanks again! I haven't been active in these forums since I retired a
year and a half ago, but I see that many of the same people are just
as helpful as always. ;-)

Bob Butler

9/6/2011 3:15:00 AM

0


<rraisley@bellsouth.net> wrote in message
news:cc9dff4b-187a-42de-b71d-0b5033076029@h9g2000vbr.googlegroups.com...
> Thanks, Bob and Mike! That worked great. Yep, using Set when I assign
> the object prevents the error. I can use .Name to see if the container
> is already in the list to be refreshed, and as suggested, set each
> item of the array = Nothing after doing the refresh.
>
> One other quick question: I notice the name of the control does not
> include the form name, and these routines are run from a BAS module,
> and can be updating several different forms. Does the Parents array
> keep track of the form name,

If the Parents array has a reference to the control then
Parents(controlname).Parent
should be the form; if you find cases where the control's parent is not the
form then you'd have to walk backwards up the Parents to find it

Public Function GetFormFor(ByVal TheControl As Control) As Form
Dim oForm As Form
Dim oParent As Object
Set oParent = TheControl.Parent
Do Until (oParent Is Nothing) Or Not (oForm Is Nothing)
If TypeOf oParent Is Form Then
Set oForm = oParent
Else
Set oParent = oParent.Parent
End If
Loop
Set GetFormFor = oForm
Set oParent = Nothing
Set oForm = Nothing
End Function


ralph

9/6/2011 4:43:00 AM

0

On Mon, 5 Sep 2011 18:48:57 -0700 (PDT), rraisley@bellsouth.net wrote:

>Thanks, Bob and Mike! That worked great. Yep, using Set when I assign
>the object prevents the error. I can use .Name to see if the container
>is already in the list to be refreshed, and as suggested, set each
>item of the array = Nothing after doing the refresh.
>

To amplify on Bob's always sage response - another reason (if not the
primarily one) for VB using the "Set" keyword for object assignments
is because VB provided Default Properties for its objects. A
convenient 'feature' to save some typing ...

Dim s As String
s = Text1.Text ' .Text a the default property
' or
s = Text1 ' Wee! I don't have to type .Text
Text1 = "This is text in Text1"
Text2 = Text1 ' both now show the same text

But trouble brews when you attempt to assign a control ...

Dim txtNew As New TextBox
txtNew = Text1 ' assigns the text
Set txtNew = Text1 ' assigns the control

Experience has demonstrated that default properties can be a problem.
Best practice is to always provide a complete reference. Many
developers believe that if VB5/6 had just banned 'default properties'
life would have been better - even though it would have broken all the
code before and most, if not all, the "Beginning VB" sample code ever
written. <g>

However, I'm one of the few that am glad they didn't. ...
<Wait! ... Ok, it's good. Bob has gone to bed by now and won't read
this.>

Because it means we can still write our own collection objects that
support the Dictionary Lookup operator (the Bang '!' operator).

To define your own default properties ...
Drop the Tools menu
Select "Procedure Attributes"
In the Name box select the property you want to make the default
Click "Advance"
Select "User Interface Default"

Enjoy. <just don't let Bob catch you doing it>

-ralph

Bob Butler

9/6/2011 5:34:00 AM

0


"ralph" <nt_consulting64@yahoo.net> wrote in message
news:6b8b67lje5c9u9fbocp9esdnrk355sgsf7@4ax.com...
> On Mon, 5 Sep 2011 18:48:57 -0700 (PDT), rraisley@bellsouth.net wrote:
>
>>Thanks, Bob and Mike! That worked great. Yep, using Set when I assign
>>the object prevents the error. I can use .Name to see if the container
>>is already in the list to be refreshed, and as suggested, set each
>>item of the array = Nothing after doing the refresh.
>>
>
> To amplify on Bob's always sage response

thanks, the royalty check is in the mail

> - another reason (if not the
> primarily one) for VB using the "Set" keyword for object assignments
> is because VB provided Default Properties for its objects. A
> convenient 'feature' to save some typing ...
>
> Dim s As String
> s = Text1.Text ' .Text a the default property
> ' or
> s = Text1 ' Wee! I don't have to type .Text
> Text1 = "This is text in Text1"
> Text2 = Text1 ' both now show the same text
>
> But trouble brews when you attempt to assign a control ...
>
> Dim txtNew As New TextBox
> txtNew = Text1 ' assigns the text
> Set txtNew = Text1 ' assigns the control
>
> Experience has demonstrated that default properties can be a problem.
> Best practice is to always provide a complete reference. Many
> developers believe that if VB5/6 had just banned 'default properties'
> life would have been better - even though it would have broken all the
> code before and most, if not all, the "Beginning VB" sample code ever
> written. <g>
>
> However, I'm one of the few that am glad they didn't. ...
> <Wait! ... Ok, it's good. Bob has gone to bed by now and won't read
> this.>

No, he hasn't! He should have but he's been trying to wrap what's left of
his brain around Objective C and about ready to scream or cry so he came
back to VB for a few minutes of relief and here you go and hit me with this.
<g>

What I would have liked is a real VB7 with "Option Strict" which would have
banned default properties as well as many implicit conversions and required
all arrays to be dimmed with "To" and required ByVal/Byref be specified on
all parameters and...

Even if they had removed default properties old code could be made to run by
filling them in and new code would be backwards compatible since you could
always specify. It would have been an annoyance but manageable.

> Because it means we can still write our own collection objects that
> support the Dictionary Lookup operator (the Bang '!' operator).

Now you've crossed the line! <g>

> To define your own default properties ...
> Drop the Tools menu
> Select "Procedure Attributes"
> In the Name box select the property you want to make the default
> Click "Advance"
> Select "User Interface Default"
>
> Enjoy. <just don't let Bob catch you doing it>

I have no issue with making a property the default; it's consistent with a
long history of components out there and has its place. I do hate the !
syntax because it's just a way to confuse people by hiding the details of
what you are doing. Code should be explicit, or at least reasonably so.
The ! just hides too much for my taste.

for example, ! on the recordset applies 3 defaults:

rs!name = "x" 'too short to be self-documenting
rs.fields.item("name").value ' too cumbersome
rs.fields("name").value ' best IMO - 1 default
rs("name").value ' f you're a lazy typist

YMMVAPD (and probably does)




ralph

9/6/2011 5:47:00 PM

0

On Mon, 5 Sep 2011 22:34:19 -0700, "Bob Butler"
<bob_butler@cox.invalid> wrote:


>
>What I would have liked is a real VB7 with "Option Strict" which would have
>banned default properties as well as many implicit conversions and required
>all arrays to be dimmed with "To" and required ByVal/Byref be specified on
>all parameters and...
>
>Even if they had removed default properties old code could be made to run by
>filling them in and new code would be backwards compatible since you could
>always specify. It would have been an annoyance but manageable.
>

I agree.

My VB7 would also have included a more complete suite of collections
as well (vectors, list, map, dictionary, ...).

>> Because it means we can still write our own collection objects that
>> support the Dictionary Lookup operator (the Bang '!' operator).
>
>Now you've crossed the line! <g>
>
>> To define your own default properties ...
>> Drop the Tools menu
>> Select "Procedure Attributes"
>> In the Name box select the property you want to make the default
>> Click "Advance"
>> Select "User Interface Default"
>>
>> Enjoy. <just don't let Bob catch you doing it>
>
>I have no issue with making a property the default; it's consistent with a
>long history of components out there and has its place. I do hate the !
>syntax because it's just a way to confuse people by hiding the details of
>what you are doing. Code should be explicit, or at least reasonably so.
>The ! just hides too much for my taste.
>
>for example, ! on the recordset applies 3 defaults:
>
>rs!name = "x" 'too short to be self-documenting
>rs.fields.item("name").value ' too cumbersome
>rs.fields("name").value ' best IMO - 1 default
>rs("name").value ' f you're a lazy typist
>
>YMMVAPD (and probably does)
>

The concept behind the ! is simple and eloquent - shorthand for
referencing items in keyed* collections or in cases like ADO a
collection of collections.

[* Keyed means using a 'name' opposed to an index or ordinal number.]

So if you have a bag of stuff it is more natural to access individuals
out of that bag by just using the key without regard to how the actual
collection might be structured. Why else would you build a
keyed-collection? While the syntax is terse, it was not provided just
to save keystroke, but to provide the developer with a more concise
way to express the concept that a Key references an Item.

For example:
In your snippet
rs!name
is converted to ...
rs.Fields("name").Value

And you suggest it is better, but that requires the developer to know
the collection is structured with 'Fields' and the final default
property is "Value". However, what if our bag is structured like this
....

Bag.Customers("name").Text, or
Bag.Accounts("name").String
Bag.Tomestones("name").Caption
Bag.Teams("name").str

Using the Dictionary Lookup operator it doesn't matter,

Bag!name

provides the 'value' keyed with 'name' regardless of any intermediate
terminology. The key essentially becomes a Property of that item.

You said you hated the "the ! syntax because it's just a way to
confuse people by hiding the details of what you are doing". I like
the ! syntax because it DOES hide the details allowing the developer
to express

Key -> Item

without confusion.

But like you said *YMMVAPD*, and it does vary. <BG>

-ralph

Bob Butler

9/6/2011 5:53:00 PM

0


"ralph" <nt_consulting64@yahoo.net> wrote in message
news:lllc671gpeteq8ulf8u99k20l0teso64e8@4ax.com...
> On Mon, 5 Sep 2011 22:34:19 -0700, "Bob Butler"
> <bob_butler@cox.invalid> wrote:
>
<cut>
> And you suggest it is better, but that requires the developer to know
> the collection is structured with 'Fields' and the final default
> property is "Value". However, what if our bag is structured like this
> ...
>
> Bag.Customers("name").Text, or
> Bag.Accounts("name").String
> Bag.Tomestones("name").Caption
> Bag.Teams("name").str
>
> Using the Dictionary Lookup operator it doesn't matter,
>
> Bag!name
>
> provides the 'value' keyed with 'name' regardless of any intermediate
> terminology. The key essentially becomes a Property of that item.

Way too many "developers" out there using things that they don't understand
because the implementation details are hidden. It makes it easy but it also
makes it easy to do sloppy coding. If you don't know what property you are
accessing when you use Bag! then you shouldn't be bagging it! <g>

In my day we had to type it all out explicitly and we liked it that way.
Damn kids these days... and get off my lawn!