防止我的橡皮筋闪烁?

时间:2016-05-31 15:14:58

标签: c# winforms

我采用以下代码实施了橡皮筋:

https://support.microsoft.com/en-gb/kb/314945

这是我的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;

namespace Test
{
    public partial class TestX: UserControl
    {
        private Boolean m_bLeftButton { get; set; }
        private Boolean m_bMiddleButton { get; set; }
        private Boolean m_bZoomWindow { get; set; }

        Point m_ptOriginal = new Point();
        Point m_ptLast = new Point();

        public TestX()
        {
            m_bZoomWindow = false;
            m_bLeftButton = false;
            m_bMiddleButton = false;
        }

        // Called when the left mouse button is pressed. 
        public void MyMouseDown(Object sender, MouseEventArgs e)
        {
            if(m_bZoomWindow && e.Button == MouseButtons.Left)
            {
                // Make a note that we "have the mouse".
                m_bLeftButton = true;

                // Store the "starting point" for this rubber-band rectangle.
                m_ptOriginal.X = e.X;
                m_ptOriginal.Y = e.Y;
                // Special value lets us know that no previous
                // rectangle needs to be erased.
                m_ptLast.X = -1;
                m_ptLast.Y = -1;
            }
        }

        // Convert and normalize the points and draw the reversible frame.
        private void MyDrawReversibleRectangle(Point p1, Point p2)
        {
            Rectangle rc = new Rectangle();

            // Convert the points to screen coordinates.
            p1 = PointToScreen(p1);
            p2 = PointToScreen(p2);
            // Normalize the rectangle.
            if (p1.X < p2.X)
            {
                rc.X = p1.X;
                rc.Width = p2.X - p1.X;
            }
            else
            {
                rc.X = p2.X;
                rc.Width = p1.X - p2.X;
            }
            if (p1.Y < p2.Y)
            {
                rc.Y = p1.Y;
                rc.Height = p2.Y - p1.Y;
            }
            else
            {
                rc.Y = p2.Y;
                rc.Height = p1.Y - p2.Y;
            }
            // Draw the reversible frame.
            ControlPaint.DrawReversibleFrame(rc,
                            Color.WhiteSmoke, FrameStyle.Thick);
        }

        // Called when the left mouse button is released.
        public void MyMouseUp(Object sender, MouseEventArgs e)
        {
            if(m_bZoomWindow && e.Button == MouseButtons.Left)
            {
                // Set internal flag to know we no longer "have the mouse".
                m_bZoomWindow = false;
                m_bLeftButton = false;

                // If we have drawn previously, draw again in that spot
                // to remove the lines.
                if (m_ptLast.X != -1)
                {
                    Point ptCurrent = new Point(e.X, e.Y);
                    MyDrawReversibleRectangle(m_ptOriginal, m_ptLast);

                    // Do zoom now ...
                }
                // Set flags to know that there is no "previous" line to reverse.
                m_ptLast.X = -1;
                m_ptLast.Y = -1;
                m_ptOriginal.X = -1;
                m_ptOriginal.Y = -1;
            }
        }

        // Called when the mouse is moved.
        public void MyMouseMove(Object sender, MouseEventArgs e)
        {
            Point ptCurrent = new Point(e.X, e.Y);

            if(m_bLeftButton)
            {
                // If we "have the mouse", then we draw our lines.
                if (m_bZoomWindow)
                {
                    // If we have drawn previously, draw again in
                    // that spot to remove the lines.
                    if (m_ptLast.X != -1)
                    {
                        MyDrawReversibleRectangle(m_ptOriginal, m_ptLast);
                    }
                    // Update last point.
                    if(ptCurrent != m_ptLast)
                    {
                        m_ptLast = ptCurrent;
                        // Draw new lines.
                        MyDrawReversibleRectangle(m_ptOriginal, ptCurrent);
                    }
                }
            }
        }

        // Set up delegates for mouse events.
        protected override void OnLoad(System.EventArgs e)
        {
            MouseDown += new MouseEventHandler(MyMouseDown);
            MouseUp += new MouseEventHandler(MyMouseUp);
            MouseMove += new MouseEventHandler(MyMouseMove);
            MouseWheel += new MouseEventHandler(MyMouseWheel);

            m_bZoomWindow = false;
        }
    }
}

