Click here to Skip to main content
15,891,902 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Hello everybody.
My application is a C# on VS 2005.I creat a small program for a test only with two buttons.I need to handle "KeyPress Event" on arrow keys on keyboard(left,right,up,down),but when I press this buttons application only change the focus of the buttons.
I want to handle this event and when press and hold some of this buttons to change the location on the component (for example) not to change the focus of them.How to solve the problem?

Thanks in advance.
Posted

edit ... October 14 ...

Code I posted on the C# forum after I wrote this response that will allow you to handle arrow-keys, keeping a Control inside the borders of a specific ContainerControl: [^]

... end edit ...

It is not clear to me exactly what you wish to move in response to arrow-key Events if a Button has been clicked (or, did you mean while a Button is pressed ?), but your code to handle arrow-key Events has to know which Control on the Form to move.

If you define a KeyDown EventHandler for a Button, it will only handle arrow-keys if a modifier key, like <Control>, is held down. A KeyPress EventHandler will not handle arrow-key events.

To get arrow-key Events in WinForms without a modifier key held down, you'll need to use an over-ride of the ProcessCmdKey method, and that will apply to the Form as a whole. Or, you can get into using PInvoke and the Windows API to get those key Events at a "lower level."

The idea of using a Button as the "sink" for key Events is very unusual, and I think not a good design decision.

Here's a solution idea which could move any Control on the Form that has Focus, but it does require a modifier key, like <Control> held down to work.

1. set the 'KeyPreview property of the Form in the design-time Property Grid to 'true.

2. write a KeyDown Event Handler:
C#
private void FormTemplate_KeyDown(object sender, KeyEventArgs e)
{
    // if we don't filter out repeats of the <control> Key 
    // there will be a flood of them while the key is held down
    if (e.KeyCode == Keys.Control) return;

    Control controlToMove = ActiveControl;

    // use for testing: requires a TextBox, 'textBox1 on the Frm
    //textBox1.Text +=
        //"ActiveControl: " + controlToMove.Name
        //+ " KeyCode: " + e.KeyCode.ToString()
        //+ " KeyData: " + e.KeyData.ToString()
        //+ " KeyValue: " + e.KeyValue.ToString()
        //+ Environment.NewLine;

    switch (e.KeyCode)
    {
        case Keys.Left:
            controlToMove.Left -= 1;
            break;
        case Keys.Right:
            controlToMove.Left += 1;
            break;
        case Keys.Up:
            controlToMove.Top -= 1;
            break;
        case Keys.Down:
            controlToMove.Top += 1;
            break;
    }
}</control>
Now, if you use this you may be surprised: some of the Controls on a Form that it might be most desirable to move are Container Controls, like Panels. A Panel never becomes the ActiveControl on a Form.

So, if you want to make this solution more "robust," and handle moving something like a Panel, you are going to have to come up with a way for the Form scoped KeyDown EventHandler to "know" which Panel, or other Container Control, it needs to move.

You might think you can simply use the 'GetChildAtPoint method of the Form:
C#
Control controlToMove;

private void FormTemplate_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Control || ActiveControl == null) return;

    controlToMove = this.GetChildAtPoint(this.PointToClient(MousePosition));

    if (controlToMove == null) return;

    switch (e.KeyCode)
    {
        case Keys.Left:
            controlToMove.Left -= 1;
            break;
        case Keys.Right:
            controlToMove.Left += 1;
            break;
        case Keys.Up:
            controlToMove.Top -= 1;
            break;
        case Keys.Down:
            controlToMove.Top += 1;
            break;
    }
}
Well, now you can move Panels, but you have another problem: Controls inside Panels that you click on and select will not move, but their containing Panel will. This is an artifact of the way that 'GetChildAtPoint works (or, from my point of view, doesn't work).

So, to really make this a robust solution, you need to find a way to get any Control or Container Control inside any arbitrary number of Container Controls set as the "target" of your Form scoped arrow-key EventHandler.

A cheap way to get around this is: at design-time is to select all Controls on the Form, and define a Click EventHandler they all share:
C#
private void AllControls_Click(object sender, EventArgs e)
{
    controlToMove = sender as Control;
}
And, make sure that a click on the Form "resets" arrow-key event handling:
C#
private void SomeForm_Click(object sender, EventArgs e)
{
    controlToMove = null;
}
. Well, "cheap" does not equal "elegant," but, it works.

