Scrolling GDI pixels in Panel control

为君一笑 提交于 2019-12-12 03:38:44

问题


How do we make a Panel control scroll whatever's inside of it? I'm not talking about controls or user controls or custom controls. I'm talking only about pixels; drawn with GDI+:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GDITEST
{
    public partial class Form1 : Form
    {
        public class Item
        {
            public int Height { get; set; }
            public int Width { get; set; }
            public int Top { get; set; }
        }

        internal List<Item> items = new List<Item>();

        public Form1()
        {
            InitializeComponent();
        }

        private void panel_Paint(object sender, PaintEventArgs e)
        {
            if (items != null)
            {
                if (items.Count >= 1)
                {
                    foreach (Item item in items)
                    {
                        using (Pen pen = new Pen(Color.Blue, 1))
                        {
                            int count;
                            count = items.Count;

                            count = count >= 1 ? count : 1;
                            e.Graphics.DrawRectangle(pen, 0, item.Top, (item.Width - SystemInformation.VerticalScrollBarWidth), item.Height);
                        }
                    }
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            items.Add(new Item() { Width = this.Width, Height = 25, Top = (items.Count * 25) });
            panel.Refresh();
        }
    }
}

The above code draws a blue rectangle (kinda like a vertical list). When the number of rectangles extends the height of the panel, I want the panel to scroll.

I've not been able to find out how to do this, since most of the results only return stuff related to scrolling custom controls.

I did read somewhere (which I can no longer find) that you can use some translateX or translateY methods... Yet I am having a hard time trying to find out anything more about those methods.


回答1:


There's a simple bug in your code, you forgot to offset what you draw by the scroll amount. The Panel class has two other quirks, it was optimized to be a container control and cuts corners on the way it paints. You get rid of all three issues by creating your derived class from Panel. Project > Add Class > paste the code shown below. Build > Build and drop the new control from the top of the toolbox onto your form.

using System;
using System.Windows.Forms;

class MyPanel : Panel {
    public MyPanel() {
        this.DoubleBuffered = this.ResizeRedraw = true;
    }
    protected override void OnPaint(PaintEventArgs e) {
        e.Graphics.TranslateTransform(this.AutoScrollPosition.X, this.AutoScrollPosition.Y);
        base.OnPaint(e);
    }
}

You can further optimize your Paint event handler by paying attention to the e.ClipRectangle property and skip drawing an item when it is clipped. Just in case: assign the AutoScrollMinSize property to fit the items.




回答2:


Here's a rough example on how to manually show the scrollbars. The panel contains a red rectangle, which can be clicked and dragged. If the rectangle is moved outside the viewable area, the scrollbars appear.

public class DrawPanel : Panel {

    public Rectangle rect = new Rectangle(0, 0, 200, 100);
    int offsetX = 0;
    int offsetY = 0;
    bool grabbing = false;

    public DrawPanel() {
        Dock = DockStyle.Fill;
        AutoScroll = true;
    }

    protected override void OnMouseDown(MouseEventArgs e) {
        base.OnMouseDown(e);
        var p = e.Location;
        if (rect.Contains(p)) {
            grabbing = true;
            offsetX = rect.X - p.X;
            offsetY = rect.Y - p.Y;
        }
    }

    protected override void OnMouseUp(MouseEventArgs e) {
        base.OnMouseUp(e);
        grabbing = false;
    }

    protected override void OnMouseMove(MouseEventArgs e) {
        base.OnMouseMove(e);
        if (grabbing) {
            var p = e.Location;
            rect.Location = new Point(p.X + offsetX, p.Y + offsetY);
            Invalidate();

            int right = rect.X + rect.Width;
            int bottom = rect.Y + rect.Height;

            if (right > Width || bottom > Height) {
                this.AutoScrollMinSize = new Size(right + 1, bottom + 1);
            }
        }
    }

    protected override void OnScroll(ScrollEventArgs se) {
        base.OnScroll(se);
        Invalidate();
    }

    protected override void OnPaint(PaintEventArgs e) {
        base.OnPaint(e);

        var g = e.Graphics;
        var p = AutoScrollPosition;
        Rectangle r = rect;
        r.X += p.X;
        r.Y += p.Y;
        g.DrawRectangle(Pens.Red, r);
    }

}


来源:https://stackoverflow.com/questions/33029741/scrolling-gdi-pixels-in-panel-control

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!