Scroll panel with image using keyboard (PageDown /

2019-08-09 18:54发布

问题:

What is right way to show large image in Winforms app with scroll-bars and keyboard scroll support? Currenty i'm use Panel(AutoScroll=True) with nested PitureBox (SizeMod = AutoSize).

I have 2 question:

1) What control select for drawing image? Panel and PitureBox cant be selected (focused) using Tab key. Using Button with AutoSize = true and FlatStyle = Flat is right solution?

2)How to scroll image in panel using keyboard. What keyboard events a need handle - Form, Panel or PictureBox. May be I should set for Panel AutoScroll=false and add to them HScroll and VScroll, that events I should handle?

What is right way for implement this elementary app?

(Just for info, main form have other Panel(Dock=Top) that contain some controls.)

回答1:

  • As for the first question: There is no Control which is really well suited to draw on and still can get the Focus. In the link below you can see how to make a selectable panel, though.

  • Now for the real problem: How to scroll an AutoScroll Panel by keyboard..?

This is amazingly hard to do. Here is an example for a start:

private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
  if (panel1.Bounds.Contains( this.PointToClient( Cursor.Position )  ))
  {
    if (e.KeyValue == 33) panel1.AutoScrollPosition = 
      new Point(panel1.AutoScrollPosition.X, Math.Abs(panel1.AutoScrollPosition.Y) - 10);

    if (e.KeyValue == 34) panel1.AutoScrollPosition = 
      new Point(panel1.AutoScrollPosition.X, Math.Abs(panel1.AutoScrollPosition.Y) + 10);
  }
}

I test for the Panel to contain the mouse. You may want to play around with the scroll amount.. Also replace the KeyValues with proper Keys ;-) Set KeyPreview = true; for the Form!

Note: This only works if there is no Control on the Form which can get the Focus.

Since most likely you have some such Controls, like Buttons, ListBoxes etc.. here is another solution, which works in any case, I believe..:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (panel1.Bounds.Contains(this.PointToClient(Cursor.Position)))
    switch (keyData)
    {
        case Keys.PageDown: { scroll(10);  return true; }
        case Keys.PageUp:   { scroll(-10); return true; }
       // maybe code for some more keys..?
    }

    return base.ProcessCmdKey(ref msg, keyData);
}

void scroll(int delta)
{
    panel1.AutoScrollPosition =  new Point(
           panel1.AutoScrollPosition.X, Math.Abs(panel1.AutoScrollPosition.Y) + delta);
}

This doesn't need the Form to have KeyPreview = true;.

Here is the MSDN explanation for AutoScrollPosition.

Here is a post that suggests using a subclass for Panel and/or PictureBox, which is supposed to allow them to get Focus. I couldn't get that to work though..(Nor does it seem to be any simpler in the end..)