none
Multiple Forms and KeyDown Event RRS feed

  • Question

  • Working with Multiple Forms to try and make a game menu. First few forms work on mouse click to move through, third using key down event to move box around in.

    The key down event as written works in a single form, but not in the hierarchy of forms  - can anyone advise please?

    Sunday, January 7, 2018 12:45 AM

Answers

  •  Try using the ProcessCmdKey overrides function of the Play form to handle the Arrow keys.  This will work to move the PictureBox no mater what control on the form has focus.  It will also stop the Arrow keys from iterating through the controls.  However,  the Tab and Shift+Tab keys can still be used to do that.

     As i said in my last post,  the Arrow keys are used by the Form as command keys.  They are used to shift focus forward or backward through the controls on the form.  So,  even if you keep setting focus back to the PictureBox,  every time you press an Arrow key it will shift focus back to another control,  your Back Button. 

     Try it just like this,  i believe it will work for your situation...

    Public Class Play
        Private Sub Back_Click(sender As Object, e As EventArgs) Handles Back.Click
            Me.Hide()
            FirstMenu.Show()
        End Sub
    
        Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
            If keyData = Keys.Up Then
                PictureBox1.Top = PictureBox1.Top - 10 'up
                Return True 'returning True tells the form not to process this key, you have processed it
            End If
            If keyData = Keys.Down Then
                PictureBox1.Top = PictureBox1.Top + 10 'down
                Return True
            End If
            If keyData = Keys.Left Then
                PictureBox1.Left = PictureBox1.Left - 10 'left
                Return True
            End If
            If keyData = Keys.Right Then
                PictureBox1.Left = PictureBox1.Left + 10 'right
                Return True
            End If
    
            Return MyBase.ProcessCmdKey(msg, keyData)
        End Function
    End Class


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, January 7, 2018 1:46 PM
    • Marked as answer by CrazyMum123 Sunday, January 7, 2018 1:50 PM
    Sunday, January 7, 2018 1:24 PM

