By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
429,435 Members | 2,033 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 429,435 IT Pros & Developers. It's quick & easy.

Using KeyDown from inside OnPaint

P: n/a
KeyDown won't work KeyPress fails KeyDown not seen

inspired by a poster here:http://tinyurl.com/62d97l I found some
interesting stuff, which I reproduce below for newbies like me.

The main reason you would want to do this is for example to trigger
something from an OnPaint event without resorting to boolean switches--
say if a user presses the "M" key while the program is Painting, the
user gets the PaintHandler to do something else. Arguably it's
quicker than waiting for Paint to finish, though I'm not sure of
that. BTW I think for KeyPress the form needs to have focus, but I'm
not sure. But KeyDown I think will work regardless of focus.

RL
public partial class Form1 : Form
{

Keys myGlobalKey;

char myGlobalChar; //declare your 'global' (not really)
variables here--important!

// stuff deleted

public Form1()
{

myGlobalKey = new Keys(); //instantiate here. For safety
do this before InitializeComponent();
myGlobalKey2 = new Keys();
myGlobalChar = new char();

//stuff deleted

// !!! IMPORTANT – make sure “key preview” property is set to true in
Form!! Default is False (!)

// InitializeComponent(); should have this line (if key preview
property set to true): this.KeyPreview = true

// for Debug. to work below (optional) set debugger windows to operate
(F5 key) and declare “using System.Diagnostics;”

///////// set up “key down” event (lightning bolt)

private void Form1_KeyDown(object sender, KeyEventArgs e)
{

myGlobalKey = e.KeyCode;

if (myGlobalKey == Keys.D)
{
Debug.WriteLine("D/d pressed");
MessageBox.Show("D!");
} //works fine from here, for example, but also works from
OnPaint, see below
Invalidate(true); //refresh the form immeadiately after a
key pressed
}

// for less bounce (debatable) this is an older way of getting
information from the key, use “KeyPress” event (works with char not
KeyCode). Not as easy to use most say.

private void Form1_KeyPress(object sender, KeyPressEventArgs
e)
{
//more stable, since key down and up both req'd, but need
control to have focus
myGlobalChar = e.KeyChar; //not e.KeyCode, but returns
character
if (myGlobalChar== 'x')
{
Debug.WriteLine("small X pressed");
MessageBox.Show("x!"); //works fine from here
}
Invalidate(true);
}

////////// now, to show keypresses work even from OnPaint, which is
overridden onto the base PaintEventHandler

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e); //!!! manditory or nothing from Paint Event
handler done. Putting it at beginning rather than end of OnPaint
executes Paint event handler first rather than last (before rather
than after OnPaint). Note: Frazier p. 450 to p453 has a discussion on
OnPaint versus PaintEventHandler base. base.OnPaint(e) will trigger
the PaintEventHandler
if (MouseButtons == MouseButtons.Left)
{
Debug.WriteLine("LMB clicked");
}
//shows you can get mouse info from inside OnPaint

if (myGlobalKey == Keys.O)
{
Debug.WriteLine("Oh! O pressed inside paint");
MessageBox.Show("O! from Paint");
} //works fine, but note: since OnPaint refreshes so fast, you’ll
get a dozen or so messageboxes even if you press quickly. Use escape
key to get out of them

if (myGlobalChar == 'w')
{
Debug.WriteLine("small w pressed Paint");
MessageBox.Show("w! from Paint"); //works fine, but you get lots
of messageboxes, as before
}

// another way of triggering keyboard using ModifierKeys

if ((ModifierKeys == Keys.Shift))
{
Debug.WriteLine("Shift pressed");
if (Cursor.Position.X 50)
{ MessageBox.Show (“shift pressed and cursor 50”);}
} //shows you can get/use mouse cursor from inside OnPaint

// works fine, but I could not get documentation on how ModifierKeys
is declared, so I prefer to use Keys as above.


Aug 5 '08 #1
Share this Question
Share on Google+
14 Replies


P: n/a
On 5 août, 19:25, raylopez99 <raylope...@yahoo.comwrote:
KeyDown won't work KeyPress fails KeyDown not seen

inspired by a poster here:http://tinyurl.com/62d97lI found some
interesting stuff, which I reproduce below for newbies like me.

The main reason you would want to do this is for example to trigger
something from an OnPaint event without resorting to boolean switches--
say if a user presses the "M" key while the program is Painting, the
user gets the PaintHandler to do something else. *Arguably it's
quicker than waiting for Paint to finish, though I'm not sure of
that. *BTW I think for KeyPress the form needs to have focus, but I'm
not sure. *But KeyDown I think will work regardless of focus.

RL

