Need a way to tell if a System.Windows.Forms.Button is "depressed" (pushed down)

J

jrhoads23

Hello,
I am trying to find a way to tell if an .NET windows forms Button
(System.Windows.Forms.Button) is "depressed" (pushed down). For my
application, I can not use a check box control set to button style, I
must use a System.Windows.Forms.Button. I can not find a way to tell
when it is momentaraly pressed.

I tried calling the API SendMessage with the button handle and
BM_GETSTATE to get the state of the button. This will only return when
the button has focus (BST_FOCUS). It will never return a result with
BST_PUSHED even when the button is in fact pressed down.
Any ideas?
Jeff
 
J

Jay B. Harlow [MVP - Outlook]

Jeff,
Have you considered using a CheckBox or RadioButton control with the
Appearance property set to Button?

This causes the CheckBox or RadioButton to look like a normal Button, but
continue to function (toggle) as a CheckBox or RadioButton.

You can set the AutoCheck property of the CheckBox or RadioButton if you
don't want them to stay down.

Hope this helps
Jay
 
J

jrhoads23

Jay,
Thanks for the suggestion. I tried using both the CheckBox and
RadioButton. Neither of them work because their Checked property is not
set until the user releases the left mouse button. If you create a
button, click it with the left mouse button and hold the mouse button
down you will see that the button stays "pushed down". The CheckChanged
event is not fired, OnClick event is not fired, and Checked property is
False until you release the mouse button. I am looking to be able to
tell when the button is actually depressed (pushed down)

I am doing my own painting on my button and want it to "push down" with
the button by offsetting it when the button is depressed. Currently the
button gets pushed down but what I painted on it does not.

Jeff
 
L

Lloyd Sheen

Here is a simple way. Use the mousedown and mouseup events of the button.
Create a form with a button and a label using their default values. Then
add the following code to see what happens. You can still use the painting
code you currently use but you can now use the button as an off/on button.


