Forms.Panel and the KeyUp event (message)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • sklett

    Forms.Panel and the KeyUp event (message)

    I know that Panel (and most of it's derivitives) don't raise keyboard
    events. I *really* need to catch keyboard events though so I've been
    googling the topic and have found quite a few suggestions. The one
    suggestion I've found that makes the most sense isn't working for me and
    after this most recent failure I'm really at a loss! ;0)

    I'm overriding WndProc and checking the Message.Msg property for the
    WM_KEYUP message.

    If anyone has any ideas for me I would really appreciate it!


    Here is a complete application that shows the failure.

    <code>
    using System;
    using System.Collecti ons.Generic;
    using System.Windows. Forms;

    namespace PanelKeyEventEx ample
    {
    public class Form1 : Form
    {
    public Form1()
    {
    InitializeCompo nent();
    }

    private MyPanel panel1;

    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.Componen tModel.IContain er components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing ">true if managed resources should be
    disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
    if (disposing && (components != null))
    {
    components.Disp ose();
    }
    base.Dispose(di sposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeCompo nent()
    {
    this.panel1 = new MyPanel();
    this.SuspendLay out();
    //
    // panel1
    //
    this.panel1.Loc ation = new System.Drawing. Point(46, 49);
    this.panel1.Nam e = "panel1";
    this.panel1.Siz e = new System.Drawing. Size(200, 100);
    this.panel1.Tab Index = 0;
    //
    // Form1
    //
    this.AutoScaleD imensions = new System.Drawing. SizeF(6F, 13F);
    this.AutoScaleM ode = System.Windows. Forms.AutoScale Mode.Font;
    this.ClientSize = new System.Drawing. Size(292, 266);
    this.Controls.A dd(this.panel1) ;
    this.Name = "Form1";
    this.Text = "Form1";
    this.ResumeLayo ut(false);
    }

    #endregion
    }

    static class Program
    {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
    Application.Ena bleVisualStyles ();
    Application.Set CompatibleTextR enderingDefault (false);
    Application.Run (new Form1());
    }
    }

    public class MyPanel : Panel
    {
    const int WM_KEYUP = 0x0101;

    protected override void WndProc(ref Message m)
    {
    if (m.Msg == WM_KEYUP)
    {
    Console.WriteLi ne("KeyUp message caught");
    }

    base.WndProc(re f m);
    }
    }
    }
    </code>


  • =?Utf-8?B?TW9ydGVuIFdlbm5ldmlrIFtDIyBNVlBd?=

    #2
    RE: Forms.Panel and the KeyUp event (message)

    Hi,

    Actually, you can trap key events in a panel just fine, but the problem is
    the panel doesn't focus easily. One way to focus on a panel is to handle the
    MouseDown event and set focus there.

    Try this

    public class MyPanel : Panel
    {
    protected override void OnKeyDown(KeyEv entArgs e)
    {
    base.OnKeyDown( e);
    }

    protected override void OnMouseDown(Mou seEventArgs e)
    {
    base.OnMouseDow n(e);

    Focus();
    }
    }


    --
    Happy Coding!
    Morten Wennevik [C# MVP]


    "sklett" wrote:
    I know that Panel (and most of it's derivitives) don't raise keyboard
    events. I *really* need to catch keyboard events though so I've been
    googling the topic and have found quite a few suggestions. The one
    suggestion I've found that makes the most sense isn't working for me and
    after this most recent failure I'm really at a loss! ;0)
    >
    I'm overriding WndProc and checking the Message.Msg property for the
    WM_KEYUP message.
    >
    If anyone has any ideas for me I would really appreciate it!
    >
    >
    Here is a complete application that shows the failure.
    >
    <code>
    using System;
    using System.Collecti ons.Generic;
    using System.Windows. Forms;
    >
    namespace PanelKeyEventEx ample
    {
    public class Form1 : Form
    {
    public Form1()
    {
    InitializeCompo nent();
    }
    >
    private MyPanel panel1;
    >
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.Componen tModel.IContain er components = null;
    >
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing ">true if managed resources should be
    disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
    if (disposing && (components != null))
    {
    components.Disp ose();
    }
    base.Dispose(di sposing);
    }
    >
    #region Windows Form Designer generated code
    >
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeCompo nent()
    {
    this.panel1 = new MyPanel();
    this.SuspendLay out();
    //
    // panel1
    //
    this.panel1.Loc ation = new System.Drawing. Point(46, 49);
    this.panel1.Nam e = "panel1";
    this.panel1.Siz e = new System.Drawing. Size(200, 100);
    this.panel1.Tab Index = 0;
    //
    // Form1
    //
    this.AutoScaleD imensions = new System.Drawing. SizeF(6F, 13F);
    this.AutoScaleM ode = System.Windows. Forms.AutoScale Mode.Font;
    this.ClientSize = new System.Drawing. Size(292, 266);
    this.Controls.A dd(this.panel1) ;
    this.Name = "Form1";
    this.Text = "Form1";
    this.ResumeLayo ut(false);
    }
    >
    #endregion
    }
    >
    static class Program
    {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
    Application.Ena bleVisualStyles ();
    Application.Set CompatibleTextR enderingDefault (false);
    Application.Run (new Form1());
    }
    }
    >
    public class MyPanel : Panel
    {
    const int WM_KEYUP = 0x0101;
    >
    protected override void WndProc(ref Message m)
    {
    if (m.Msg == WM_KEYUP)
    {
    Console.WriteLi ne("KeyUp message caught");
    }
    >
    base.WndProc(re f m);
    }
    }
    }
    </code>
    >
    >
    >

    Comment

    • sklett

      #3
      Re: Forms.Panel and the KeyUp event (message)

      Hi Morten,

      Thank you for the reply! I hadn't thought about the focus issue, I thought
      that all messages would run the WndProc regardless of focus state. I will
      give your suggestion a try. I'm not sure what effect it will have on the
      operation of my control.

      You seem to really know your WinForm and Control stuff from posts I've read
      by you. If you don't mind I'd like to describe the control I have and the
      issue I'm trying to solve.

      The purpose of the control is to allow my user's to select pages from a
      document, it's similar in function to the "thumbnails " in acrobat reader.

      I have implemented the control as a derived FlowLayoutPanel that I populate
      with CheckBox controls. Each checkbox control has it's Image property set
      to one of the pages in my source image[].

      It works great, fulfills the use case, quick, etc, etc.

      I'm always trying to tweak my user interfaces, especially data entry
      applications, so the user doesn't feel the urge to grab the mouse and click.
      With my page selection control they tend to use the mouse to click on the
      thumbnails. *I* know it's possible to tab and spacebar to select the
      checkboxes, etc, etc but for my users that is a bit too awkward.

      My plan was to handle the numeric key presses (1-9) to select the
      corresponding pages. This is limited in that it will only support 9 pages,
      but for 99% of the time this will be fine.

      As my control is essentially a FlowLayoutpanel with child controls it seems
      I need to handle the key presses on the FlowLayoutPanel .

      In your opinion, am I on the right track?

      I'm concerned that if I set focus to the *Panel programmaticall y (per your
      suggestion) then if a user clicks on a checkbox control with the mouse the
      focus will be removed from the FlowLayoutPanel . Then subsequent 1-9 presses
      won't be caught by the Panel.

      I will try it and see what happens, I just wanted to run the design my you
      for any thoughts you might have or suggestions.

      Thanks again,
      Steve


      "Morten Wennevik [C# MVP]" <MortenWennevik @hotmail.comwro te in message
      news:614E0990-78DF-4ADC-B12C-93B9218BBC0B@mi crosoft.com...
      Hi,
      >
      Actually, you can trap key events in a panel just fine, but the problem is
      the panel doesn't focus easily. One way to focus on a panel is to handle
      the
      MouseDown event and set focus there.
      >
      Try this
      >
      public class MyPanel : Panel
      {
      protected override void OnKeyDown(KeyEv entArgs e)
      {
      base.OnKeyDown( e);
      }
      >
      protected override void OnMouseDown(Mou seEventArgs e)
      {
      base.OnMouseDow n(e);
      >
      Focus();
      }
      }
      >
      >
      --
      Happy Coding!
      Morten Wennevik [C# MVP]
      >
      >
      "sklett" wrote:
      >
      >I know that Panel (and most of it's derivitives) don't raise keyboard
      >events. I *really* need to catch keyboard events though so I've been
      >googling the topic and have found quite a few suggestions. The one
      >suggestion I've found that makes the most sense isn't working for me and
      >after this most recent failure I'm really at a loss! ;0)
      >>
      >I'm overriding WndProc and checking the Message.Msg property for the
      >WM_KEYUP message.
      >>
      >If anyone has any ideas for me I would really appreciate it!
      >>
      >>
      >Here is a complete application that shows the failure.
      >>
      ><code>
      >using System;
      >using System.Collecti ons.Generic;
      >using System.Windows. Forms;
      >>
      >namespace PanelKeyEventEx ample
      >{
      > public class Form1 : Form
      > {
      > public Form1()
      > {
      > InitializeCompo nent();
      > }
      >>
      > private MyPanel panel1;
      >>
      > /// <summary>
      > /// Required designer variable.
      > /// </summary>
      > private System.Componen tModel.IContain er components = null;
      >>
      > /// <summary>
      > /// Clean up any resources being used.
      > /// </summary>
      > /// <param name="disposing ">true if managed resources should be
      >disposed; otherwise, false.</param>
      > protected override void Dispose(bool disposing)
      > {
      > if (disposing && (components != null))
      > {
      > components.Disp ose();
      > }
      > base.Dispose(di sposing);
      > }
      >>
      > #region Windows Form Designer generated code
      >>
      > /// <summary>
      > /// Required method for Designer support - do not modify
      > /// the contents of this method with the code editor.
      > /// </summary>
      > private void InitializeCompo nent()
      > {
      > this.panel1 = new MyPanel();
      > this.SuspendLay out();
      > //
      > // panel1
      > //
      > this.panel1.Loc ation = new System.Drawing. Point(46, 49);
      > this.panel1.Nam e = "panel1";
      > this.panel1.Siz e = new System.Drawing. Size(200, 100);
      > this.panel1.Tab Index = 0;
      > //
      > // Form1
      > //
      > this.AutoScaleD imensions = new System.Drawing. SizeF(6F, 13F);
      > this.AutoScaleM ode = System.Windows. Forms.AutoScale Mode.Font;
      > this.ClientSize = new System.Drawing. Size(292, 266);
      > this.Controls.A dd(this.panel1) ;
      > this.Name = "Form1";
      > this.Text = "Form1";
      > this.ResumeLayo ut(false);
      > }
      >>
      > #endregion
      > }
      >>
      > static class Program
      > {
      > /// <summary>
      > /// The main entry point for the application.
      > /// </summary>
      > [STAThread]
      > static void Main()
      > {
      > Application.Ena bleVisualStyles ();
      > Application.Set CompatibleTextR enderingDefault (false);
      > Application.Run (new Form1());
      > }
      > }
      >>
      > public class MyPanel : Panel
      > {
      > const int WM_KEYUP = 0x0101;
      >>
      > protected override void WndProc(ref Message m)
      > {
      > if (m.Msg == WM_KEYUP)
      > {
      > Console.WriteLi ne("KeyUp message caught");
      > }
      >>
      > base.WndProc(re f m);
      > }
      > }
      >}
      ></code>
      >>
      >>
      >>

      Comment

      • sklett

        #4
        Re: Forms.Panel and the KeyUp event (message)

        I'm concerned that if I set focus to the *Panel programmaticall y (per your
        suggestion) then if a user clicks on a checkbox control with the mouse the
        focus will be removed from the FlowLayoutPanel . Then subsequent 1-9
        presses won't be caught by the Panel.
        Turns out this is indeed the case. When my control is shown, I click in the
        background space of the FlowLayouPanel which fires the mouse down event and
        I set focus. I can then press the numeric keys and everything works great.

        If I then click on a child control of the FlowLayoutPanel the focus is lost
        and my numeric key events are not handled. I understand why this is
        happening, I just don't understand what I can do about it.

        I can imagine some hacks that might work but I'm not happy with any of them.
        This requirement of mine is something I will need to have in other controls
        I plan to create. It's really surprising to me that a Panel doesn't get all
        messages! ;0(

        If anyone can think of a solution to get my events or messages to always
        make it to my FlowLayoutPanel I would really appreciate it.

        My ideas for possible solutions are:

        1) Anonymous handlers added to each child control that is created. Maybe
        for the click event, keyDown, ?? - this handler would first service the
        child controls event then set focus to the parent (FlowLayoutPane l). This
        is nasty and limited, for example, if I decided to add a control that had
        it's own nested control this solution would fail. I could recurse up the
        tree until I find the FLP but this is just more nastiness.

        I feel like I'm leaving a more elegant solution behind, there must be a way
        to do this.

        2) .... actually that's all I have right now ;0)

        -Steve


        Comment

        • =?Utf-8?B?TW9ydGVuIFdlbm5ldmlrIFtDIyBNVlBd?=

          #5
          Re: Forms.Panel and the KeyUp event (message)

          Hi Steve,

          The easiest way to prevent the checkboxes stealing focus is handling the
          GotFocus or Enter event and then programmaticall y set focus back to the
          panel.

          In your panel try adding this code

          protected override void OnControlAdded( ControlEventArg s e)
          {
          base.OnControlA dded(e);

          e.Control.Enter += new EventHandler(Co ntrol_Enter);
          }

          void Control_Enter(o bject sender, EventArgs e)
          {
          Focus();
          }

          If you need to perform some action against the selected 'page' you can just
          use the sender reference to determine which page was clicked.

          You probably need to

          --
          Happy Coding!
          Morten Wennevik [C# MVP]


          "sklett" wrote:
          I'm concerned that if I set focus to the *Panel programmaticall y (per your
          suggestion) then if a user clicks on a checkbox control with the mouse the
          focus will be removed from the FlowLayoutPanel . Then subsequent 1-9
          presses won't be caught by the Panel.
          >
          Turns out this is indeed the case. When my control is shown, I click in the
          background space of the FlowLayouPanel which fires the mouse down event and
          I set focus. I can then press the numeric keys and everything works great.
          >
          If I then click on a child control of the FlowLayoutPanel the focus is lost
          and my numeric key events are not handled. I understand why this is
          happening, I just don't understand what I can do about it.
          >
          I can imagine some hacks that might work but I'm not happy with any of them.
          This requirement of mine is something I will need to have in other controls
          I plan to create. It's really surprising to me that a Panel doesn't get all
          messages! ;0(
          >
          If anyone can think of a solution to get my events or messages to always
          make it to my FlowLayoutPanel I would really appreciate it.
          >
          My ideas for possible solutions are:
          >
          1) Anonymous handlers added to each child control that is created. Maybe
          for the click event, keyDown, ?? - this handler would first service the
          child controls event then set focus to the parent (FlowLayoutPane l). This
          is nasty and limited, for example, if I decided to add a control that had
          it's own nested control this solution would fail. I could recurse up the
          tree until I find the FLP but this is just more nastiness.
          >
          I feel like I'm leaving a more elegant solution behind, there must be a way
          to do this.
          >
          2) .... actually that's all I have right now ;0)
          >
          -Steve
          >
          >
          >

          Comment

          • sklett

            #6
            Re: Forms.Panel and the KeyUp event (message)


            "Morten Wennevik [C# MVP]" <MortenWennevik @hotmail.comwro te in message
            news:597216DF-A48B-41D4-B2A8-46B2AB457267@mi crosoft.com...
            Hi Steve,
            >
            The easiest way to prevent the checkboxes stealing focus is handling the
            GotFocus or Enter event and then programmaticall y set focus back to the
            panel.
            >
            In your panel try adding this code
            >
            protected override void OnControlAdded( ControlEventArg s e)
            {
            base.OnControlA dded(e);
            >
            e.Control.Enter += new EventHandler(Co ntrol_Enter);
            }
            >
            void Control_Enter(o bject sender, EventArgs e)
            {
            Focus();
            }
            >
            If you need to perform some action against the selected 'page' you can
            just
            use the sender reference to determine which page was clicked.
            >
            You probably need to
            >
            --
            Happy Coding!
            Morten Wennevik [C# MVP]
            Hi Morten,

            Thanks again for the continued help! Your suggestion worked very well. I
            needed to add a call to Focus() in my control's parent OnShown event and now
            it works as I would like it to.

            I'm now that much closer to keeping my user's hands OFF the mouse! ;0)

            -Steve


            Comment

            Working...