-1

Basically, I've created an extension of the panel class that adds draws multiple bitmaps onto itself In order to create multiple musical staves. I've tried adding a vertical scroll bar onto the panel but that hasn't worked. My Paint procedure is similar to this

private void StavePanel_Paint(object sender, PaintEventArgs e)
{
    for(int i = 0; i < linenumber; i++)
    {
        Bitmap bmp = new Bitmap(Width, 200);
        //edit bmp to resemble stave
        e.Graphics.DrawImage(bmp,new Point(0,200*i);
    }
}
Sophie Coyne
  • 1,018
  • 7
  • 16
  • Have you tried the `AutoScroll` property (or adding a `VScrollBar`/`HScrollBar`)? – varocarbas Oct 06 '15 at 18:46
  • Yes, this doesn't seem to work – Sophie Coyne Oct 06 '15 at 18:46
  • What you mean with "doesn't seem to work"? Perhaps you are not using them properly. Could you please explain what you did exactly? – varocarbas Oct 06 '15 at 18:47
  • I added an instance of the "VScrollBar" class to the form, this makes this scroll bar appear but it isn't functional. I've set AutoScroll and VerticallScroll.Enabled to true – Sophie Coyne Oct 06 '15 at 18:51
  • It is certainly functional, but the right conditions have to be present. For example: if your form has a height of 50 and one of the controls on it has a Location.Y value of 100, the scroll bar would be functional (exactly the same than the AutoScroll property of the panel). – varocarbas Oct 06 '15 at 18:53
  • Alright then, give me the constructor that would make an extension of a panel scrollable, and I'll see if jt works ^_^ – Sophie Coyne Oct 06 '15 at 18:54
  • Just inherit from `Panel`. `Panel` has the property `AutoScroll`. Set it to true and it would work when required (= when the controls inside it are located outside the boundaries). Alternatively, you might add `VScrollBar`/`HScrollBar` or any other suggestions given by Olivier in his answer. – varocarbas Oct 06 '15 at 18:55
  • I haven't added controls though, I've merely drawn bitmaps onto the panel. – Sophie Coyne Oct 06 '15 at 18:59
  • Whatever, but this whatever has to lie outside the boundaries of the container (panel, in this case) to allow the scrollbars to work. Anyway... I have helped you enough via comments; you should now focus on the answer you got. – varocarbas Oct 06 '15 at 19:01
  • Well, believe it or not it doesn't work. I'm gonna try to use Pictureboxes to force it to work but it seems not to do so simply with an image. – Sophie Coyne Oct 06 '15 at 19:03
  • Are you calling .Invalidate on the panel when the position of the scrollbar you added changes? If you don't do that then it won't know that it needs to redraw its self – Bradley Uffner Oct 06 '15 at 19:05

4 Answers4

1

Just set the AutoScrollMinSize property:

panel1.AutoScrollMinSize = new Size(0, 1000);

During the paint event, you need to translate the positions of your drawing by using the TranslateTransform method. Also, you need to dispose your bitmaps after you draw them:

e.Graphics.TranslateTransform(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y);

using (Bitmap bmp = new Bitmap(Width, 200)) {
  //edit bmp to resemble stave
  e.Graphics.DrawImage(bmp,new Point(0,200*i);
}

or create and store them ahead of time to avoid that cost during the paint event.

LarsTech
  • 80,625
  • 14
  • 153
  • 225
0

Set the AutoScroll property to true.

You might also consider alternatives:

  • FlowLayoutPanel and add PictureBoxes dynamically instead of painting.
  • TableLayoutPanel and add PictureBoxes dynamically instead of painting.
  • extend ListBox and set the DrawMode property to OwnerDrawFixed or OwnerDrawVariable and then override the methods OnPaint and OnMeasureItem (only for OwnerDrawVariable).
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
0

If you want to continue using your existing pattern of calling GDI code to paint your control you should add a scrollbar control and add an event handler to its change event. The change handler doesn't need to do anything other than call .Invalidate on the panel. .Invalidate is a signal to the control that it is "dirty" and needs to be redrawn. You will need to modify your painting code to offset the drawing in the inverse direction of the scrollbar value.

So if your scrollbar is at position 50, you should draw everything at Y - 50.

If you are using pure GDI drawing code there is no need to mess with the AutoScroll property at all. That is only used if your panel hosts an actual control that is larger than the panel.

Bradley Uffner
  • 16,641
  • 3
  • 39
  • 76
0

As others mentioned, you need to set AutoScroll to true. But then, anytime you add or remove a bitmap (or at the beginning if they are fixed), you need to set the AutoScrollMinSize height using the formula bitmapCount * bitmapHeight. Also in your paint handler you need to consider the AutoScrollPosition.Y property.

Here is a small example of the concept in action:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Tests
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var form = new Form();
            var panel = new Panel { Dock = DockStyle.Fill, Parent = form };
            // Setting the AutoScrollMinSize
            int bitmapCount = 10;
            int bitmapHeight = 200;
            panel.AutoScrollMinSize = new Size(0, bitmapCount * bitmapHeight);
            panel.Paint += (sender, e) =>
            {
                // Considering the AutoScrollPosition.Y
                int offsetY = panel.AutoScrollPosition.Y;
                var state = offsetY != 0 ? e.Graphics.Save() : null;
                if (offsetY != 0) e.Graphics.TranslateTransform(0, offsetY);
                var rect = new Rectangle(0, 0, panel.ClientSize.Width, bitmapHeight);
                var sf = new StringFormat(StringFormat.GenericTypographic) { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
                for (int i = 0; i < bitmapCount; i++)
                {
                    // Your bitmap drawing goes here
                    e.Graphics.FillRectangle(Brushes.Yellow, rect);
                    e.Graphics.DrawRectangle(Pens.Red, rect);
                    e.Graphics.DrawString("Bitmap #" + (i + 1), panel.Font, Brushes.Blue, rect, sf);
                    rect.Y += bitmapHeight;
                }
                if (state != null) e.Graphics.Restore(state);
            };
            Application.Run(form);
        }
    }
}

EDIT: As LarsTech correctly mentioned in the comments, you don't really need to set AutoScroll property in this case. All other remains the same.

Community
  • 1
  • 1
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • AutoScroll is really only used when you have controls inside the panel. When you set the AutoScrollMinSize property, you don't need the AutoScroll to be true. – LarsTech Oct 06 '15 at 19:44
  • @LarsTech: Thanks, you are right of course! I'll correct the answer. Now I see that you posted exactly the same while I was preparing my answer, Sorry about the duplicate. – Ivan Stoev Oct 06 '15 at 19:49