And now, after all this, the question remains in my mind: is it really a good thing to have run-time moving of Controls in this way. My "gut" says: "no," unless it's some very special circumstance. imho, what's demonstrated here is too much work :)

There are, after all, other standard ways of enabling Controls to move at run-time, via MouseDown, MouseMove, MouseUp; you can even put up a PropertyGrid Control at run-time and let the user edit the pixel locations of Controls.

How often do you really need to move every Control on a Form at run-time ?
 
Share this answer
 
v2
Comments
t_nedelchev 9-Oct-13 8:54am    
Sorry It's my mistake.I do not explain very well what want to do but your soluition work.Thanks a lot.
In addition:
In my application a have a picture box and add array of cantrols(at the moment labels).I want to move selected label.Now use the mouse to drag and move the labels but I want to add moving the selected label using arrow keys(left,right,up,down).Is there any way to do this without modifier key, <control>
BillWoodruff 9-Oct-13 12:05pm    
Glad you found something useful in my response.

Reality check: the Labels you want to move with the arrow-keys are in the same ContainerControl (Form, Panel, GroupBox, etc.) as the PictureBox ?

And, do you wish to make sure the run-time user can only move a Label within the Bounds of the PictureBox ?

edit #1:

How important to you is it to use Labels ? The reason I ask is that Labels are designed not to receive keyboard Events. However, you can make Labels get keyboard Events with some over-rides: what you have to do is a bit of a hack.

Have you thought about using bitmaps, or icons, instead of Labels; perhaps in different shapes and colors ?

edit: #2

It turns out there are some very interesting aspects of making Labels work in the way you want; figuring it out has taught me something ... although I'm not sure I'll use what I've learned in the future. So, I have up-voted your question.

Is what you really want for the end-user to be able to do something at run-time to create new Labels, edit existing ones, delete existing ones ?

Of interest ... if you implemented a scrolling view of an Image in a PictureBox by putting it in a Panel and doing the usual ... is what you would want to do with your Labels when the image was scrolled: that would get tricky, although I'm sure it's do-able.
t_nedelchev 10-Oct-13 4:45am    
I'm sorry to bother you but I am grateful for helping me.What do you think is the most elegant solution for the following:
In Form have a Picturebox (constant size not scrollable) add an image into.I want to add array of controls no matter what look like a circle (the selected will be with different color).I want to end user can move this controls.Now using class moving the controls by mouse, bounds into picturebox and draw a line betwin controls.I want to add using arrow keys(without modifier key Ctrl) left, right to change the selected control and up down to move selected controls.After end moving I take the coordinates of the moved control.Now when I press Arrow keys without modifier the program change the selected controls(do not want to do this).
BillWoodruff 10-Oct-13 5:38am    
If I understand what your design is ... and I'm not sure I do ... that sounds like a lot of work ! Getting the arrow-keys to work only on a selected Control on a Form is tricky: you are going to need to override ProcessCmdKey. It's even more difficult for a Label Control because the Label Control, like the PictureBox, by design does not handle key events.

When a Form has something on it like a TreeView, getting the TreeView not to respond to key events is difficult even though you have not defined any key EventHandlers for the TreeView !

Check this out: http://mike-caron.com/2010/07/dude-wheres-my-arrow-key/

For drawing shapes and connecting lines on a Form you might consider using the Shape facility found in VB, which you can use in C# by referencing the VB library. Search CodeProject and you'll find some articles on that.

http://msdn.microsoft.com/en-us/library/system.windows.shapes.shape.aspx

If you create connecting lines by drawing in C# you may have some problems with flickering, and the lines themselves will not be "clickable" objects.
Take a look at similar questions posted here. This thread contains several useful tips: capture all keyboard key including[^].
 
Share this answer
 
Comments
BillWoodruff 9-Oct-13 21:32pm    
fyi: the link to the MSDN thread cited in your Sept. 13 post is specifically for WPF. I believe, but am not absolutely certain, that the OP here is using WinForms. There are some tricky issues in getting Labels in WinForms to process key Events like the arrow-keys: multiple method over-rides required.
V.Lorz 10-Oct-13 1:42am    
Thanks for noting that.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900