允许自定义控件正确滚动出视野

杰里米·索伦森

我有一个自定义控件,其中包含带有文本的填充圆角矩形。(实际控件更加复杂,但是此处显示的代码具有相同的症状。)我将控件的实例附加到Panel,并使用AutoScroll = true使Panel成为另一个Panel的子级。我认为这对于正确的滚动行为就足够了,但是如果您滚动以使控件的左侧偏离面板的左侧,则它会粘住并且控件会收缩。与滚动相同,因此控件应在顶部关闭。(底部和右侧似乎没有问题。)这是示例代码(需要对System.Windows.Forms和System.Drawing的引用。)我在Windows上将Visual Studio 2010与.NET 4客户端一起使用。

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


namespace CustomControlScrollTest
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }

    // Form with a Dock = Fill panel with autoscroll turned on, and a nested panel
    // with few custom roundRectControls.
    public class Form1 : Form
    {
        Panel autoScrollPanel;
        Panel rectPanel;

        public Form1()
        {
            Size = new Size(300, 200);

            autoScrollPanel = new Panel();
            autoScrollPanel.Dock = DockStyle.Fill;
            autoScrollPanel.AutoScroll = true;
            autoScrollPanel.AutoScrollMinSize = new Size(600, 450);

            autoScrollPanel.Resize += autoScrollPanel_Resize;
            autoScrollPanel.Scroll += autoScrollPanel_Scroll;

            Controls.Add(autoScrollPanel);

            rectPanel = new Panel();
            rectPanel.Size = autoScrollPanel.AutoScrollMinSize;
            rectPanel.Controls.AddRange(new RoundRectControl[] {
                new RoundRectControl(),
                new RoundRectControl(),
                new RoundRectControl(),
                new RoundRectControl(),
                new RoundRectControl()
            });

            foreach (Control c in rectPanel.Controls)
            {
                c.Click += c_Click;
            }

            autoScrollPanel.Controls.Add(rectPanel);

            placeBoxes();
        }

        // we want to be able to recalculate the boxes position at any time
        // in the real program this occurs due to model changes
        void c_Click(object sender, EventArgs e)
        {
            placeBoxes();
        }

        void autoScrollPanel_Scroll(object sender, ScrollEventArgs e)
        {
            Refresh();
        }

        void autoScrollPanel_Resize(object sender, EventArgs e)
        {
            Refresh();
        }

        private void placeBoxes()
        {
            for (int i = 0; i < rectPanel.Controls.Count; ++i)
            {
                int j = i + 1;
                var node = rectPanel.Controls[i] as RoundRectControl;
                if (node != null)
                {
                    node.Title = "Hello (" + j + ")";
                    node.Location = new Point(i * 100, j * 75);
                    node.Visible = true;                   
                }
            }
        }
    }

    // A rounded rectangle filled blue with a black border and white text
    // the size is determined by the text
    public class RoundRectControl : Control
    {
        public RoundRectControl()
        {
            var f = SystemFonts.MessageBoxFont;
            titleFont = new Font(f.Name, f.SizeInPoints + 2, FontStyle.Bold, GraphicsUnit.Point);
            ResizeRedraw = true;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            var g = e.Graphics;

            var left = e.ClipRectangle.X;
            var right = left + titleWidth + 2 * radius;
            var top = e.ClipRectangle.Y;
            var bottom = top + nodeHeight + 2 * radius;

            var r2 = 2 * radius;

            using (var path = new GraphicsPath())
            {
                path.AddArc(left,       bottom - r2, r2,  r2, 90,  90);
                path.AddArc(left,       top,         r2,  r2, 180, 90);
                path.AddArc(right - r2, top,         r2,  r2, 270, 90);
                path.AddArc(right - r2, bottom - r2, r2,  r2, 0,   90);
                path.CloseFigure();

                g.FillPath(titleBrush, path);
                g.DrawPath(borderPen, path);
            }

            g.DrawString(title, titleFont, titleTextBrush, left + radius, top + radius);
        }

        private string title;
        public string Title
        {
            get { return title; }
            set
            {
                title = value;
                Size = getSize();
                Invalidate();
            }
        }

        private Brush titleBrush = Brushes.Blue;

        private Brush titleTextBrush = Brushes.White;

        private Pen borderPen = Pens.Black;

        private Size getSize()
        {
            var g = CreateGraphics();
            var titleSize = g.MeasureString(title, titleFont);
            titleWidth = (int)titleSize.Width;
            nodeHeight = (int)titleSize.Height;
            return new Size(titleWidth + 2 * radius + 1, nodeHeight + 2 * radius + 1);
        }

        public override Size GetPreferredSize(Size proposedSize)
        {
            return getSize();
        }

        private int titleWidth;
        private int nodeHeight;

        private Font titleFont;

        private int radius = 5;
    }
}
γηράσκωδ'αείπολλάδιδασκόμε

试试这个

protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        var g = e.Graphics;

        //total width and height of rounded rectangle
        var width = titleWidth + 2 * radius + 1;
        var height = nodeHeight + 2 * radius + 1;

        var left = e.ClipRectangle.X;
        var top = e.ClipRectangle.Y;

        //check if clipping occurs. If yes, set to 0
        if (width > e.ClipRectangle.Width)
        {
            left = 0; // *= -1;
        }

        //check if clipping occurs.If yes, set to 0
        if (height > e.ClipRectangle.Height)
        {
            top = 0; // *= -1
        }

        var right = left + titleWidth + 2 * radius;
        var bottom = top + nodeHeight + 2 * radius;

        var r2 = 2 * radius;

        using (var path = new GraphicsPath())
        {
            path.AddArc(left, bottom - r2, r2, r2, 90, 90);
            path.AddArc(left, top, r2, r2, 180, 90);
            path.AddArc(right - r2, top, r2, r2, 270, 90);
            path.AddArc(right - r2, bottom - r2, r2, r2, 0, 90);
            path.CloseFigure();

            g.FillPath(titleBrush, path);
            g.DrawPath(borderPen, path);
        }

        g.DrawString(title, titleFont, titleTextBrush, left + radius, top + radius);
    }

问题是当您向右滚动(向右移动,e.ClipRectangle.Width变小)并且矩形超出区域时,e.ClipRectangle.X为正!因此,在这种情况下,我们将其设置为零。e.ClipRectangle.X不能为负,因此即使您将其反转(编辑前的解决方案),它也将变为零。

编辑

你可以做

var left = 0;
var right = left + titleWidth + 2 * radius;
var top = 0;
var bottom = top + nodeHeight + 2 * radius;

两者都在工作

您可以使用这些样式

this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

避免闪烁

瓦尔特

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在多内容自定义控件中允许命名元素

来自分类Dev

在WTL中的自定义绘制控件中实现滚动

来自分类Dev

如何正确公开自定义控件上的属性?

来自分类Dev

如何防止自定义用户控件上的各个控件散开(并仍然允许调整大小)

来自分类Dev

DataGridTemplateColumn的自定义控件

来自分类Dev

自定义gui控件

来自分类Dev

指令自定义控件

来自分类Dev

自定义控件Android

来自分类Dev

ASP.NET自定义控件,templatesection仅允许在其中添加自定义类

来自分类Dev

如何使滚动条在自定义控件中良好播放?

来自分类Dev

如何基于带有动画的滚动视图进行自定义控件?

来自分类Dev

自定义控件的自定义属性

来自分类Dev

自定义控件自定义标签“for”属性放置

来自分类Dev

C#- 自定义控件的自定义属性

来自分类Dev

Android Crouton自定义视图不允许滚动文本(字幕效果)

来自分类Dev

如何正确地向另一个自定义控件添加一个自定义控件,使其以表格形式呈现?

来自分类Dev

+ =委托{}是将自定义eventarg附加到UI控件事件的正确方法吗?

来自分类Dev

为什么自定义输入控件在Ant Design表单中无法正确验证?

来自分类Dev

如何在自定义控件中正确响应焦点消息?

来自分类Dev

如何正确使用自定义控件的“数据源选择器编辑器”?

来自分类Dev

PRISM WPF 自定义交互请求 - 动态视图控件显示不正确

来自分类Dev

如何将 ObservableCollection 正确绑定到自定义控件属性?

来自分类Dev

自定义UITableViewCell的问题:滚动出视图出队列问题时会清除UITextFields

来自分类Dev

自定义UITableViewCell的问题:滚动出视图出队列问题时会清除UITextFields

来自分类Dev

自定义控件OnPaint不会触发

来自分类Dev

在Xamarin中创建自定义控件

来自分类Dev

BX Slider自定义控件

来自分类Dev

向自定义控件添加功能

来自分类Dev

自定义控件的基类

Related 相关文章

  1. 1

    在多内容自定义控件中允许命名元素

  2. 2

    在WTL中的自定义绘制控件中实现滚动

  3. 3

    如何正确公开自定义控件上的属性?

  4. 4

    如何防止自定义用户控件上的各个控件散开(并仍然允许调整大小)

  5. 5

    DataGridTemplateColumn的自定义控件

  6. 6

    自定义gui控件

  7. 7

    指令自定义控件

  8. 8

    自定义控件Android

  9. 9

    ASP.NET自定义控件,templatesection仅允许在其中添加自定义类

  10. 10

    如何使滚动条在自定义控件中良好播放?

  11. 11

    如何基于带有动画的滚动视图进行自定义控件?

  12. 12

    自定义控件的自定义属性

  13. 13

    自定义控件自定义标签“for”属性放置

  14. 14

    C#- 自定义控件的自定义属性

  15. 15

    Android Crouton自定义视图不允许滚动文本(字幕效果)

  16. 16

    如何正确地向另一个自定义控件添加一个自定义控件,使其以表格形式呈现?

  17. 17

    + =委托{}是将自定义eventarg附加到UI控件事件的正确方法吗?

  18. 18

    为什么自定义输入控件在Ant Design表单中无法正确验证?

  19. 19

    如何在自定义控件中正确响应焦点消息?

  20. 20

    如何正确使用自定义控件的“数据源选择器编辑器”?

  21. 21

    PRISM WPF 自定义交互请求 - 动态视图控件显示不正确

  22. 22

    如何将 ObservableCollection 正确绑定到自定义控件属性?

  23. 23

    自定义UITableViewCell的问题:滚动出视图出队列问题时会清除UITextFields

  24. 24

    自定义UITableViewCell的问题:滚动出视图出队列问题时会清除UITextFields

  25. 25

    自定义控件OnPaint不会触发

  26. 26

    在Xamarin中创建自定义控件

  27. 27

    BX Slider自定义控件

  28. 28

    向自定义控件添加功能

  29. 29

    自定义控件的基类

热门标签

归档