public partial class Form1 : Form
* * {

* * * * Keys myGlobalKey;

* * * * char myGlobalChar; *//declare your 'global' (not really)
variables here--important!

// stuff deleted

* * * public Form1()
* * * * {

* * * * * * myGlobalKey = new Keys(); //instantiate here. *For safety
do this before InitializeComponent();
* * * * * * myGlobalKey2 = new Keys();
* * * * * * myGlobalChar = new char();

//stuff deleted

// *!!! IMPORTANT – make sure “key preview” property is set to true in
Form!! *Default is False (!)

// InitializeComponent(); should have this line (if key preview
property set to true): *this.KeyPreview = true

// for Debug. to work below (optional) set debugger windows to operate
(F5 key) and declare “using System.Diagnostics;”

///////// set up “key down” event (lightning bolt)

* * * * private void Form1_KeyDown(object sender, KeyEventArgs e)
* * * * {

* * * * * * myGlobalKey = e.KeyCode;

* * * * * * if (myGlobalKey == Keys.D)
* * * * * * {
* * * * * * * * Debug.WriteLine("D/d pressed");
* * * * * * * * MessageBox.Show("D!");
* * * * * * } //works fine from here, for example, but also works from
OnPaint, see below

* * * * * * Invalidate(true); //refresh the form immeadiatelyafter a
key pressed
* * * * }

// for less bounce (debatable) this is an older way of getting
information from the key, use “KeyPress” event (works with char not
KeyCode). *Not as easy to use most say.

* * * * private void Form1_KeyPress(object sender, KeyPressEventArgs
e)
* * * * {
* * * * * * //more stable, since key down and up both req'd, but need
control to have focus
* * * * * * myGlobalChar = e.KeyChar; //not e.KeyCode, but returns
character
* * * * * * if (myGlobalChar== 'x')
* * * * * * {
* * * * * * * * Debug.WriteLine("small X pressed");
* * * * * * * * MessageBox.Show("x!"); //works fine from here
* * * * * * }
* * * * * * Invalidate(true);
* * * * }

////////// *now, to show keypresses work even from OnPaint, which is
overridden onto the base PaintEventHandler

protected override void OnPaint(PaintEventArgs e)
*{

* * *base.OnPaint(e); //!!! manditory or nothing from Paint Event
handler done. *Putting it at beginning rather than end of OnPaint
executes Paint event handler first rather than last (before rather
than after OnPaint). *Note: Frazier p. 450 to p453 has a discussion on
OnPaint versus PaintEventHandler base. base.OnPaint(e) will trigger
the PaintEventHandler

* if (MouseButtons == MouseButtons.Left)
* * {
* * * * Debug.WriteLine("LMB clicked");
* * }
//shows you can get mouse info from inside OnPaint

* if (myGlobalKey == Keys.O)
* {
* * * Debug.WriteLine("Oh! O pressed inside paint");
* * * MessageBox.Show("O! from Paint");
* } //works fine, but note: *since OnPaint refreshes so fast, you’ll
get a dozen or so messageboxes even if you press quickly. *Use escape
key to get out of them

* if (myGlobalChar == 'w')
* {
* * * Debug.WriteLine("small w pressed Paint");
* * * MessageBox.Show("w! from Paint"); //works fine, but you get lots
of messageboxes, as before
* }

// another way of triggering keyboard using ModifierKeys

* * * *if ((ModifierKeys == Keys.Shift))
* * * *{
* * * * * *Debug.WriteLine("Shift pressed");
* * * * * *if (Cursor.Position.X 50)
* * * * * *{ MessageBox.Show (“shift pressed and cursor 50”);}
* * * * } //shows you can get/use mouse cursor from inside OnPaint

// works fine, but I could not get documentation on how ModifierKeys
is declared, so I prefer to use Keys as above.
Hey Ray,

Just one thing : you shouldn't use MessageBox inside a Paint handler,
because of the problems you mention (typically, closing the MessageBox
will cause another repaint, which will cause another MessageBox to
appear, and so on). Just use "Debug.WriteLine("blh blah");" and when
you type Ctrl-F5, make sure the "Output" window is showing (View/
Output). Pin it down if necessary. That way, all your debug messages
are shown in this window and don't interrupt the main program, or
cause stacks of alert boxes (there's nothing wrong with your program,
it's just a convenience). Thanks for the tutorial !

Michel
Aug 5 '08 #2

P: n/a
On Tue, 05 Aug 2008 11:38:56 -0700, <mi**************@gmail.comwrote:
Just one thing : you shouldn't use MessageBox inside a Paint handler,
[...]
Ideally, you shouldn't do _anything_ in a Paint handler (or in OnPaint())
that is not directly related to drawing the current state of the control.

There are a few reasonable exceptions, like debug output (as you
mentioned) and calculations that don't affect the state of the control
(e.g. frame rate calculations). Doing other stuff creates a "spaghetti
design" at best, and could lead to serious bugs at the worst.

The Paint handler is for _drawing_ (or "painting" if you like :) ). It's
not a place for other things.

Pete
Aug 5 '08 #3

P: n/a
On Aug 5, 11:38*am, michel.desang...@gmail.com wrote:
On 5 août, 19:25, raylopez99 <raylope...@yahoo.comwrote:
KeyDown won't work KeyPress fails KeyDown not seen
inspired by a poster here:http://tinyurl.com/62d97lIfound some
interesting stuff, which I reproduce below for newbies like me.
The main reason you would want to do this is for example to trigger
something from an OnPaint event without resorting to boolean switches--
say if a user presses the "M" key while the program is Painting, the
user gets the PaintHandler to do something else. *Arguably it's
quicker than waiting for Paint to finish, though I'm not sure of
that. *BTW I think for KeyPress the form needs to have focus, but I'm
not sure. *But KeyDown I think will work regardless of focus.
RL
public partial class Form1 : Form
* * {
* * * * Keys myGlobalKey;
* * * * char myGlobalChar; *//declare your 'global' (not really)
variables here--important!
// stuff deleted
* * * public Form1()
* * * * {
* * * * * * myGlobalKey = new Keys(); //instantiate here.*For safety
do this before InitializeComponent();
* * * * * * myGlobalKey2 = new Keys();
* * * * * * myGlobalChar = new char();
//stuff deleted
// *!!! IMPORTANT – make sure “key preview” property is set to true in
Form!! *Default is False (!)
// InitializeComponent(); should have this line (if key preview
property set to true): *this.KeyPreview = true
// for Debug. to work below (optional) set debugger windows to operate
(F5 key) and declare “using System.Diagnostics;”
///////// set up “key down” event (lightning bolt)
* * * * private void Form1_KeyDown(object sender, KeyEventArgs e)
* * * * {
* * * * * * myGlobalKey = e.KeyCode;
* * * * * * if (myGlobalKey == Keys.D)
* * * * * * {
* * * * * * * * Debug.WriteLine("D/d pressed");
* * * * * * * * MessageBox.Show("D!");
* * * * * * } //works fine from here, for example, but alsoworks from
OnPaint, see below
* * * * * * Invalidate(true); //refresh the form immeadiately after a
key pressed
* * * * }
// for less bounce (debatable) this is an older way of getting
information from the key, use “KeyPress” event (works with char not
KeyCode). *Not as easy to use most say.
* * * * private void Form1_KeyPress(object sender, KeyPressEventArgs
e)
* * * * {
* * * * * * //more stable, since key down and up both req'd, but need
control to have focus
* * * * * * myGlobalChar = e.KeyChar; //not e.KeyCode, but returns
character
* * * * * * if (myGlobalChar== 'x')
* * * * * * {
* * * * * * * * Debug.WriteLine("small X pressed");
* * * * * * * * MessageBox.Show("x!"); //works fine from here
* * * * * * }
* * * * * * Invalidate(true);
* * * * }
////////// *now, to show keypresses work even from OnPaint, which is
overridden onto the base PaintEventHandler
protected override void OnPaint(PaintEventArgs e)
*{
* * *base.OnPaint(e); //!!! manditory or nothing from Paint Event
handler done. *Putting it at beginning rather than end of OnPaint
executes Paint event handler first rather than last (before rather
than after OnPaint). *Note: Frazier p. 450 to p453 has a discussion on
OnPaint versus PaintEventHandler base. base.OnPaint(e) will trigger
the PaintEventHandler
* if (MouseButtons == MouseButtons.Left)
* * {
* * * * Debug.WriteLine("LMB clicked");
* * }
//shows you can get mouse info from inside OnPaint
* if (myGlobalKey == Keys.O)
* {
* * * Debug.WriteLine("Oh! O pressed inside paint");
* * * MessageBox.Show("O! from Paint");
* } //works fine, but note: *since OnPaint refreshes so fast, you’ll
get a dozen or so messageboxes even if you press quickly. *Use escape
key to get out of them
* if (myGlobalChar == 'w')
* {
* * * Debug.WriteLine("small w pressed Paint");
* * * MessageBox.Show("w! from Paint"); //works fine, but you getlots
of messageboxes, as before
* }
// another way of triggering keyboard using ModifierKeys
* * * *if ((ModifierKeys == Keys.Shift))
* * * *{
* * * * * *Debug.WriteLine("Shift pressed");
* * * * * *if (Cursor.Position.X 50)
* * * * * *{ MessageBox.Show (“shift pressed and cursor >50”);}
* * * * } //shows you can get/use mouse cursor from inside OnPaint
// works fine, but I could not get documentation on how ModifierKeys
is declared, so I prefer to use Keys as above.

Hey Ray,

Just one thing : you shouldn't use MessageBox inside a Paint handler,
because of the problems you mention (typically, closing the MessageBox
will cause another repaint, which will cause another MessageBox to
appear, and so on). Just use "Debug.WriteLine("blh blah");" and when
you type Ctrl-F5, make sure the "Output" window is showing (View/
Output). Pin it down if necessary. That way, all your debug messages
are shown in this window and don't interrupt the main program, or
cause stacks of alert boxes (there's nothing wrong with your program,
it's just a convenience). Thanks for the tutorial !

Michel
Thanks Michel. If you have a favorite book on C# let me know (I've
ordered a bunch, including Jon Skeet's!)

Tx Peter D., for pointing out Paint should only be for painting. I
was actually trying to show here how you don't have to use bools to
trigger events in other eventhandlers, but, looking over this code, I
notice essentially the use of 'global' (form wide, namespace wide)
variables does the same thing as a bool. So, aside from the static
member functions you pointed out, I'm at a loss on how you can
transfer 'e' across different event handlers (not inherited but
totally different), other than of course using a 'global' state-
holding class, which is what i do anyway. So I know I'm on the right
track..

RL
Aug 6 '08 #4

P: n/a
On Aug 6, 1:46*pm, raylopez99 <raylope...@yahoo.comwrote:
variables does the same thing as a bool. *So, aside from the static
member functions you pointed out, I'm at a loss on how you can
transfer 'e' across different event handlers (not inherited but
totally different), other than of course using a 'global' state-
holding class, which is what i do anyway. *So I know I'm on the right
track..
This way of doing things (responding to events, and storing data from
one event that might be required when handling another) is simply
inherent to the event-driven approach. Trying to avoid it serves no
point.
Aug 6 '08 #5

P: n/a
On 6 août, 11:46, raylopez99 <raylope...@yahoo.comwrote:
On Aug 5, 11:38*am, michel.desang...@gmail.com wrote:


On 5 août, 19:25, raylopez99 <raylope...@yahoo.comwrote:
KeyDown won't work KeyPress fails KeyDown not seen
inspired by a poster here:http://tinyurl.com/62d97lIfoundsome
interesting stuff, which I reproduce below for newbies like me.
The main reason you would want to do this is for example to trigger
something from an OnPaint event without resorting to boolean switches--
say if a user presses the "M" key while the program is Painting, the
user gets the PaintHandler to do something else. *Arguably it's
quicker than waiting for Paint to finish, though I'm not sure of
that. *BTW I think for KeyPress the form needs to have focus, but I'm
not sure. *But KeyDown I think will work regardless of focus.
RL
public partial class Form1 : Form
* * {
* * * * Keys myGlobalKey;
* * * * char myGlobalChar; *//declare your 'global' (not really)
variables here--important!
// stuff deleted
* * * public Form1()
* * * * {
* * * * * * myGlobalKey = new Keys(); //instantiate here. *For safety
do this before InitializeComponent();
* * * * * * myGlobalKey2 = new Keys();
* * * * * * myGlobalChar = new char();
//stuff deleted
// *!!! IMPORTANT – make sure “key preview” property is set to true in
Form!! *Default is False (!)
// InitializeComponent(); should have this line (if key preview
property set to true): *this.KeyPreview = true
// for Debug. to work below (optional) set debugger windows to operate
(F5 key) and declare “using System.Diagnostics;”
///////// set up “key down” event (lightning bolt)
* * * * private void Form1_KeyDown(object sender, KeyEventArgs e)
* * * * {
* * * * * * myGlobalKey = e.KeyCode;
* * * * * * if (myGlobalKey == Keys.D)
* * * * * * {
* * * * * * * * Debug.WriteLine("D/d pressed");
* * * * * * * * MessageBox.Show("D!");
* * * * * * } //works fine from here, for example, but also works from
OnPaint, see below
* * * * * * Invalidate(true); //refresh the form immeadiately after a
key pressed
* * * * }
// for less bounce (debatable) this is an older way of getting
information from the key, use “KeyPress” event (works with char not
KeyCode). *Not as easy to use most say.
* * * * private void Form1_KeyPress(object sender, KeyPressEventArgs
e)
* * * * {
* * * * * * //more stable, since key down and up both req'd, but need
control to have focus
* * * * * * myGlobalChar = e.KeyChar; //not e.KeyCode, but returns
character
* * * * * * if (myGlobalChar== 'x')
* * * * * * {
* * * * * * * * Debug.WriteLine("small X pressed");
* * * * * * * * MessageBox.Show("x!"); //works fine from here
* * * * * * }
* * * * * * Invalidate(true);
* * * * }
////////// *now, to show keypresses work even from OnPaint, which is
overridden onto the base PaintEventHandler
protected override void OnPaint(PaintEventArgs e)
*{
* * *base.OnPaint(e); //!!! manditory or nothing from Paint Event
handler done. *Putting it at beginning rather than end of OnPaint
executes Paint event handler first rather than last (before rather
than after OnPaint). *Note: Frazier p. 450 to p453 has a discussionon
OnPaint versus PaintEventHandler base. base.OnPaint(e) will trigger
the PaintEventHandler
* if (MouseButtons == MouseButtons.Left)
* * {
* * * * Debug.WriteLine("LMB clicked");
* * }
//shows you can get mouse info from inside OnPaint
* if (myGlobalKey == Keys.O)
* {
* * * Debug.WriteLine("Oh! O pressed inside paint");
* * * MessageBox.Show("O! from Paint");
* } //works fine, but note: *since OnPaint refreshes so fast, you’ll
get a dozen or so messageboxes even if you press quickly. *Use escape
key to get out of them
* if (myGlobalChar == 'w')
* {
* * * Debug.WriteLine("small w pressed Paint");
* * * MessageBox.Show("w! from Paint"); //works fine, but you get lots
of messageboxes, as before
* }
// another way of triggering keyboard using ModifierKeys
* * * *if ((ModifierKeys == Keys.Shift))
* * * *{
* * * * * *Debug.WriteLine("Shift pressed");
* * * * * *if (Cursor.Position.X 50)
* * * * * *{ MessageBox.Show (“shift pressed and cursor50”);}
* * * * } //shows you can get/use mouse cursor from inside OnPaint
// works fine, but I could not get documentation on how ModifierKeys
is declared, so I prefer to use Keys as above.
Hey Ray,
Just one thing : you shouldn't use MessageBox inside a Paint handler,
because of the problems you mention (typically, closing the MessageBox
will cause another repaint, which will cause another MessageBox to
appear, and so on). Just use "Debug.WriteLine("blh blah");" and when
you type Ctrl-F5, make sure the "Output" window is showing (View/
Output). Pin it down if necessary. That way, all your debug messages
are shown in this window and don't interrupt the main program, or
cause stacks of alert boxes (there's nothing wrong with your program,
it's just a convenience). Thanks for the tutorial !
Michel

Thanks Michel. *If you have a favorite book on C# let me know (I've
ordered a bunch, including Jon Skeet's!)

Tx Peter D., for pointing out Paint should only be for painting. *I
was actually trying to show here how you don't have to use bools to
trigger events in other eventhandlers, but, looking over this code, I
notice essentially the use of 'global' (form wide, namespace wide)
variables does the same thing as a bool. *So, aside from the static
member functions you pointed out, I'm at a loss on how you can
transfer 'e' across different event handlers (not inherited but
totally different), other than of course using a 'global' state-
holding class, which is what i do anyway. *So I know I'm on the right
track..

RL- Masquer le texte des messages précédents -

- Afficher le texte des messages précédents -
Well, Jon Skeet's is pretty much my favorite at the moment, so you
should be all set ! It's both full of info AND very well-written. I
don't know the guy, have never talked to him, even though we have
occasionally participated in the same threads, so it's not a shameless
plug ! (it's called "C# in depth", for those who don't know it yet :
http://csharpindepth.com).

About the transfering of e, the only place where you're still using a
global variable is for checking out which key is pressed (other than
the control keys). There are several solutions to this : the first
obvious one would be to use a keyboard hook into the window's message
pump, but that's a lot of boilerplate code, and it doesn't satisfy
your condition for avoiding globals altogether.

The second one would be to use the GetAsyncKeyState function, which is
in user32.dll. To use it, add at the top of your class (just below
"public partial class Form1 : Form") :

[DllImport("User32.dll")]
private static extern short GetAsyncKeyState(short key);

Then, anywhere in your code, you can check whether a key is pressed by
doing the following test :

if (GetAsyncKeyState((short)Keys.A) < 0)
{
// the letter A is currently pressed, do something with it
}

It even works for Keys.Insert and other non-ASCII keys. If the result
is < 0, the key is pressed, if it's >= 0, the key isn't pressed.

Be aware that it's asynchronous, which implies that it returns the
state of the keys at the moment you're testing it, and not the moment
some other event happened (for instance, if you put such a test inside
an event handler for a mouse click, it won't tell you whether the key
was pressed when the click happened, but when the test was evaluated
(yeah, in this case, you'd have to be pretty fast to have different
results, I just wanted to be thorough :)).

The third solution to avoid globals... Ok, I'm going to use a trick
there... is to use globals. But of a different nature. Let's say that
you want to detect whether the "C" key is pressed because then you
want to draw a circle in your paint event. Instead of having a
KeyState class, you could have, say, an ActionQueue class, and queue
inside the requested actions. Inside the onPaint, you would for
instance check :

if (Actions.Count 0)
{
Action action = Actions.Dequeue(); // I'm not writing the generics
details here to simplify, this is just pseudo-code
if (action == ActionsEnum.Circle)
{
DrawCircle();
}
else if (action == ActionsEnum.Erase)
{
ErasePicture();
}
// ...
}

The advantages of this technique are long-term ones : it will simplify
Undo implementation, and possibly the serialization of your actions.
Also, you've transformed arbitrary commands (Keys.C) into meaningful
ones (Actions.Circle, for instance), which will be much easier when
you go back on your code months later (or someone else).

It's much more work, but in the end, I think it's worth it. Also, you
get rid of reading the key state in real-time (just implement the
onKeyPress or onKeyDown event handlers and insert the corresponding
actions in your queue there). You have decoupled the keyboard handling
from the drawing, and in terms of OOP, that's always a Good Thing. :)

But I think that as soon as your program is going to grow, you'll have
to resort to state classes/variables anyway (to store the state of a
tool, for example, or remember settings between sessions). So the
transfering of "e" won' t be such a problem anymore (unless you're
aiming for a time-critical stateless app, in which case solution 2
above should work).

Maybe you would be interested in learning about "finite state
machines", which is a way of programming that has some similarities to
this problem. I cannot tell you more about it because I haven't delved
into it yet, but there is considerable litterature about it all around
and what I read so far was quite interesting (though rather arduous).

Hope this helps !

Michel
Aug 6 '08 #6

P: n/a
On Aug 6, 3:47*am, Pavel Minaev <int...@gmail.comwrote:
This way of doing things (responding to events, and storing data from
one event that might be required when handling another) is simply
inherent to the event-driven approach. Trying to avoid it serves no
point.
Good, then I'm on the right track, like I said.

RL

Aug 6 '08 #7

P: n/a
On Aug 6, 4:10*am, michel.desang...@gmail.com wrote:
>
Well, Jon Skeet's is pretty much my favorite at the moment, so you
should be all set ! It's both full of info AND very well-written. I
don't know the guy, have never talked to him, even though we have
occasionally participated in the same threads, so it's not a shameless
plug ! (it's called "C# in depth", for those who don't know it yet :http://csharpindepth.com).
Yeah Jon's the poor man's Scott Meyers, who wrote some books on C++ in
the late 1990s that got a lot of press ("effective c++"). I read
through some of them, and they were full of good stuff. Mostly, if I
recall correctly, garbage collection was a big problem back then, and
we all know how C# "solved" that problem (is the cure worse than the
disease though?)

About the transfering of e, the only place where you're still using a
global variable is for checking out which key is pressed (other than
the control keys).
There are several solutions to this :
Why would you want a solution? After reading through this thread, I
think from an OOP point of view you should not be designing around
this "problem"/
the first
obvious one would be to use a keyboard hook into the window's message
pump, but that's a lot of boilerplate code, and it doesn't satisfy
your condition for avoiding globals altogether.
Right. I don't want to learn MFC again (I didn't know it all that
well the first time, though I did write some useful programs in C++).
>
The second one would be to use the GetAsyncKeyState function, which is
in user32.dll. To use it, add at the top of your class (just below
"public partial class Form1 : Form") :
No way, too complicated.

Be aware that it's asynchronous, which implies that it returns the
state of the keys at the moment you're testing it, and not the moment
some other event happened (for instance, if you put such a test inside
an event handler for a mouse click, it won't tell you whether the key
was pressed when the click happened, but when the test was evaluated
(yeah, in this case, you'd have to be pretty fast to have different
results, I just wanted to be thorough :)).
Well, if it's asynchronous, it might be a good idea for multi-threaded
programs, which is something I have to study at some point, but even
with multi-threaded programs (writing programs to run on multi-core
machines), keeping your event handler events seperate should allow for
multithreading I would imagine.
>
The third solution to avoid globals... Ok, I'm going to use a trick
there... is to use globals.
OK, I got that. That's what I do now--store state information in a
class and pass the class around, between event handlers or between
main forms and sub-forms, etc.
But of a different nature. Let's say that
you want to detect whether the "C" key is pressed because then you
want to draw a circle in your paint event. Instead of having a
KeyState class, you could have, say, an ActionQueue class, and queue
inside the requested actions. Inside the onPaint, you would for
instance check :

if (Actions.Count 0)
{
* Action action = Actions.Dequeue(); // I'm not writing the generics
details here to simplify, this is just pseudo-code
* if (action == ActionsEnum.Circle)
Action. I don't know Action. Jon Skeet has a big thing about Action--
in fact, the first page I turned to in his book that I just got today
was on Action! LOL! I'll have to study Action then.
>
The advantages of this technique are long-term ones : it will simplify
Undo implementation, and possibly the serialization of your actions.
Also, you've transformed arbitrary commands (Keys.C) into meaningful
ones (Actions.Circle, for instance), which will be much easier when
you go back on your code months later (or someone else).
I don't get it, but please don't explain, you're wasting your time.
I'm too new. I think you're saying that with "Undo" you have to take
a "snapshot" of the state of the machine at any time, and using your
"global" scheme involving "Action" you can take that "snapshot" easier
than using state variables that are being passed around. OK, if
that's the point, but it's a big over my head now. Anyway I think
they have a macro / method for "Undo" in C#, an [attribute] like
[serialization], and you can pretty much serialize anything (except
hash numbers it turns out). I'll get to it in a month or two.
>
It's much more work, but in the end, I think it's worth it. Also, you
get rid of reading the key state in real-time (just implement the
onKeyPress or onKeyDown event handlers and insert the corresponding
actions in your queue there). You have decoupled the keyboard handling
from the drawing, and in terms of OOP, that's always a Good Thing. :)
Decoupling is good. Tightly coupled versus loosely coupled--the debate
continues! I don't know what they are talking about...
>
But I think that as soon as your program is going to grow, you'll have
to resort to state classes/variables anyway (to store the state of a
tool, for example, or remember settings between sessions). So the
transfering of "e" won' t be such a problem anymore (unless you're
aiming for a time-critical stateless app, in which case solution 2
above should work).
Yes, agreed. I don't really care about transferring 'e' anymore, it
was just an academic question.
>
Maybe you would be interested in learning about "finite state
machines", which is a way of programming that has some similarities to
this problem. I cannot tell you more about it because I haven't delved
into it yet, but there is considerable litterature about it all around
and what I read so far was quite interesting (though rather arduous).
I thought Alan Turning said every PC is a FSM, no? And the famous
"HALT" problem, an infinite loop, 0.99999.... Something like that.
>
Hope this helps !

Michel
No it doesn't! But don't worry about it, half the stuff you did make
sense to me was quite helpful! :-)

RL

Aug 6 '08 #8

P: n/a
On 6 août, 17:52, raylopez99 <raylope...@yahoo.comwrote:
On Aug 6, 4:10*am, michel.desang...@gmail.com wrote:
Well, Jon Skeet's is pretty much my favorite at the moment, so you
should be all set ! It's both full of info AND very well-written. I
don't know the guy, have never talked to him, even though we have
occasionally participated in the same threads, so it's not a shameless
plug ! (it's called "C# in depth", for those who don't know it yet :http://csharpindepth.com).

Yeah Jon's the poor man's Scott Meyers, who wrote some books on C++ in
the late 1990s that got a lot of press ("effective c++"). *I read
through some of them, and they were full of good stuff. *Mostly, if I
recall correctly, garbage collection was a big problem back then, and
we all know how C# "solved" that problem (is the cure worse than the
disease though?)
About the transfering of e, the only place where you're still using a
global variable is for checking out which key is pressed (other than
the control keys).
There are several solutions to this :

Why would you want a solution? *After reading through this thread, I
think from an OOP point of view you should not be designing around
this "problem"/
the first
obvious one would be to use a keyboard hook into the window's message
pump, but that's a lot of boilerplate code, and it doesn't satisfy
your condition for avoiding globals altogether.

Right. *I don't want to learn MFC again (I didn't know it all that
well the first time, though I did write some useful programs in C++).
The second one would be to use the GetAsyncKeyState function, which is
in user32.dll. To use it, add at the top of your class (just below
"public partial class Form1 : Form") :

No way, too complicated.
Be aware that it's asynchronous, which implies that it returns the
state of the keys at the moment you're testing it, and not the moment
some other event happened (for instance, if you put such a test inside
an event handler for a mouse click, it won't tell you whether the key
was pressed when the click happened, but when the test was evaluated
(yeah, in this case, you'd have to be pretty fast to have different
results, I just wanted to be thorough :)).

Well, if it's asynchronous, it might be a good idea for multi-threaded
programs, which is something I have to study at some point, but even
with multi-threaded programs (writing programs to run on multi-core
machines), keeping your event handler events seperate should allow for
multithreading I would imagine.
The third solution to avoid globals... Ok, I'm going to use a trick
there... is to use globals.

OK, I got that. *That's what I do now--store state information in a
class and pass the class around, between event handlers or between
main forms and sub-forms, etc.
But of a different nature. Let's say that
you want to detect whether the "C" key is pressed because then you
want to draw a circle in your paint event. Instead of having a
KeyState class, you could have, say, an ActionQueue class, and queue
inside the requested actions. Inside the onPaint, you would for
instance check :
if (Actions.Count 0)
{
* Action action = Actions.Dequeue(); // I'm not writing the generics
details here to simplify, this is just pseudo-code
* if (action == ActionsEnum.Circle)

Action. *I don't know Action. *Jon Skeet has a big thing about Action--
in fact, the first page I turned to in his book that I just got today
was on Action! LOL! *I'll have to study Action then.
The advantages of this technique are long-term ones : it will simplify
Undo implementation, and possibly the serialization of your actions.
Also, you've transformed arbitrary commands (Keys.C) into meaningful
ones (Actions.Circle, for instance), which will be much easier when
you go back on your code months later (or someone else).

I don't get it, but please don't explain, you're wasting your time.
I'm too new. *I think you're saying that with "Undo" you have to take
a "snapshot" of the state of the machine at any time, and using your
"global" scheme involving "Action" you can take that "snapshot" easier
than using state variables that are being passed around. *OK, if
that's the point, but it's a big over my head now. *Anyway I think
they have a macro / method for "Undo" in C#, an [attribute] like
[serialization], and you can pretty much serialize anything (except
hash numbers it turns out). *I'll get to it in a month or two.
It's much more work, but in the end, I think it's worth it. Also, you
get rid of reading the key state in real-time (just implement the
onKeyPress or onKeyDown event handlers and insert the corresponding
actions in your queue there). You have decoupled the keyboard handling
from the drawing, and in terms of OOP, that's always a Good Thing. :)

Decoupling is good. Tightly coupled versus loosely coupled--the debate
continues! *I don't know what they are talking about...
But I think that as soon as your program is going to grow, you'll have
to resort to state classes/variables anyway (to store the state of a
tool, for example, or remember settings between sessions). So the
transfering of "e" won' t be such a problem anymore (unless you're
aiming for a time-critical stateless app, in which case solution 2
above should work).

Yes, agreed. *I don't really care about transferring 'e' anymore, it
was just an academic question.
Maybe you would be interested in learning about "finite state
machines", which is a way of programming that has some similarities to
this problem. I cannot tell you more about it because I haven't delved
into it yet, but there is considerable litterature about it all around
and what I read so far was quite interesting (though rather arduous).

I thought Alan Turning said every PC is a FSM, no? *And the famous
"HALT" problem, an infinite loop, 0.99999.... Something like that.
Hope this helps !
Michel

No it doesn't! *But don't worry about it, half the stuff you did make
sense to me was quite helpful! :-)

RL
That was the whole point. I know the question was purely academic, and
I submitted the first two solutions two demonstrate why, in the end,
you inevitably would have to fall back on state-keeping.

Just one thing about the Action I was talking about : it was just
meant as an example and I wasn't refering to the Action Jon's talking
about, which is part of the framework. Rewrite that as "PaintAction"
or "UserAction" or anything that's not used in the frameword. Bad
choice of words !

Anyway, you seem to be having fun with all that and that's all that
matters !

Michel
Aug 6 '08 #9

P: n/a
On Aug 6, 10:54*am, michel.desang...@gmail.com wrote:
>
That was the whole point. I know the question was purely academic, and
I submitted the first two solutions two demonstrate why, in the end,
you inevitably would have to fall back on state-keeping.
Ah, now I see. :-)
>
Just one thing about the Action I was talking about : it was just
meant as an example and I wasn't refering to the Action Jon's talking
about, which is part of the framework. Rewrite that as "PaintAction"
or "UserAction" or anything that's not used in the frameword. Bad
choice of words !
OK. Jon BTW was featured in the MSDN today when my front page news
reader loaded up--LOL, a local celebrity who'se almost famous--with
his book review of a fellow called Nash, "Accelerated C#". Jon was
very kind to the author in his review, probably because he wants to
work with him in a future book (reading between the lines), though it
seemed the book was a bit esoteric and obtuse for most programmers
like me (the target audience? perhaps like in chess, where the target
audience is always kids, tyros, and people who want to memorize
openings rather than advanced players, because the advanced players
usually don't read chess books, certainly not annotated moves in
books, they just review games played by strong players). Most computer
science books, like chess books, are poorly written I've found--I buy
a half dozen every year and throw out half of them, but I write it off
as a business expense.
>
Anyway, you seem to be having fun with all that and that's all that
matters !
Yes, coding is addictive I find. I'm starting to get into it now,
full swing. Layout is very important I'm finding--user layout so it
looks familiar, because with the Wizard you can do all kinds of crazy
stuff with controls that quickly becomes visual clutter...but I just
love the drag-and-drop stuff for menus and controls, even the timer,
trees, and dialog boxes...great stuff.

RL
Aug 6 '08 #10

P: n/a
On 7 août, 00:22, raylopez99 <raylope...@yahoo.comwrote:
On Aug 6, 10:54*am, michel.desang...@gmail.com wrote:
That was the whole point. I know the question was purely academic, and
I submitted the first two solutions two demonstrate why, in the end,
you inevitably would have to fall back on state-keeping.

Ah, now I see. :-)
Just one thing about the Action I was talking about : it was just
meant as an example and I wasn't refering to the Action Jon's talking
about, which is part of the framework. Rewrite that as "PaintAction"
or "UserAction" or anything that's not used in the frameword. Bad
choice of words !

OK. *Jon BTW was featured in the MSDN today when my front page news
reader loaded up--LOL, a local celebrity who'se almost famous--with
his book review of a fellow called Nash, "Accelerated C#". *Jon was
very kind to the author in his review, probably because he wants to
work with him in a future book (reading between the lines), though it
seemed the book was a bit esoteric and obtuse for most programmers
like me (the target audience? perhaps like in chess, where the target
audience is always kids, tyros, and people who want to memorize
openings rather than advanced players, because the advanced players
usually don't read chess books, certainly not annotated moves in
books, they just review games played by strong players). Most computer
science books, like chess books, are poorly written I've found--I buy
a half dozen every year and throw out half of them, but I write it off
as a business expense.
But you do have to cater for people who have some experience in the
field. I've been working as programmer for 25 years (next october), so
I'm quite glad that there are esoteric and sometimes difficult books
around, otherwise, we'd be condemned to read the same "teach yourself
something in 10 minutes" over and over again. Still, those (well,
maybe not those, but say, introductory books on a new version of a
language) are helpful because it saves time to have everything nicely
summed up in one source, rather that peruse through the documentation
for each new function (and sometimes, you find this :
http://msdn.microsoft.com/en-us/libr...esfactory.aspx,
note the "this type does nothing meaningful" !).
Anyway, you seem to be having fun with all that and that's all that
matters !

Yes, coding is addictive I find. * I'm starting to get into it now,
full swing. *Layout is very important I'm finding--user layout so it
looks familiar, because with the Wizard you can do all kinds of crazy
stuff with controls that quickly becomes visual clutter...but I just
love the drag-and-drop stuff for menus and controls, even the timer,
trees, and dialog boxes...great stuff.
Yes, UI design is just as important and fun as the code itself. You're
in the right group, cause I don't think you'll find many ppl here
saying "that programmation stuff ? Nahh, hate it...". :)

