|
Prev: Comparing lists in Excel/Visual Basic
Next: Want to buy VB6 compatible Farpoint Spread OCX software. (NOT the .NET version)
From: rick-paulos on 14 Apr 2008 13:31 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 14 Apr 2008 23:08 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 15 Apr 2008 02:21 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 15 Apr 2008 11:03 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 15 Apr 2008 12:33
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 |