From: rick-paulos on
VB6

I'm trying to limit msflexgrid selection to a single row and track
which row is selected.

I have selectionmode set to flexselectionbyrow

I'm getting an out of stack space error #28 with this following sub.
I checked the debug stack and this sub is listed dozens/hundreds of
time over even If I don't call it more than a couple of times.

It looks to me that setting grid.rowsel is calling the sub (recursion)
and that causes the stack over flow.
Any alternative suggestions on how can I limit row selection to a
single row?

Private Sub Grid_SelChange()
'reduce multi row select to single row
Grid.RowSel = Grid.Row
currentgridrow = Grid.Row
'update caption to show db stats & selected row
Mainform.Caption = version + racename + " - " +
EventName(currentevent) + " - " + Str(numberofentrants) + "/" +
Str(entrantsinevent) + " - " + Str(currentgridrow)
End Sub



thanks,
rick
From: Steve Gerrard on
rick-paulos(a)uiowa.edu wrote:
> VB6
>
>
> It looks to me that setting grid.rowsel is calling the sub (recursion)

Stands to reason, since the event handles selection changes.

> and that causes the stack over flow.
> Any alternative suggestions on how can I limit row selection to a
> single row?

Below illustrates a generally useful way for blocking recursion on event
handlers.


>
> Private Sub Grid_SelChange()

Static Busy As Boolean
If Not Busy Then
Busy = True

> 'reduce multi row select to single row
> Grid.RowSel = Grid.Row
> currentgridrow = Grid.Row
> 'update caption to show db stats & selected row
> Mainform.Caption = version + racename + " - " +
> EventName(currentevent) + " - " + Str(numberofentrants) + "/" +
> Str(entrantsinevent) + " - " + Str(currentgridrow)

Busy = False
End If

> End Sub
>



From: Mike Williams on
On 15 Apr, 04:08, "Steve Gerrard" <mynameh...(a)comcast.net> wrote:

> Below illustrates a generally useful way
> for blocking recursion on event handlers.
> Private Sub Grid_SelChange()
>  Static Busy As Boolean
> If Not Busy Then
> Busy = True
> ' do something that causes a
> ' SelChange Change event
> Busy = False
> End If
> End Sub

Now there's a turn up for the book (as they say in this neck of the
woods)! I could have sworn that you needed a DoEvents in there,
between the line that triggers the change and the line that sets Busy
back to False, but on testing it appears that you do not! In fact I've
used such constructs myself many times in the past and I've always
used a DoEvents. And now it turns out not to be actually necessary.

I had always assumed that the event which your code triggered (the
Change event in this case) would go in a queue waiting to be actioned
and that the queue would not be actioned until after the code block
finished executing, unless you put a DoEvents in there to deliberately
cause the event to execute immediately. Now after testing it I can see
that for events triggered by your VB code the event gets executed
immediately anyway, so the DoEvents is not necessary, unlike events
triggered by the system (a resize or whatever triggered by the user)
which do behave in the manner I described and which do end up waiting
in the queue until the code block finishes. I'm glad you posted that,
Steve.

In fact I have often used an event specifically to delay the execution
of some code, in the mistaken belief that something I did would go in
a queue until my current code block finished executing. For example
I've just written a program for my daughter which required a fairly
lengthy code block to be executed in response to a WM_DISPLAYCHANGE
message which I was trapping in a subclassed WindowProc function. I
have always figured that in any subclassed routine it is better to
"get out of there" as quickly as possible (just my old fashioned way,
I suppose?) and I figured that if I simply changed the Text property
of a TextBox Text in the subclass routine then my code in the subclass
routine would finish (the WindowProc routine would finish executing)
and the code in the TextBox's Change event would not begin executing
until after that point in time. Now it appears that this is not the
case, and the Change event code gets executed immediately, while I am
still in the subclass routine, so I might as well have just called the
"lengthy code block" directly, without bothering with all that Change
event stuff! You learn something new every day! Thanks a lot, Steve.

So, it looks like I'll have to do it some other way, perhaps by
setting up a "one shot" Timer or something, or perhaps using some kind
of system message that performs the task. Must get my thinking cap on!

Curiouser and curiouser, as Alice would have said! I would be very
interested to hear your thoughts regarding this "get out of there
quickly" thing that is in my head regarding code in subclassed system
events, such as Window messages and key and mouse events, especially
low level events. Is it actually necessary to "get out of there
quickly", or am I just being a bit old fashioned?

Mike