Michel
Aug 7 '08 #11

P: n/a
On Aug 7, 2:44*am, michel.desang...@gmail.com wrote:
y
summed up in one source, rather that peruse through the documentation
for each new function (and sometimes, you find this :http://msdn.microsoft.com/en-us/libr...forms.gridtabl...,
note the "this type does nothing meaningful" !).
Good one. "GridTablesFactory Class This API supports the .NET
Framework infrastructure and is not intended to be used directly from
your code. This type does nothing meaningful."
BTW, according to an interesting article in the Wall Street Journal
last week, here is what you should be making with 10+ years or so
experience. Hope you are doing well.

Computer Science (they also have a "Computer Engineering" category
that's 5 to 10k higher):

Staring salary: USD$ 55.9K, mid-career (10+ years) median: $95.5k;
mid-career lowest 10% (bottom): $56k; highest 10% $154k

Before you get too egotistical and self-important, consider the
following three careers paths by comparison:

Construction: (same sequence as before): $53.7k, 88.9k, 56.3K, 171k
Drama: " ": 35.9k, 56.9k, 36.7k, 153k.
Forestry: " ": 39.1k, 62.6k, 41k, 111k

From this, you can tell that there's money to be made in being
management--in drama, and in construction and even, to a lesser
degree, in "forestry" (what do those guys do but hike all day?!), but
not perhaps in Computer Science. Electrical Engineers make about the
same as Comp. Sci. majors, with about 10k more at the top end, but the
guys that really clean up are the chem. engrs, they make, at the top
end, $194k. Almost as good as being a doctor or lawyer or accountant
or indian chief.

RL
Aug 7 '08 #12

P: n/a
On 7 août, 18:32, raylopez99 <raylope...@yahoo.comwrote:
On Aug 7, 2:44*am, michel.desang...@gmail.com wrote:
y
summed up in one source, rather that peruse through the documentation
for each new function (and sometimes, you find this :http://msdn.microsoft.com/en-us/libr...forms.gridtabl...,
note the "this type does nothing meaningful" !).

Good one. "GridTablesFactory Class This API supports the .NET
Framework infrastructure and is not intended to be used directly from
your code. This type does nothing meaningful."

BTW, according to an interesting article in the Wall Street Journal
last week, here is what you should be making with 10+ years or so
experience. *Hope you are doing well.

Computer Science (they also have a "Computer Engineering" category
that's 5 to 10k higher):

Staring salary: *USD$ 55.9K, mid-career (10+ years) median: $95.5k;
mid-career lowest 10% (bottom): $56k; highest 10% $154k

Before you get too egotistical and self-important, consider the
following three careers paths by comparison:

Construction: *(same sequence as before): *$53.7k, 88.9k, 56.3K, 171k
Drama: " ": 35.9k, 56.9k, 36.7k, 153k.
Forestry: " ": 39.1k, 62.6k, 41k, 111k

From this, you can tell that there's money to be made in being
management--in drama, and in construction and even, to a lesser
degree, in "forestry" (what do those guys do but hike all day?!), but
not perhaps in Computer Science. *Electrical Engineers make about the
same as Comp. Sci. majors, with about 10k more at the top end, but the
guys that really clean up are the chem. engrs, they make, at the top
end, $194k. *Almost as good as being a doctor or lawyer or accountant
or indian chief.

RL
Thanks for the info, but unfortunately it doesn't apply to me : I have
my own company (so I make less than that, but hope to make more than
that in the end if I'm successful), and I'm french. There is a serious
shortage of programmers in Europe right now, so the salaries are
probably slightly higher.

But, the drama thing... Darn, I admit it's rather tempting :)

Michel
Aug 8 '08 #13

P: n/a
On Aug 5, 11:45*am, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
Ideally, you shouldn't do _anything_ in a Paint handler (or in OnPaint())*
that is not directly related to drawing the current state of the control.

There are a few reasonable exceptions, like debug output (as you *
mentioned) and calculations that don't affect the state of the control *
(e.g. frame rate calculations). *Doing other stuff creates a "spaghetti*
design" at best, and could lead to serious bugs at the worst.

The Paint handler is for _drawing_ (or "painting" if you like :) ). *It's *
not a place for other things.
Good points no doubt, but I notice programs where the converse is not
true: they do drawing or painting from outside of OnPaint. Example:
using from inside of a mouse move eventhandler
"Control.Paint.DrawReversibleFrame(Rectangle,
this.BackColor,FrameStyle.Dashed);" to draw a dashed rectangle that
moves with the mouse button. They could have set a flag that then
paints the rectangle from Paint, but that would not make the code as
readable I guess.

RL
Aug 8 '08 #14

P: n/a
On Aug 8, 6:33*pm, raylopez99 <raylope...@yahoo.comwrote:
|Good points no doubt, but I notice programs where the converse is
not
true: *they do drawing or painting from outside of OnPaint. *Example:
using from inside of a mouse move eventhandler
"Control.Paint.DrawReversibleFrame(Rectangle,
this.BackColor,FrameStyle.Dashed);" to draw a dashed rectangle that
moves with the mouse button. * They could have set a flag that then
paints the rectangle from Paint, but that would not make the code as
readable I guess.
This is a patently bad idea, because Windows can force a redraw on you
at any moment (e.g. another program raises a window over yours, and
then hides it again - the area that was obscured by the window will
need to be redrawn). If you handle all your drawing in OnPaint, then
it will "just work" for you; but if you draw outside, then all that
you draw will be erased and not redrawn.
Aug 11 '08 #15

This discussion thread is closed

Replies have been disabled for this discussion.