All replies

  •  It is not real clear what your saying the problem is....  Do you want a few different forms to all detect a key being pressed even if some are in the background,  or is it that you have several forms and want whichever one has focus to use the KeyXxx methods.  Also, is it the same key that all the forms should detect or different keys for different forms?

     Also,  the one it is moving a 'Box' around in,  is it suppose to be continuous movement or should it only move once each time the key is pressed.

     There are different ways to handle different scenarios so,  you may need to use more than one method.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, January 7, 2018 11:33 AM corrected spelling
    Sunday, January 7, 2018 1:09 AM
  • I hope you can clarify your requirements soon. I have seen many vague questions cause a big discussion from members speculating about what the person might need.

    One thing to understand is that the key down and up events and related events need a control that has the focus.



    Sam Hobbs
    SimpleSamples.Info

    Sunday, January 7, 2018 3:07 AM
  • Handling event is in fact doing actions after receiving a wm_message from the OS. That name message did exist even before Internet. The problem comes now, that because of the name "message" you cannot find anything about it on Internet. 

    However, the OS broadcast a message which can be received by active forms. This message is only very short available. That is why more modeless forms are probably so seldom used. Therefore are MDI and Modal forms. A solution. Yea this problem exist with modeless forms since 1990. 

    There was a long thread a week ago from somebody who claimed there was a solution, which this forum must give. A pity, the thread became only longer and longer.  


    Success Cor


    Sunday, January 7, 2018 8:58 AM
  • Hopefully, this clarifies - I am just really trying to play with forms and create a basic menu I can build on. My first menu code is as below. At present Story and instructions menu just hold placeholder text boxes and a return to the menu button. My play menu code is as shown. I want to simply move the icon around the panel using arrow keys. the code works in isolation but not in the menu structure.

    Public Class Play
        Private Sub Back_Click(sender As Object, e As EventArgs) Handles Back.Click
            Me.Hide()
            FirstMenu.Show()
        End Sub
    
        Private Sub Play_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
            If e.KeyCode = Keys.Up Then
                PictureBox1.Top = PictureBox1.Top - 10 'up
    
            End If
            If e.KeyCode = Keys.Down Then
                PictureBox1.Top = PictureBox1.Top + 10 'down
            End If
            If e.KeyCode = Keys.Left Then
                PictureBox1.Left = PictureBox1.Left - 10 'left
    
            End If
            If e.KeyCode = Keys.Right Then
                PictureBox1.Left = PictureBox1.Left + 10 'right
            End If
        End Sub
    
        Private Sub Play_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        End Sub
    
    
    
        Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
    
        End Sub
    End Class


        Private Sub Story1_Click(sender As Object, e As EventArgs) Handles Story1.Click
            Me.Hide()
            Story.Show()
        End Sub
    
        Private Sub Instructions1_Click(sender As Object, e As EventArgs) Handles Instructions1.Click
            Me.Hide()
            Instructions.Show()
        End Sub
    
        Private Sub Play1_Click(sender As Object, e As EventArgs) Handles Play1.Click
            Me.Hide()
            Play.Show()
        End Sub
    
        Private Sub Quit_Click(sender As Object, e As EventArgs) Handles Quit.Click
            End
        End Sub
    End Class

    many thanks


    • Edited by CrazyMum123 Sunday, January 7, 2018 11:58 AM
    Sunday, January 7, 2018 11:56 AM
  • ....I want to simply move the icon around the panel using arrow keys. the code works in isolation but not in the menu structure.


     I am still not sure what you mean by the underlined part of the quote above,  or what the actual problem you are having is.

     Is your 'menu structure' just Button controls or are they actually MenuItems in a MenuStrip or ToolStrip control?

     Are you asking how to activate/press these buttons when the Menu Form has focus and specific keys are pressed?  For example,  if the menu form is focused and you press the "P" or "Ctrl+P" keys,  it would activate the Play button.

     Are you asking why the keys don't work to move the 'icon' when you have set focus to a button or menu item?


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, January 7, 2018 12:48 PM
    Sunday, January 7, 2018 12:38 PM
  • One thing to understand is that the key down and up events and related events need a control that has the focus.



    Sam Hobbs
    SimpleSamples.Info

    I agree.

    Perhaps Mum needs to set focus to the picturebox for the keypress event. Perhaps this event (or other method) can be used:

        Private Sub PictureBox1_MouseEnter(sender As Object, e As EventArgs) Handles PictureBox1.MouseEnter
            PictureBox1.Focus()
    
        End Sub
    

    Depends on all the details.

    Sunday, January 7, 2018 12:39 PM
  • Not sure I did this correctly but tried integrating into my code - still doesn't work - see attached

    ublic Class Play
        Private Sub Back_Click(sender As Object, e As EventArgs) Handles Back.Click
            Me.Hide()
            FirstMenu.Show()
        End Sub
    
        Private Sub PictureBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles PictureBox1.KeyDown
            PictureBox1.Focus()
        End Sub
    
        Private Sub Play_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
            If e.KeyCode = Keys.Up Then
                PictureBox1.Top = PictureBox1.Top - 10 'up
    
            End If
            If e.KeyCode = Keys.Down Then
                PictureBox1.Top = PictureBox1.Top + 10 'down
            End If
            If e.KeyCode = Keys.Left Then
                PictureBox1.Left = PictureBox1.Left - 10 'left
    
            End If
            If e.KeyCode = Keys.Right Then
                PictureBox1.Left = PictureBox1.Left + 10 'right
            End If
        End Sub
    
    
        Private Sub Play_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        End Sub
    
    
    
        Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
    
        End Sub
    End Class
    

    Sunday, January 7, 2018 12:55 PM
  • Not sure I did this correctly but tried integrating into my code - still doesn't work - see attached

    ublic Class Play
        Private Sub Back_Click(sender As Object, e As EventArgs) Handles Back.Click
            Me.Hide()
            FirstMenu.Show()
        End Sub
    
        Private Sub PictureBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles PictureBox1.KeyDown
            PictureBox1.Focus()
        End Sub
    
        Private Sub Play_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
            If e.KeyCode = Keys.Up Then
                PictureBox1.Top = PictureBox1.Top - 10 'up
    
            End If
            If e.KeyCode = Keys.Down Then
                PictureBox1.Top = PictureBox1.Top + 10 'down
            End If
            If e.KeyCode = Keys.Left Then
                PictureBox1.Left = PictureBox1.Left - 10 'left
    
            End If
            If e.KeyCode = Keys.Right Then
                PictureBox1.Left = PictureBox1.Left + 10 'right
            End If
        End Sub
    
    
        Private Sub Play_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        End Sub
    
    
    
        Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
    
        End Sub
    End Class

    You added a keydown event. Look at my example closely it is the mouseenter event for the picturebox. The keydown event will not fire if the picturebox does not have focus.

    As Razerz mentions, if you click a button the focus will go to the button and now the keydown event for the picturebox will not fire.

    Sunday, January 7, 2018 1:06 PM
  • You are using the KeyDown events of the Form,  not the KeyDown event of the PictureBox so,  setting focus to the PictureBox will not do anything as far as i can see.  If the play form is the foreground window and has focus,  then the form should detect the keys.  You just need to make sure you have set the Play form's KeyPreview property to True.

        Private Sub Play_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            KeyPreview = True
        End Sub

      If you have other controls on the form besides just a PictureBox,  then you will need to use other methods to detect the Arrow keys.  They are a command key which is used by the form to iterate through controls.


    If you say it can`t be done then i`ll try it


    • Edited by IronRazerz Sunday, January 7, 2018 1:41 PM
    Sunday, January 7, 2018 1:09 PM
  • You are using the KeyDown events of the Form,  not the KeyDown event of the PictureBox so,  setting focus to the PictureBox will not do anything as far as i can see.  If the play form is the foreground window and has focus,  then the form should detect the keys.  You just need to make sure you have set the Play form's KeyPreview property to True.

        Private Sub Play_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            KeyPreview = True
        End Sub

      If you have other controls on the form besides just a PictureBox,  then you will need to use other methods to detect the Arrow keys.  They are a control key which is used by the form to iterate through controls.


    If you say it can`t be done then i`ll try it


    Oh yeah. I did not notice. Mum, you need to use the picturebox keydown event in this case if you are using the picturebox focus.

    So which events to use depends on the relationship of the child and parents of the forms and controls.

    PS Perhaps you should start from the start and explain how you arrived at what you do and why you are using multiple forms for a menu etc?

    You can do it either way I suppose. Use the form key events or the control. Depends... but whichever the event must match the control that has the focus.


    PS like this. However if you are jumping all over you may need to use the form events like Razerz shows.

    Public Class Play
            Private Sub Back_Click(sender As Object, e As EventArgs) Handles Back.Click
                Me.Hide()
                FirstMenu.Show()
            End Sub
    
            Private Sub PictureBox1_MouseEnter(sender As Object, e As EventArgs) Handles PictureBox1.MouseEnter
                PictureBox1.Focus()
            End Sub
    
            Private Sub PictureBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles PictureBox1.KeyDown
                If e.KeyCode = Keys.Up Then
                    PictureBox1.Top = PictureBox1.Top - 10 'up
    
                End If
                If e.KeyCode = Keys.Down Then
                    PictureBox1.Top = PictureBox1.Top + 10 'down
                End If
                If e.KeyCode = Keys.Left Then
                    PictureBox1.Left = PictureBox1.Left - 10 'left
    
                End If
                If e.KeyCode = Keys.Right Then
                    PictureBox1.Left = PictureBox1.Left + 10 'right
                End If
            End Sub
        End Class


    PS I guess I am confused on what exactly is happening.

    Sunday, January 7, 2018 1:18 PM
  •  Try using the ProcessCmdKey overrides function of the Play form to handle the Arrow keys.  This will work to move the PictureBox no mater what control on the form has focus.  It will also stop the Arrow keys from iterating through the controls.  However,  the Tab and Shift+Tab keys can still be used to do that.

     As i said in my last post,  the Arrow keys are used by the Form as command keys.  They are used to shift focus forward or backward through the controls on the form.  So,  even if you keep setting focus back to the PictureBox,  every time you press an Arrow key it will shift focus back to another control,  your Back Button. 

     Try it just like this,  i believe it will work for your situation...

    Public Class Play
        Private Sub Back_Click(sender As Object, e As EventArgs) Handles Back.Click
            Me.Hide()
            FirstMenu.Show()
        End Sub
    
        Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
            If keyData = Keys.Up Then
                PictureBox1.Top = PictureBox1.Top - 10 'up
                Return True 'returning True tells the form not to process this key, you have processed it
            End If
            If keyData = Keys.Down Then
                PictureBox1.Top = PictureBox1.Top + 10 'down
                Return True
            End If
            If keyData = Keys.Left Then
                PictureBox1.Left = PictureBox1.Left - 10 'left
                Return True
            End If
            If keyData = Keys.Right Then
                PictureBox1.Left = PictureBox1.Left + 10 'right
                Return True
            End If
    
            Return MyBase.ProcessCmdKey(msg, keyData)
        End Function
    End Class


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, January 7, 2018 1:46 PM
    • Marked as answer by CrazyMum123 Sunday, January 7, 2018 1:50 PM
    Sunday, January 7, 2018 1:24 PM
  • Thank you - this works perfectly. Can I be a real nuisance and ask you to explain the code as I understand now that the problem is I have multiple controls on the form and that it is iterating through them all when I use arrow keys and that this is somehow restricting this, but other than that I am a little confused?
    Sunday, January 7, 2018 1:54 PM
  •  PS - As a side note...  for games it is much better to draw all your images onto the form or even a single Panel or single Picturebox.  I have a small working example of doing this at the link below if you care to look at it.

    Drawing and moving a game sprite image on a form


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, January 7, 2018 2:04 PM
    Sunday, January 7, 2018 1:59 PM
  • Hi Ray and Tommy,

    I never use modeless forms. However, your message made me clear why I never understood when it was sometimes going and sometimes not. 

    If you press a button the form becomes active.

    Thanks guys from this dummy,


    Cor



    Sunday, January 7, 2018 2:06 PM
  • Thank you - this works perfectly. Can I be a real nuisance and ask you to explain the code as I understand now that the problem is I have multiple controls on the form and that it is iterating through them all when I use arrow keys and that this is somehow restricting this, but other than that I am a little confused?

     You can start by reading the Msdn documents on the ProcessCmdKey function at the link below.  See the Remarks section.

    Control.ProcessCmdKey Method

     This function is called every time the form receives a WM_KEYDOWN or WM_SYSKEYDOWN Message no mater what control on the form has focus.  It is used for determining which keys are used by the form for command keys such as the Arrow keys,  Tab keys,  and accelerator keys.  It gives you access to actually stop the form from processing the command keys or any other keys by returning True or False when the key you want to handle yourself is sent in the (keyData) parameter.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, January 7, 2018 5:09 PM
    Sunday, January 7, 2018 2:42 PM
  • I had originally planned to move the emoji in my example around until I reached an open door icon, and was intending to use a simple if statement at the end of my key down code to create a message box to say game over when PictureBox1.location = PictureBox2.location. I cannot get this to work on the function code and am not sure where else it might work from. Can you advise, please ?

    Public Class Play
        ' Private Sub Back_Click(sender As Object, e As EventArgs) Handles Back.Click
        'Me.Hide()
        '   FirstMenu.Show()
        'End Sub
        Dim keydata As Keys
    
    
    
        Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keydata As Keys) As Boolean
            If keydata = Keys.Up Then
    
    
                PictureBox1.Top = PictureBox1.Top - 10 'up
                Return True
            Else
                If keydata = Keys.Down Then
                    PictureBox1.Top = PictureBox1.Top + 10 'down
                    Return True
                Else
                    If keydata = Keys.Left Then
                        PictureBox1.Left = PictureBox1.Left - 10 'left
                        Return True
                    Else
    
                        If keydata = Keys.Right Then
                            PictureBox1.Left = PictureBox1.Left + 10 'right
                            Return True
    
                        End If
                    End If
                End If
            End If
            If PictureBox1.Location = PictureBox2.Location Then
                MsgBox("Gane Over")
            End If
    
            ' End Sub
    
            Return MyBase.ProcessCmdKey(msg, keydata)
        End Function
    
        Private Sub Play_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            KeyPreview = True
        End Sub
    
    
    
        Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
    
        End Sub
    
        Private Sub Maze_MouseClick(sender As Object, e As MouseEventArgs) Handles Maze.MouseClick
            MsgBox("game over")
        End Sub
    
        Private Sub Solution_MouseClick(sender As Object, e As MouseEventArgs) Handles Solution.MouseClick
            MsgBox(" show soln")
        End Sub
    
        Private Sub Back_MouseClick(sender As Object, e As MouseEventArgs) Handles Back.MouseClick
            MsgBox("main menu")
        End Sub
    End Class
    


    Sunday, January 7, 2018 3:20 PM
  •  Perhaps try using the PictureBox1.LocationChanged event.  It would also be better to check if the PictureBox1.Bounds intersects with PictureBox2.Bounds.  The way you are checking it,  the location of PictureBox1 would have to be exactly the same as PictureBox2.Location which is probably not going to happen depending on the starting location of both PictureBoxes.

     For example,  if PictureBox1 started at (10,10) and PictureBox2 started at (22, 10),  and you are moving PictureBox1 in increments of 10 pixels at a time....  figure out what happens if you moved PictureBox1 once to the right,  it would be at (20,10).  Then if you moved it again to the right,  it would be at (30,10).  So,  you can see that it would never be at (22,10) which is the location of PictureBox2.

     Using the PictureBox1.Bounds.IntersectsWith method will detect if PictureBox1 is actually touching or overlapping any part of PictureBox2.  For example...

    Public Class Form1
        Private Sub PictureBox1_LocationChanged(sender As Object, e As EventArgs) Handles PictureBox1.LocationChanged
            If PictureBox1.Bounds.IntersectsWith(PictureBox2.Bounds) Then
                MessageBox.Show("Game Over!!!")
            End If
        End Sub
    
        Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
            If keyData = Keys.Up Then
                PictureBox1.Top = PictureBox1.Top - 10 'up
                Return True 'returning True tells the form not to process this key, you have processed it
            End If
            If keyData = Keys.Down Then
                PictureBox1.Top = PictureBox1.Top + 10 'down
                Return True
            End If
            If keyData = Keys.Left Then
                PictureBox1.Left = PictureBox1.Left - 10 'left
                Return True
            End If
            If keyData = Keys.Right Then
                PictureBox1.Left = PictureBox1.Left + 10 'right
                Return True
            End If
    
            Return MyBase.ProcessCmdKey(msg, keyData)
        End Function
    End Class
     

     I would not recommend showing MessageBox's from inside the ProcessCmdKey overrides function.  MessageBoxes will stop the code from executing any further until the MessageBox is closed.

     

     Also,  you do not need to declare a variable as keyData,  that is a parameter that is inside the ProcessCmdKey function.  Get rid of this line...

    Dim keydata As Keys

     

     Also,  you do not need to set the KeyPreview property of the form to true.  That is only used for the KeyXxxx events and is not needed for the ProcessCmdKey function.  So,  you can get rid of this event too.

        Private Sub Play_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            KeyPreview = True
        End Sub

     

     


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, January 7, 2018 3:58 PM
    Sunday, January 7, 2018 3:50 PM
  • Handling event is in fact doing actions after receiving a wm_message from the OS. That name message did exist even before Internet. The problem comes now, that because of the name "message" you cannot find anything about it on Internet. 

    I first learned Windows and Windows programming when I was asked to write a Windows device driver back when the internet was not available for getting help. I think I can find the relevant documentation of the keyboard messages but I have the advantage of being familiar with the classic Windows API.

    That is why more modeless forms are probably so seldom used. Therefore are MDI and Modal forms.

    A modeless form is very much like most main windows of Windows applications. Modeless forms work more like main frame windows than modal forms.

    There was a long thread a week ago from somebody who claimed there was a solution, which this forum must give. A pity, the thread became only longer and longer.

    A member took it personally when I said that threads sometimes get large like that. I however know it happens.



    Sam Hobbs
    SimpleSamples.Info

    Sunday, January 7, 2018 7:01 PM
  •  Try using the ProcessCmdKey overrides function of the Play form to handle the Arrow keys. 

    I think the ProcessCmdKey method is like the MFC PreTranslateMessage method. Fifteen years ago I wrote Processing Keyboard Messages because so many CodeGuru members were suggesting using the PreTranslateMessage method and I wanted to document alternative solutions that are object-oriented.

    Since this response is accepted as an answer I won't bother suggesting something else but for the benefit of others I think this is not the technique that Microsoft would suggest. It is not object-oriented because the ProcessCmdKey method is used to process messages intended for children of the form. Sometime that is necessary but it is best to minimize doing that as much as possible.



    Sam Hobbs
    SimpleSamples.Info

    Sunday, January 7, 2018 8:17 PM
  • Since this response is accepted as an answer I won't bother suggesting something else ....

     Please do since i don't seem to understand as well as a professional like you,  how windows messages work.

    If you say it can`t be done then i`ll try it

    Sunday, January 7, 2018 8:53 PM
  • The problem is that the requirements are so unclear. Look at the initial question; it is so vague. I prefer to not spend much time on something unless I understand what the requirements are. Sometimes I can guess and I think I am pretty good at guessing but if I don't think I have a good guess then I try to get clarification first. My guess is that I would have a good suggestion if I understood the requirements adequately.

    I will try to analyze what has been posted to determine what the requirements are.



    Sam Hobbs
    SimpleSamples.Info

    Monday, January 8, 2018 6:20 AM
  • Okay, I apologize. This is probably the way to do it. I still don't understand what the intent is and that is why I did not look as this as closely as I should have.


    Sam Hobbs
    SimpleSamples.Info

    Monday, January 8, 2018 6:17 PM
  •  "My last post before this one was intended to be an apology; people should not take advantage of a person apologizing."

     Well,  it is probably to late now but,  i will apologize for my last post.  For some reason I did not refresh the page before i started typing that post and did not even see you had apologized until just now.  So,  i will say sorry and hope that we can start off on a better foot the next time we run into each other.  I am not hard to get along with.  8)

     PS - I am deleting my last post too.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Monday, January 8, 2018 8:24 PM
    Monday, January 8, 2018 8:21 PM
  • I believe you that you are a nice person and don't make trouble.


    Sam Hobbs
    SimpleSamples.Info

    Monday, January 8, 2018 8:44 PM