Private Sub Button1_MouseDown(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles Button1.MouseDown
Me.Label1.Text = "Pressed"
End Sub

Private Sub Button1_MouseUp(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles Button1.MouseUp
Me.Label1.Text = "Not Pressed"
End Sub

Lloyd Sheen
 
S

Samuel R. Neff

Also want to track mouseenter and mouseleave events as the affect the
pressed state.

Might be easier to extend the button and add your painting code to the
PaintDown or PaintFlatDown methods.

Sam
 
J

jrhoads23

I thought about tracking the mouse up/down and location. It will work
ok except for when the user gives the button focus and then presses the
space bar. But still, it would be better to handle the mouse end of it
and then worry about the space bar issue.

It would just be so much easier if the BST_PUSHED style could be
captured. I cant figure out why the API call will not return this.
 
J

Jay B. Harlow [MVP - Outlook]

Jeff,
Lets back up to the beginning:

How are you defining, and when are you using SendMessage with BM_GETSTATE &
BST_PUSHED?

The following is a sample of a CheckBox that has an IsPushed property.

The IsPushed property returns true then the mouse is down & the control has
focus, in other words when the control is Pressed.

It uses BM_GETSTATE & SendMessage to check for the BST_PUSHED state. The
same code works for CheckBox, RadioButton, & Button class in .NET.

Remember under .NET an Integer is a 32bit value, while a Long is a 64bit
value. Defining the function with IntPtr as I did, ensures it will continue
working as expected in the 64-bit version of Windows. Also remember that
BM_GETSTATE returns a set of bit flags, you need to isolate the specific
bits you are interested in.

Public Class CheckBoxEx
Inherits CheckBox

Private Enum ButtonMessage As Integer
GetCheck = &HF0
SetCheck = &HF1
GetState = &HF2
SetState = &HF3
SetStyle = &HF4

Click = &HF5
GetImage = &HF6
SetImage = &HF7
End Enum

<Flags()> _
Private Enum ButtonState As Integer
UnChecked = &H0
Checked = &H1
Indeterminate = &H2
StateMask = &H3
Pushed = &H4
Focus = &H8
End Enum

Private Declare Auto Function SendMessage Lib "user32" (ByVal hWnd As
IntPtr, ByVal msg As ButtonMessage, ByVal wParam As IntPtr, ByVal lParam As
IntPtr) As IntPtr

Public ReadOnly Property IsPushed() As Boolean
Get
Dim rc As IntPtr
rc = SendMessage(Me.Handle, ButtonMessage.GetState, IntPtr.Zero,
IntPtr.Zero)
Dim state As ButtonState = CType(rc.ToInt32(), ButtonState)
Return ((state And ButtonState.Pushed) = ButtonState.Pushed)
End Get
End Property

End Class

Hope this helps
Jay
 
M

Mick Doherty

Hi Jay,

I can confirm Jeffs results. BM_GETSTATE always returns 0 or 8 (focused or
not_focused) and nothing else.

I tested your class out and IsPushed always returns False, although it
should definately give the results that you are expecting.

I prefer to use WndProc to Sendmessage but the result is the same either
way.

\\\
Dim m As Message
m = Message.Create(Handle, BM_GETSTATE, IntPtr.Zero, IntPtr.Zero)
WndProc(m)
Dim state As ButtonState = CType(m.Result.ToInt32(), ButtonState)
Return ((state And ButtonState.Pushed) = ButtonState.Pushed)
///

My System specs:
WindowsXP Pro SP2
VS2003
 
J

Jay B. Harlow [MVP - Outlook]

Mick,
Where are you using BM_GETSTATE? My IsPressed (ergo BM_GETSTATE) returns
True when called from the Control.MouseMove event when the mouse is down,
and the mouse did not leave the control. If you think about it, the "button"
is never really pressed otherwise.

Try the following:

Private WithEvents CheckBox1 As CheckBoxEx


Private Sub CheckBox1_MouseDown(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles CheckBox1.MouseDown
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseDown")
End Sub

Private Sub CheckBox1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles CheckBox1.MouseMove
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseMove")
End Sub

Private Sub CheckBox1_MouseUp(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles CheckBox1.MouseUp
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseUp")
End Sub

Private Sub CheckBox1_MouseEnter(ByVal sender As Object, ByVal e As
System.EventArgs) Handles CheckBox1.MouseEnter
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseEnter")
End Sub

Private Sub CheckBox1_MouseLeave(ByVal sender As Object, ByVal e As
System.EventArgs) Handles CheckBox1.MouseLeave
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseLeave")
End Sub

Private Sub CheckBox1_MouseHover(ByVal sender As Object, ByVal e As
System.EventArgs) Handles CheckBox1.MouseHover
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseHover")
End Sub


Hope this helps
Jay

"Mick Doherty"
Hi Jay,

I can confirm Jeffs results. BM_GETSTATE always returns 0 or 8 (focused or
not_focused) and nothing else.

I tested your class out and IsPushed always returns False, although it
should definately give the results that you are expecting.

I prefer to use WndProc to Sendmessage but the result is the same either
way.

\\\
Dim m As Message
m = Message.Create(Handle, BM_GETSTATE, IntPtr.Zero, IntPtr.Zero)
WndProc(m)
Dim state As ButtonState = CType(m.Result.ToInt32(), ButtonState)
Return ((state And ButtonState.Pushed) = ButtonState.Pushed)
///

My System specs:
WindowsXP Pro SP2
VS2003

--
Mick Doherty
http://dotnetrix.co.uk/nothing.html


Jay B. Harlow said:
Jeff,
Lets back up to the beginning:

How are you defining, and when are you using SendMessage with BM_GETSTATE
& BST_PUSHED?

The following is a sample of a CheckBox that has an IsPushed property.

The IsPushed property returns true then the mouse is down & the control
has focus, in other words when the control is Pressed.

It uses BM_GETSTATE & SendMessage to check for the BST_PUSHED state. The
same code works for CheckBox, RadioButton, & Button class in .NET.

Remember under .NET an Integer is a 32bit value, while a Long is a 64bit
value. Defining the function with IntPtr as I did, ensures it will
continue working as expected in the 64-bit version of Windows. Also
remember that BM_GETSTATE returns a set of bit flags, you need to isolate
the specific bits you are interested in.

Public Class CheckBoxEx
Inherits CheckBox

Private Enum ButtonMessage As Integer
GetCheck = &HF0
SetCheck = &HF1
GetState = &HF2
SetState = &HF3
SetStyle = &HF4

Click = &HF5
GetImage = &HF6
SetImage = &HF7
End Enum

<Flags()> _
Private Enum ButtonState As Integer
UnChecked = &H0
Checked = &H1
Indeterminate = &H2
StateMask = &H3
Pushed = &H4
Focus = &H8
End Enum

Private Declare Auto Function SendMessage Lib "user32" (ByVal hWnd As
IntPtr, ByVal msg As ButtonMessage, ByVal wParam As IntPtr, ByVal lParam
As IntPtr) As IntPtr

Public ReadOnly Property IsPushed() As Boolean
Get
Dim rc As IntPtr
rc = SendMessage(Me.Handle, ButtonMessage.GetState,
IntPtr.Zero, IntPtr.Zero)
Dim state As ButtonState = CType(rc.ToInt32(), ButtonState)
Return ((state And ButtonState.Pushed) = ButtonState.Pushed)
End Get
End Property

End Class

Hope this helps
Jay

Jay,
Thanks for the suggestion. I tried using both the CheckBox and
RadioButton. Neither of them work because their Checked property is not
set until the user releases the left mouse button. If you create a
button, click it with the left mouse button and hold the mouse button
down you will see that the button stays "pushed down". The CheckChanged
event is not fired, OnClick event is not fired, and Checked property is
False until you release the mouse button. I am looking to be able to
tell when the button is actually depressed (pushed down)

I am doing my own painting on my button and want it to "push down" with
the button by offsetting it when the button is depressed. Currently the
button gets pushed down but what I painted on it does not.

Jeff


Jay B. Harlow [MVP - Outlook] wrote:
Jeff,
Have you considered using a CheckBox or RadioButton control with the
Appearance property set to Button?

This causes the CheckBox or RadioButton to look like a normal Button,
but
continue to function (toggle) as a CheckBox or RadioButton.

You can set the AutoCheck property of the CheckBox or RadioButton if
you
don't want them to stay down.

Hope this helps
Jay

Hello,
I am trying to find a way to tell if an .NET windows forms Button
(System.Windows.Forms.Button) is "depressed" (pushed down). For my
application, I can not use a check box control set to button style,
I
must use a System.Windows.Forms.Button. I can not find a way to
tell
when it is momentaraly pressed.

I tried calling the API SendMessage with the button handle and
BM_GETSTATE to get the state of the button. This will only return
when
the button has focus (BST_FOCUS). It will never return a result
with
BST_PUSHED even when the button is in fact pressed down.
Any ideas?
Jeff
 
M

Mick Doherty

I tried it in the OnPaint method and the OnMouseMove method.

Running your code has the same results. I get a lot of "Checkbox1_MouseX:
False" in the Output Window, never a True.

--
Mick Doherty
http://dotnetrix.co.uk/nothing.html


Jay B. Harlow said:
Mick,
Where are you using BM_GETSTATE? My IsPressed (ergo BM_GETSTATE) returns
True when called from the Control.MouseMove event when the mouse is down,
and the mouse did not leave the control. If you think about it, the
"button" is never really pressed otherwise.

Try the following:

Private WithEvents CheckBox1 As CheckBoxEx


Private Sub CheckBox1_MouseDown(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles CheckBox1.MouseDown
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseDown")
End Sub

Private Sub CheckBox1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles CheckBox1.MouseMove
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseMove")
End Sub

Private Sub CheckBox1_MouseUp(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles CheckBox1.MouseUp
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseUp")
End Sub

Private Sub CheckBox1_MouseEnter(ByVal sender As Object, ByVal e As
System.EventArgs) Handles CheckBox1.MouseEnter
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseEnter")
End Sub

Private Sub CheckBox1_MouseLeave(ByVal sender As Object, ByVal e As
System.EventArgs) Handles CheckBox1.MouseLeave
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseLeave")
End Sub

Private Sub CheckBox1_MouseHover(ByVal sender As Object, ByVal e As
System.EventArgs) Handles CheckBox1.MouseHover
Debug.WriteLine(CheckBox1.IsPushed, "CheckBox1_MouseHover")
End Sub


Hope this helps
Jay

"Mick Doherty"
Hi Jay,

I can confirm Jeffs results. BM_GETSTATE always returns 0 or 8 (focused
or not_focused) and nothing else.

I tested your class out and IsPushed always returns False, although it
should definately give the results that you are expecting.

I prefer to use WndProc to Sendmessage but the result is the same either
way.

\\\
Dim m As Message
m = Message.Create(Handle, BM_GETSTATE, IntPtr.Zero, IntPtr.Zero)
WndProc(m)
Dim state As ButtonState = CType(m.Result.ToInt32(), ButtonState)
Return ((state And ButtonState.Pushed) = ButtonState.Pushed)
///

My System specs:
WindowsXP Pro SP2
VS2003

--
Mick Doherty
http://dotnetrix.co.uk/nothing.html


Jay B. Harlow said:
Jeff,
Lets back up to the beginning:

How are you defining, and when are you using SendMessage with
BM_GETSTATE & BST_PUSHED?

The following is a sample of a CheckBox that has an IsPushed property.

The IsPushed property returns true then the mouse is down & the control
has focus, in other words when the control is Pressed.

It uses BM_GETSTATE & SendMessage to check for the BST_PUSHED state. The
same code works for CheckBox, RadioButton, & Button class in .NET.

Remember under .NET an Integer is a 32bit value, while a Long is a 64bit
value. Defining the function with IntPtr as I did, ensures it will
continue working as expected in the 64-bit version of Windows. Also
remember that BM_GETSTATE returns a set of bit flags, you need to
isolate the specific bits you are interested in.

Public Class CheckBoxEx
Inherits CheckBox

Private Enum ButtonMessage As Integer
GetCheck = &HF0
SetCheck = &HF1
GetState = &HF2
SetState = &HF3
SetStyle = &HF4

Click = &HF5
GetImage = &HF6
SetImage = &HF7
End Enum

<Flags()> _
Private Enum ButtonState As Integer
UnChecked = &H0
Checked = &H1
Indeterminate = &H2
StateMask = &H3
Pushed = &H4
Focus = &H8
End Enum

Private Declare Auto Function SendMessage Lib "user32" (ByVal hWnd As
IntPtr, ByVal msg As ButtonMessage, ByVal wParam As IntPtr, ByVal lParam
As IntPtr) As IntPtr

Public ReadOnly Property IsPushed() As Boolean
Get
Dim rc As IntPtr
rc = SendMessage(Me.Handle, ButtonMessage.GetState,
IntPtr.Zero, IntPtr.Zero)
Dim state As ButtonState = CType(rc.ToInt32(), ButtonState)
Return ((state And ButtonState.Pushed) = ButtonState.Pushed)
End Get
End Property

End Class

Hope this helps
Jay

Jay,
Thanks for the suggestion. I tried using both the CheckBox and
RadioButton. Neither of them work because their Checked property is not
set until the user releases the left mouse button. If you create a
button, click it with the left mouse button and hold the mouse button
down you will see that the button stays "pushed down". The CheckChanged
event is not fired, OnClick event is not fired, and Checked property is
False until you release the mouse button. I am looking to be able to
tell when the button is actually depressed (pushed down)

I am doing my own painting on my button and want it to "push down" with
the button by offsetting it when the button is depressed. Currently the
button gets pushed down but what I painted on it does not.

Jeff


Jay B. Harlow [MVP - Outlook] wrote:
Jeff,
Have you considered using a CheckBox or RadioButton control with the
Appearance property set to Button?

This causes the CheckBox or RadioButton to look like a normal Button,
but
continue to function (toggle) as a CheckBox or RadioButton.

You can set the AutoCheck property of the CheckBox or RadioButton if
you
don't want them to stay down.

Hope this helps
Jay

Hello,
I am trying to find a way to tell if an .NET windows forms Button
(System.Windows.Forms.Button) is "depressed" (pushed down). For my
application, I can not use a check box control set to button style,
I
must use a System.Windows.Forms.Button. I can not find a way to
tell
when it is momentaraly pressed.

I tried calling the API SendMessage with the button handle and
BM_GETSTATE to get the state of the button. This will only return
when
the button has focus (BST_FOCUS). It will never return a result
with
BST_PUSHED even when the button is in fact pressed down.
Any ideas?
Jeff
 
J

Jay B. Harlow [MVP - Outlook]

Mick,
Doh!

Unfortunately I removed one very important piece of the puzzle!

Public Sub New()
MyBase.FlatStyle = FlatStyle.System
End Sub

When I trimmed the class for posting I trimmed the constructor also (in
addition to some other logic that was not needed). Oops :-(


If you have FlatStyle = System, then Windows is handling the button state &
my IsPressed works as expected. However if you have FlatStyle = Standard
then .NET is handling the button state & my IsPressed does not work as
expected...

Hope this helps
Jay

"Mick Doherty"
I tried it in the OnPaint method and the OnMouseMove method.

Running your code has the same results. I get a lot of "Checkbox1_MouseX:
False" in the Output Window, never a True.
<<xnip>>
 
M

Mick Doherty

I see, in which case the following code works perfectly:
\\\
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If m.Msg = &HF Then 'WM_PAINT
Dim msg As Message
msg = Message.Create(Handle, &HF2, IntPtr.Zero, IntPtr.Zero)
WndProc(msg)
If CBool(msg.Result.ToInt32 And &H4) Then Debug.WriteLine("Pushed")
End If
End Sub
///
....but does not help.
The reason for getting the state of the button is so that we can correctly
paint it. We cannot paint System buttons, and when not set to
Flatstyle.System we cannot use BM_GETSTATE.

We'll just have to stick to the long winded method that I use in the example
on my site.
 
J

Jay B. Harlow [MVP - Outlook]

Mick,
IMHO this is an excellent example of where one gets burned for relying on an
implementation detail. We are attempting to reply on the fact that Button is
implemented as a Win32 button, when apparently it is not, worse sometimes it
is & sometimes is isn't...
We'll just have to stick to the long winded method that I use in the
example on my site.
I haven't looked, I wonder if .NET 2.0 (VS.NET 2005, aka Whidbey, due out
later in 2005) adds a Pressed property to ButtonBase... For details on
VS.NET 2005 see http://lab.msdn.microsoft.com/vs2005/

If you haven't you may want to submit a feature request on the above site,
it might be too late for .NET 2.0 (then again it may not be), but if its on
the list it may make .NET 3.0.

As I stated in my project where I needed "custom buttons" I did not derive
from Button...

Hope this helps
Jay

"Mick Doherty"
 
J

jrhoads23

Jay said:
Mick,
Where are you using BM_GETSTATE? My IsPressed (ergo BM_GETSTATE) returns
True when called from the Control.MouseMove event when the mouse is down,
and the mouse did not leave the control. If you think about it, the "button"
is never really pressed otherwise.

Jay,
Thanks for the info but a button still can be "pressed" without
clicking on it. If the button has focus and the user presses the space
bar, the button is "pushed down" and goes back up when the user
releases the space bar. So just handling the Control.MouseMove will not
cut it because it will not handle this case. So it is another "gotcha"
in all of this because you now need to also track the space bar state
combined with if the button has focus.

This has been a great thread. I did not know that if you set the button
to be FlatStyle = System, then you can get the Pushed state, but like
someone mentioned, you can not paint it then.

So here is where I am at. If I want to be able to paint the button I
will have to use option 1.
Option 1) Subclass the System.Windows.Forms.Button (FlatStyle =
Standard) and manually keep track of mouse position, mouse clicks,
space bar pressed state, focus, ... This can be done but there are many
things to watch for (for example, if you mouse click on a button, hold
the mouse button down, and drag off the button - the button pops back
up. If you keep the mouse button down and drag back over the button, it
goes back down. If you release the mouse at any time, anywhere on the
screen, the button comes back up)

If I want to be able to tell the pushed state of the button I will have
to go with option 2 which is just no be able to paint the button (which
then the Pushed state does me no good)
Am I missing any other options? Looks like it will be #1.

Jeff
 
J

Jay B. Harlow [MVP - Outlook]

Jeff,
Thanks for the info but a button still can be "pressed" without
clicking on it. If the button has focus and the user presses the space
bar, the button is "pushed down" and goes back up when the user
True, you can use the keyboard to "press" the button also...
If I want to be able to tell the pushed state of the button I will have
to go with option 2 which is just no be able to paint the button (which
then the Pushed state does me no good)
Am I missing any other options? Looks like it will be #1.
That's the extent of my understanding...

Hope this helps
Jay
 
M

Mick Doherty

I agree with you there. I wont be making a feature request though since I
already have the Button Class behaving as I would like it. I have
implemented a ButtonDrawState property and only need to supply new paint
methods if I decide to change the appearance.

Most of the wrapped WIN32 controls are broken in some way or another.

When I first decided to modify the button class I was surprised to find that
there was not a ButtonState property passed in to the paint eventhandler. I
expected it to be similar to the Menus paint eventhandler which has e.State.
After all, we quite clearly need to know the state of the button in order to
draw it. We really should not need to rely on InterOp to handle the basic
functions of a control, but in this case, even InterOp was not a help.
 
M

Mick Doherty

Option1 is the solution. As I said earlier I have already done it and the
source is available on my site. Just supply your own paint methods and query
the ButtonDrawState property that I implemented.
 
A

alejandro lapeyre

"Mick Doherty" >
Most of the wrapped WIN32 controls are broken in some way or another.
I think that is because of Microsoft has a good reputation on keeping things
downward compatible. In this case, beeing compatible with VB5 errors in this
area.

(Rembember Common Control Replacement Project?)

:)

Alejandro Lapeyre
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top