BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Just sharing a coding trick

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> comp.lang.pascal.delphi.misc
View previous topic :: View next topic  
Author Message
DAVID B MORGAN
Guest





PostPosted: Sun Jan 15, 2006 10:03 am    Post subject: Just sharing a coding trick Reply with quote



Hi everybody,

This technique may be well known to some of you, but it is
new to me. It may also be bad practice; I don't know!

I had a code problem recently. I realize that I could
probably have solved it with rethinking the logical flow of the
program, but it was easier and faster doing it this way.

=============The Scenario=============

1. When enabled a Ttimer would decrement a scrollbar
one position each time it fires.

2. The user could also manually adjust the scrollbar at any time.

3. I needed the scrollbar.onchange event to fire only when the
scrollbar position was changed manually NOT when its
position was changed by the Ttimer.

4. Scrollbar.onchange event needs to fire different parts of the
Ttimer event depending on if it is enabled or disabled

=============The Problem===============

Ttimer fired scrollbar.onchange that fired TTimer that fired
scrollbar.onchange etc...[Infinite Loop]

=============The Solution===============

procedure TForm1.Timer1Timer(Sender: TObject);
begin
If timer1.enabled=true then
begin
//Lots of code here
end;
scrollbar1.OnChange:=nil; {<- here is the trick}
scrollbar1.Position:=scrollbar1.Position-1;
scrollbar1.OnChange:=ScrollBar1Change;
if timer1.enabled =false then
begin
// Lots of code here
end;
end;

procedure TForm1.ScrollBar1Change(Sender: TObject);
begin
//Lots of code here
timer1timer(sender);
//Lots of code here
end;


Back to top
alanglloyd@aol.com
Guest





PostPosted: Sun Jan 15, 2006 12:45 pm    Post subject: Re: Just sharing a coding trick Reply with quote



When you want the timer to move the scrollbar set its Enabled to true.

In TScrollBar.OnScroll event handler (called only when the user moves
the scrolbar) set TTimer.Enabled to false.

Your "trick" is a valid one within an event handler to prevent
recursive operation. Its not often used elsewhere, and here its better
IMO to use OnScroll.

Your ...

if timer1.enabled =false then
begin
// Lots of code here
end;

.... will be executed when you call Timer1Timer but IMO its better for
this sort of action to call an event handler with a nil parameter and
test for that. Its clearer code too. Both in the event handler and the
calling code it is then obvious that the timer is not calling it. It is
slightly confusing to code an "if control is not enabled" in an event
handler which one usually expects to be called only when the control is
enabled. That's why I think nil testing is better and obviously
indicates a non-control call of the event handler.

Alan Lloyd

Back to top
DAVID B MORGAN
Guest





PostPosted: Sun Jan 15, 2006 12:49 pm    Post subject: Re: Just sharing a coding trick Reply with quote



Alan,
Thank you for your feedback.

David


Back to top
Tom de Neef
Guest





PostPosted: Sun Jan 15, 2006 5:13 pm    Post subject: Re: Just sharing a coding trick Reply with quote

"DAVID B MORGAN" <lepton2 (AT) verizon (DOT) net> schreef in bericht
news:J5pyf.863$FS3.675 (AT) trndny04 (DOT) ..
Quote:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
If timer1.enabled=true then
begin
//Lots of code here
end;
scrollbar1.OnChange:=nil; {<- here is the trick}
scrollbar1.Position:=scrollbar1.Position-1;
scrollbar1.OnChange:=ScrollBar1Change;
if timer1.enabled =false then
begin
// Lots of code here
end;
end;

procedure TForm1.ScrollBar1Change(Sender: TObject);
begin
//Lots of code here
timer1timer(sender);
//Lots of code here
end;

It's a bit like enabling and disabling application interrupts, as in:

procedure disableInterrupts;
// avoid interrupts that can corrupt the calculation process currently
running
begin
Application.OnMessage:=MainForm.AppMessage;
end;

procedure enableInterrupts;
// allow interrupts
begin
Application.OnMessage:=NIL;
end;

procedure TMainForm.AppMessage(var Msg: TMsg; var Handled: Boolean);
// trap all user actions and dump them except an ESC key press
begin
if (Msg.wParam<>27) AND hintWindow.IsHintMsg(Msg)
then Handled := True;
end;

Two remarks - no wish to be pedantic - about the code itself:
1) use "If timer1.enabled" and "If NOT timer1.enabled" instead of "If
timer1.enabled=true" and "If timer1.enabled=false" (the results may be
different on different compilers).
2) save the old value of the handler, as in
oldOnChange:=scrollbar1.OnChange;
scrollbar1.OnChange:=nil; {<- here is the trick}
scrollbar1.Position:=scrollbar1.Position-1;
scrollbar1.OnChange:=oldOnChange;

Tom



Back to top
Jamie
Guest





PostPosted: Sun Jan 15, 2006 6:09 pm    Post subject: Re: Just sharing a coding trick Reply with quote

DAVID B MORGAN wrote:

Quote:
Hi everybody,

This technique may be well known to some of you, but it is
new to me. It may also be bad practice; I don't know!

I had a code problem recently. I realize that I could
probably have solved it with rethinking the logical flow of the
program, but it was easier and faster doing it this way.

=============The Scenario=============

1. When enabled a Ttimer would decrement a scrollbar
one position each time it fires.

2. The user could also manually adjust the scrollbar at any time.

3. I needed the scrollbar.onchange event to fire only when the
scrollbar position was changed manually NOT when its
position was changed by the Ttimer.