From: Steve Gerrard on
Mike Williams wrote:
> On 15 Apr, 04:08, "Steve Gerrard" <mynameh...(a)comcast.net> wrote:
>
> I had always assumed that the event which your code triggered (the
> Change event in this case) would go in a queue waiting to be actioned
> and that the queue would not be actioned until after the code block
> finished executing, unless you put a DoEvents in there to deliberately
> cause the event to execute immediately. Now after testing it I can see
> that for events triggered by your VB code the event gets executed
> immediately anyway, so the DoEvents is not necessary, unlike events
> triggered by the system (a resize or whatever triggered by the user)
> which do behave in the manner I described and which do end up waiting
> in the queue until the code block finishes. I'm glad you posted that,
> Steve.
>
> In fact I have often used an event specifically to delay the execution
> of some code, in the mistaken belief that something I did would go in
> a queue until my current code block finished executing. For example
> I've just written a program for my daughter which required a fairly
> lengthy code block to be executed in response to a WM_DISPLAYCHANGE
> message which I was trapping in a subclassed WindowProc function. I
> have always figured that in any subclassed routine it is better to
> "get out of there" as quickly as possible (just my old fashioned way,
> I suppose?) and I figured that if I simply changed the Text property
> of a TextBox Text in the subclass routine then my code in the subclass
> routine would finish (the WindowProc routine would finish executing)
> and the code in the TextBox's Change event would not begin executing
> until after that point in time. Now it appears that this is not the
> case, and the Change event code gets executed immediately, while I am
> still in the subclass routine, so I might as well have just called the
> "lengthy code block" directly, without bothering with all that Change
> event stuff! You learn something new every day! Thanks a lot, Steve.
>
> So, it looks like I'll have to do it some other way, perhaps by
> setting up a "one shot" Timer or something, or perhaps using some kind
> of system message that performs the task. Must get my thinking cap on!
>
> Curiouser and curiouser, as Alice would have said! I would be very
> interested to hear your thoughts regarding this "get out of there
> quickly" thing that is in my head regarding code in subclassed system
> events, such as Window messages and key and mouse events, especially
> low level events. Is it actually necessary to "get out of there
> quickly", or am I just being a bit old fashioned?
>

HI Mike,

I had roughly the same notion about events being triggered, until I worked for a
while with classes that raised events, and discovered that an event occurring
within VB are essentially like a direct call, as you have described. Although it
must go through a little more lookup code to find out if there are any event
handlers listening, it does not continue your own code until the event has been
handled - or ignored - first.

To get the queued effect, I think you have to use windows messaging. If you had
sent a SetText type of message to the text box, instead of setting the text
directly, then a message would have gone into the message queue, the rest of
your subclass routine would complete, and then, at its leisure, Windows would
process the next message and trigger the text box change event. But if you
change the text directly, it becomes a direct call (I almost want to say modal),
going through the VB runtime and executing the change event before your next
line of code executes.

I don't really know if getting out of your WindowProc in a hurry is all that
critical. Most of what happens in VB, as you know, is triggered by events, most
of which trace back to a message getting processed. A button click event, for
instance, starts out with a windows mouse message getting processed, which
decides to trigger the event handler. All of your button click code is running
in a call from the master window proc that responded to that mouse message. It
is actually pretty difficult to get code to run that hasn't been initiated by a
window proc somewhere up the call chain.

Still, there is something about subclassing that suggests that the less you do
the better, and the sooner you can return to normal VB runtime operations, the
better. I don't have enough experience with it to say if there is a cost to
having a long routine run from your own window proc. Maybe you are "working
without a net" while you are in there, and a VB error will crash your app? I'm
not sure.

Have fun sorting it out.



From: Mike Williams on
On 15 Apr, 16:03, "Steve Gerrard" <mynameh...(a)comcast.net> wrote:

> Have fun sorting it out.

I certainly shall Steve. I quite like this sort of stuff. I just wish
I wasn't always so busy and I had more time for it :-(

> To get the queued effect, I think you
> have to use windows messaging. If you
> had sent a SetText type of message to
> the text box, then . . . . .

Thanks for the suggestion Steve, but I've just tried that and it
doesn't work. I get exactly the same effect when I send a WM_SETTEXT
message as I do when setting the text using the TextBox's Text
property, with the Change event being executed immediately instead of
ending up in a queue. So I'll need to look into some other options I
think. I don't want to use the one shot Timer method, but if I can't
turn anything else up then that's what I might actually do. It's early
days yet, though. I'm sure something will turn up, as Mr Micawber used
to say :-)

> I don't really know if getting out of
> your WindowProc in a hurry is all that
> critical. Most of what happens in VB,
> as you know, is triggered by events
> . . . still, there is something about
> subclassing that suggests that the less
> you do the better, and the sooner you
> can return to normal VB runtime operations,
> the better.

Yep. That's the way I feel about it. I generally like to "get out of
there as quickly as possible" in all forms of subclassing. But I
mentioned the window's WM_DISPLAYCHANGE message that I had recently
been using just as an example, and I was really thinking about what
happens when subclassing events at a lower level, such as subclassing
the mouse on a system wide basis, as I have occasionally had the need
to do.

In such cases, unless I specifically want to "eat" the message, I
don't want to stay in there too long because I'm effectively holding
up a message that is destined for all sorts of different places and
that will stop Windows responding to the user's mouse input completely
for the duration that my subclass function code is executing. In fact
I've just carried out a small test of doing exactly that and I
deliberately spent between 50 milliseconds to 100 milliseconds in the
routine, and it made the mouse extremely "jerky" and caused it to
behave very strangely system wide, regardless of whether I called the
default handler before or after I started my "long time in there"
routine. I know that 50 to 100 milliseconds is a deliberately overly
long period of time to spend in the routine, but just to cover all the
bases I would rather trigger an event of some kind to handle the
actual "working code" and get out of the subclass routine as quickly
as possible.

I must admit that I'm a very old fashioned kind of guy and I'm basing
my judgement of these things on my experiences with much simpler
system of many years ago, when I had an extensive knowledge of exactly
how the operating system and the hardware worked and behaved and when
I could run rings around it by intercepting the hardware interrupts
directly. There weren't many surprises that my Amiga could spring on
me! These days I must confess that I'm a little bit lost at times in
the complexity of the Windows messaging system :-(

I think I might go for the simple "one shot" Timer method after
all :-)

Mike