它本身可以工作,但矩形闪烁。其他程序(如CAD软件包)在绘制矩形时没有闪烁。

我的表单已设置为使用DoubleBuffering,所以我认为没问题。还有其他人遇到过这个问题吗?

更新:我想我会回到开头并使用表格布局面板和嵌入式用户控件进行测试winforms项目。我将用户控件设置为像我提供的答案一样工作。唯一的区别是我设置了这样的用户控件构造函数:

public MyUserControl()
{
    InitializeComponent();

    _selectionPen = new Pen(Color.Black, 3.0f);

    SetStyle(ControlStyles.OptimizedDoubleBuffer | 
             ControlStyles.AllPaintingInWmPaint | 
             ControlStyles.UserPaint, true);
    BackColor = Color.Transparent;
    Dock = DockStyle.Fill;
    Margin = new Padding(1);
}

请注意其他控件样式 AllPaintingInWmPaint UserPaint ?除了 OptimizedDoubleBuffer 样式之外,我似乎还需要这些。我还将表单设置为双缓冲。

当我进行这些调整时,我可以绘制一个无闪烁的橡皮筋。 Hoorah!但是当我在嵌入式类中添加用于在用户控件中呈现DWG的时候,我会因为强加另一个而产生冲突。

这就是我所处的位置,我将等待从DWG查看器类的供应商那里收集到什么。

1 个答案:

答案 0 :(得分:1)

使用Paint事件演示,从我的评论到OP。

我能够在Paint中进行并在控件上设置ControlStyles.OptimizeDoubleBuffer时获得最流畅的方框。当然,它取决于你的盒子的预期界限 - 这不会超过控件本身的界限(即不会绘制到表单或桌面上):

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

namespace WinformsScratch.RubberBand
{
    public class TestY : Control
    {
        private Point? _selectionStart;
        private Point? _selectionEnd;

        private readonly Pen _selectionPen;

        public TestY()
        {
            _selectionPen = new Pen(Color.Black, 3.0f);

            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            MouseDown += (s, e) => {
                if (e.Button == MouseButtons.Left) 
                    _selectionStart = _selectionEnd = e.Location;
            };

            MouseUp += (s, e) => {
                if (e.Button == MouseButtons.Left) 
                {
                    _selectionStart = _selectionEnd = null; 
                    Invalidate(false); 
                }
            };

            MouseMove += (s, e) => {
                if (_selectionStart.HasValue &&
                    _selectionEnd.HasValue &&
                    _selectionEnd.Value != e.Location)
                {
                    _selectionEnd = e.Location;
                    Invalidate(false);
                }
            };

            Paint += (s, e) => {
                if (_selectionStart.HasValue && _selectionEnd.HasValue)
                    e.Graphics.DrawRectangle(_selectionPen, GetSelectionRectangle());
            };
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_selectionPen != null) _selectionPen.Dispose();
            }
            base.Dispose(disposing);
        }

        private Rectangle GetSelectionRectangle()
        {
            Rectangle rc = new Rectangle();

            if (_selectionStart.HasValue && _selectionEnd.HasValue)
            {
                // Normalize the rectangle.
                if (_selectionStart.Value.X < _selectionEnd.Value.X)
                {
                    rc.X = _selectionStart.Value.X;
                    rc.Width = _selectionEnd.Value.X - _selectionStart.Value.X;
                }
                else
                {
                    rc.X = _selectionEnd.Value.X;
                    rc.Width = _selectionStart.Value.X - _selectionEnd.Value.X;
                }

                if (_selectionStart.Value.Y < _selectionEnd.Value.Y)
                {
                    rc.Y = _selectionStart.Value.Y;
                    rc.Height = _selectionEnd.Value.Y - _selectionStart.Value.Y;
                }
                else
                {
                    rc.Y = _selectionEnd.Value.Y;
                    rc.Height = _selectionStart.Value.Y - _selectionEnd.Value.Y;
                }
            }

            return rc;
        }
    }
}