4. Scrollbar.onchange event needs to fire different parts of the
Ttimer event depending on if it is enabled or disabled

=============The Problem===============

Ttimer fired scrollbar.onchange that fired TTimer that fired
scrollbar.onchange etc...[Infinite Loop]

=============The Solution===============

procedure TForm1.Timer1Timer(Sender: TObject);
begin
If timer1.enabled=true then
begin
//Lots of code here
end;
scrollbar1.OnChange:=nil; {<- here is the trick}
scrollbar1.Position:=scrollbar1.Position-1;
scrollbar1.OnChange:=ScrollBar1Change;
if timer1.enabled =false then
begin
// Lots of code here
end;
end;

procedure TForm1.ScrollBar1Change(Sender: TObject);
begin
//Lots of code here
timer1timer(sender);
//Lots of code here
end;


here is a trick i use to prevent re'entry of the code block.

procedure Tform1.ScrollBar1.Change(Sender:TObject);
Const Busy :Boolean = false; // make sure write able consts are on..
Begin
If Busy then exit else busy := true;
// do your code...
Busy := false;
End;


--
Real Programmers Do things like this.
http://webpages.charter.net/jamie_5


Back to top
Hans-Peter Diettrich
Guest





PostPosted: Mon Jan 16, 2006 6:39 pm    Post subject: Re: Just sharing a coding trick Reply with quote

Jamie schrieb:

Quote:
here is a trick i use to prevent re'entry of the code block.
procedure Tform1.ScrollBar1.Change(Sender:TObject);
Const Busy :Boolean = false; // make sure write able consts are on..
Begin
If Busy then exit else busy := true;
// do your code...
Busy := false;
End;

I don't like such code for two reasons:

Writeable constants are bad, this option allows to overwrite other
constant values as well. A state variable is okay, of course, and it
should be visible within all related procedures. Sometimes a lock
counter is ueseful, as used with BeginUpdate and EndUpdate.

Quote:
If Busy then exit else busy := true;
If the following code is interrupted, perhaps due to an exception, Busy

will stay true forever. A variable with a wider visibility can be reset
by other code, in contrast to a local constant.

DoDi

Back to top
Maarten Wiltink
Guest





PostPosted: Tue Jan 17, 2006 9:05 am    Post subject: Re: Just sharing a coding trick Reply with quote

"Hans-Peter Diettrich" <DrDiettrich (AT) nowhere (DOT) nix> wrote

Quote:
Jamie schrieb:

here is a trick i use to prevent re'entry of the code block.
procedure Tform1.ScrollBar1.Change(Sender:TObject);
Const Busy :Boolean = false; // make sure write able consts are on..
Begin
If Busy then exit else busy := true;
// do your code...
Busy := false;
End;

I don't like such code for two reasons:

Writeable constants are bad, ...

Fully agreed. "Const" is for *constant*.


Quote:
If Busy then exit else busy := true;

If the following code is interrupted, perhaps due to an exception,
Busy will stay true forever. A variable with a wider visibility can
be reset by other code, in contrast to a local constant.

True, and there should have been a try-finally in the procedure.
I wouldn't have used Exit for this, either.

But this is a local lock and you don't really want it visible outside
the procedure; you just want it done properly inside it. And you can't.
Writeable constants are too high a price to pay; I'd use a global
variable. But it is a choice between two evils.

Groetjes,
Maarten Wiltink



Back to top
Paul Dunn
Guest





PostPosted: Tue Jan 17, 2006 9:44 pm    Post subject: Re: Just sharing a coding trick Reply with quote

Tom de Neef wrote:

Quote:
It's a bit like enabling and disabling application interrupts, as in:

procedure TMainForm.AppMessage(var Msg: TMsg; var Handled: Boolean);
// trap all user actions and dump them except an ESC key press
begin
if (Msg.wParam<>27) AND hintWindow.IsHintMsg(Msg)
then Handled := True;
end;

But wouldn't that still interrupt the flow of your application (assuming
that your calculation allows application.processmessages() during it's work)
when a message arrives?

I'm a tad confused about that - surely the best way to prevent a
time-critical calculation from being interrupted is to ignore all windows
messages until it's done? Use an API function to get the status of the ESC
key periodically instead?

D.



Back to top
Tom de Neef
Guest





PostPosted: Tue Jan 17, 2006 10:55 pm    Post subject: Re: Just sharing a coding trick Reply with quote

"Paul Dunn" <paul.dunn4 (AT) ntlworld (DOT) com> schreef in bericht
news:Uydzf.302$N66.154 (AT) newsfe2-win (DOT) ntli.net...
Quote:
Tom de Neef wrote:

It's a bit like enabling and disabling application interrupts, as in:

procedure TMainForm.AppMessage(var Msg: TMsg; var Handled: Boolean);
// trap all user actions and dump them except an ESC key press
begin
if (Msg.wParam<>27) AND hintWindow.IsHintMsg(Msg)
then Handled := True;
end;

But wouldn't that still interrupt the flow of your application (assuming
that your calculation allows application.processmessages() during it's
work) when a message arrives?

I'm a tad confused about that - surely the best way to prevent a
time-critical calculation from being interrupted is to ignore all windows
messages until it's done? Use an API function to get the status of the ESC
key periodically instead?

D.


When it is time-critical, yes.
But there are also cases where you just don't want the user to change
controls during a calculation, but still want the application to change the
controls (eg update a progress bar). And you want to keep open the Esc
route, in case the calculation time runs out of hand.
Tom



Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> comp.lang.pascal.delphi.misc All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.