在C#中闪烁做一个SlideButton(DoubleBuffer显然不工作) [英] Flickering in C# doing a SlideButton (DoubleBuffer not working apparently)

查看:247
本文介绍了在C#中闪烁做一个SlideButton(DoubleBuffer显然不工作)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我简单地做了一个SlideButton控件:这是代码:

 使用System; 
使用System.Collections.Generic;
使用System.ComponentModel;
使用System.Drawing;
使用System.Data;
使用System.Linq;
使用System.Text;
使用System.Threading.Tasks;
使用System.Windows.Forms;
使用System.Diagnostics;
使用System.ComponentModel.Design;

namespace DELTA.UI.Search
{
[Designer(System.Windows.Forms.Design.ParentControlDesigner,System.Design,typeof(IDesigner))]
public partial class SlideControl:UserControl
{
public Boolean IsShown
{
get {return button.IsOpen; }
set
{
button.IsOpen = value;
}
}

private int isShownHeight;
$ b $ public Slide()
{
InitializeComponent();
this.SetStyle(
System.Windows.Forms.ControlStyles.UserPaint |
System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
System.Windows.Forms.ControlStyles.Opaque |
System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer,
true);
this.DoubleBuffered = true;
this.ResizeRedraw = true;
isShownHeight = this.Height;
this.Height = button.Height;
}

private void boton_MouseEnter(object sender,EventArgs e)
{
button.BackColor = Color.Gray;
button.Cursor = Cursors.Hand;
}

private void boton_MouseLeave(object sender,EventArgs e)
{
button.BackColor = Color.White;
button.Cursor = Cursors.Arrow;
}

private void button_OnSlideStateChangedEvent(bool isOpen)
{
Debug.WriteLine(isOpen);
if(!timerSlide.Enabled)
{
timerSlide.Start();



protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e); (b,0,this.Width,this.Height);

using

int rectWidth = this.Width / 10;
e.Graphics.FillRectangle(Brushes.LightGray,this.Width / 2 - rectWidth / 2,this.Height - 3,rectWidth,3);
}

private void timerSlide_Tick(object sender,EventArgs e)
{
if(IsShown&& this.Height + button.Height< isShownHeight)
{
int crecimiento =(isShownHeight - button.Height)/ 35;
this.Height + = this.Height + crecimiento> = isShownHeight? isShownHeight - this.Height:crecimiento;
}
else if(!IsShown& this.Height> button.Height)
{
int decrecimiento =(isShownHeight - button.Height)/ 35;
this.Height - = this.Height - decrecimiento< = button.Height? this.Height - button.Height:decrecimiento;
}
else
{
timerSlide.Stop();



private void Slide_Resize(object sender,EventArgs e)
{
//this.Invalidate(new Rectangle(0,this。高度 - 12,this.Width,12));



code
$ b

正如你所看到的,我只做了油漆操作,是在控制器底部的一个小直肠鹰的油漆。这些控件只包含一个带有isOpen标志的自定义按钮,该标志在单击时发生更改并触发OnSlideStateChangedEvent事件。该按钮的代码是:

 使用DELTA.Util; 
使用System;
使用System.Collections.Generic;
使用System.ComponentModel;
使用System.Diagnostics;
使用System.Drawing;
使用System.Linq;
使用System.Text;
使用System.Threading.Tasks;
使用System.Windows.Forms;

namespace DELTA.UI.Search
{
class SlideButton:Button
{
private Boolean isOpen = true;
public Boolean IsOpen
{
get {return isOpen; }
set
{
isOpen = value;

/ *刷新新出现的按钮* /
this.Refresh();
$ b $ *如果(OnSlideStateChangedEvent!= null)调用事件* /

OnSlideStateChangedEvent(isOpen);


$ b公共SlideButton()
:base()
{
this.BackColor = Color.White;
if(!DesignMode)
IsOpen = false;

this.DoubleBuffered = true;
}

///< summary>
///幻灯片事件
///< / summary>
[Category(ClickCustomEvents)]
[Description(点击时触发)]
公共事件OnSlideStateChanged OnSlideStateChangedEvent;
///< summary>
///更改状态的代表
///< / summary>
///< param name =isOpen>< / param>
public delegate void OnSlideStateChanged(Boolean isOpen);

///< summary>
///覆盖以避免默认的OnClick
///< / summary>
///< param name =e>< / param>
protected override OnClick(EventArgs e)
{
IsOpen =!isOpen;


protected override void OnPaint(PaintEventArgs e)
{
// TODO使用isOpen值绘制一个填充的rectagle或2个边框

/ *设置 - >打开/关闭按钮的状态* /
颜色topColor = Color.LightGray;
颜色otherSidesColor = Color.LightGray;
颜色backgroud = Color.LightGray;
SingletonImages arrow = SingletonImages.ARROW_DOWN;
Rectangle arrowPosition = new Rectangle(this.Width - 30,this.Height - 26,20,20);

if(isOpen)
{
topColor = Color.LightGray;
otherSidesColor = Color.Transparent;
backgroud = Color.White;
arrow = SingletonImages.ARROW_UP;

$ b / * PAINT ZONE * /
/ *背景* /
使用(SolidBrush brush = new SolidBrush(backgroud))
e.Graphics .FillRectangle(brush,new Rectangle(0,0,this.Width,this.Height));

/ * Border * /
ControlPaint.DrawBorder(e.Graphics,this.ClientRectangle,
otherSidesColor,2,ButtonBorderStyle.Solid,
topColor,2,ButtonBorderStyle .Solid,
otherSidesColor,2,ButtonBorderStyle.Solid,
otherSidesColor,2,ButtonBorderStyle.Solid);

/ *文字 - > Padding = 5(这可以根据需要改变为使用控件的padding属性)* /
e.Graphics.DrawString(this.Text,this.Font,Brushes.Black,new Point(10,8) );

/ *箭头* /
e.Graphics.DrawImage(arrow.Image,arrowPosition);



$ / code $ / pre
$ b

SingletonImages只是一个枚举来保存图像,以便只有一个实例。



我将SlideButton类的DoubleBuffered属性更改为true,但那是不必要的原因SlideButton没有flickr。闪烁的是Slide类。如果你需要更多的信息请问你想要什么。任何提示?

解决方案

有一天我遇到了这个问题。最简单的(也许不是最优雅的)解决方案是删除 OnPaintBackground()并将其添加到正常的 OnPaint()方法,因为否则在每次控制失效时,背景会涂在您上次的Gfx上导致闪烁的原因:

  public ctor ()
{
//这可以用OptimizedDoubleBuffer设置为true
this.SetStyle(ControlStyles.OptimizedDoubleBuffer,true);


protected override void OnPaintBackground(PaintEventArgs e)
{
//不要在此处绘制背景,而是在OnPaint()中绘制背景以防止闪烁!
//base.OnPaintBackground(e);
}

protected override void OnPaint(PaintEventArgs e)
{
//先做背景和基础材料(如果需要的话)
base。 OnPaintBackground(E);
base.OnPaint(e);

// ...定制颜色代码在这里...
}

您可以试试看,祝您好运。


i got a problem with flickering in C# WinForms proyect.

I simply made a SlideButton control: this is the code:

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

namespace DELTA.UI.Search
{
    [Designer("System.Windows.Forms.Design.ParentControlDesigner,System.Design", typeof(IDesigner))]
    public partial class Slide : UserControl
    {
        public Boolean IsShown
        {
            get { return button.IsOpen; }
            set
            {
                button.IsOpen = value;
            }
        }

        private int isShownHeight;

        public Slide()
        {
            InitializeComponent();
            this.SetStyle(
                System.Windows.Forms.ControlStyles.UserPaint |
                System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
                System.Windows.Forms.ControlStyles.Opaque |
                System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer,
                true);
            this.DoubleBuffered = true;
            this.ResizeRedraw = true;
            isShownHeight = this.Height;
            this.Height = button.Height;
        }

        private void boton_MouseEnter(object sender, EventArgs e)
        {
            button.BackColor = Color.Gray;
            button.Cursor = Cursors.Hand;
        }

        private void boton_MouseLeave(object sender, EventArgs e)
        {
            button.BackColor = Color.White;
            button.Cursor = Cursors.Arrow;
        }

        private void button_OnSlideStateChangedEvent(bool isOpen)
        {
            Debug.WriteLine(isOpen);
            if (!timerSlide.Enabled)
            {
                timerSlide.Start();
            }
        }

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

            using (Brush b = new SolidBrush(this.BackColor))
                e.Graphics.FillRectangle(b, 0, 0, this.Width, this.Height);

            int rectWidth = this.Width / 10;
            e.Graphics.FillRectangle(Brushes.LightGray, this.Width / 2 - rectWidth / 2, this.Height - 3, rectWidth, 3);
        }

        private void timerSlide_Tick(object sender, EventArgs e)
        {
            if (IsShown && this.Height + button.Height < isShownHeight)
            {
                int crecimiento = (isShownHeight - button.Height) / 35;
                this.Height += this.Height + crecimiento >= isShownHeight ? isShownHeight - this.Height : crecimiento;
            }
            else if (!IsShown && this.Height > button.Height)
            {
                int decrecimiento = (isShownHeight - button.Height) / 35;
                this.Height -= this.Height - decrecimiento <= button.Height ? this.Height - button.Height : decrecimiento;
            }
            else
            {
                timerSlide.Stop();
            }
        }

        private void Slide_Resize(object sender, EventArgs e)
        {
            //this.Invalidate(new Rectangle(0, this.Height - 12, this.Width, 12));
        }
    }
}

As you can see, the only paint operation i make is the paint of a small rectagle in the bottom of the control. The controls just contain a custom buttom with a isOpen flag that changes when clicked and fires the OnSlideStateChangedEvent event. The code of the button is:

using DELTA.Util;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DELTA.UI.Search
{
    class SlideButton : Button
    {
        private Boolean isOpen = true;
        public Boolean IsOpen
        {
            get { return isOpen; }
            set
            {
                isOpen = value;

                /* Refresh the button with the new appearence */
                this.Refresh();

                /* Call the event */
                if (OnSlideStateChangedEvent != null)
                    OnSlideStateChangedEvent(isOpen);
            }
        }

        public SlideButton()
            : base()
        {
            this.BackColor = Color.White;
            if (!DesignMode)
                IsOpen = false;

            this.DoubleBuffered = true;
        }

        /// <summary>
        /// Event for the Slide
        /// </summary>
        [Category("ClickCustomEvents")]
        [Description("Fired when this is clicked")]
        public event OnSlideStateChanged OnSlideStateChangedEvent;
        /// <summary>
        /// Delegate for the Change of state
        /// </summary>
        /// <param name="isOpen"></param>
        public delegate void OnSlideStateChanged(Boolean isOpen);

        /// <summary>
        /// Override to avoid the default OnClick
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClick(EventArgs e)
        {
            IsOpen = !isOpen;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            // TODO Use the isOpen value to paint it with a filled rectagle or 2 borders

            /* SETTINGS -> for open/close states of the button */
            Color topColor = Color.LightGray;
            Color otherSidesColor = Color.LightGray;
            Color backgroud = Color.LightGray;
            SingletonImages arrow = SingletonImages.ARROW_DOWN;
            Rectangle arrowPosition = new Rectangle(this.Width - 30, this.Height - 26, 20, 20);

            if (isOpen)
            {
                topColor = Color.LightGray;
                otherSidesColor = Color.Transparent;
                backgroud = Color.White;
                arrow = SingletonImages.ARROW_UP;
            }

            /* PAINT ZONE */
            /* Background */
            using (SolidBrush brush = new SolidBrush(backgroud))
                e.Graphics.FillRectangle(brush, new Rectangle(0, 0, this.Width, this.Height));

            /* Border */
            ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle,
            otherSidesColor, 2, ButtonBorderStyle.Solid,
            topColor, 2, ButtonBorderStyle.Solid,
            otherSidesColor, 2, ButtonBorderStyle.Solid,
            otherSidesColor, 2, ButtonBorderStyle.Solid);

            /* Text -> Padding = 5 (This can be changed to use the padding property of the control if need) */
            e.Graphics.DrawString(this.Text, this.Font, Brushes.Black, new Point(10, 8));

            /* Arrow */
            e.Graphics.DrawImage(arrow.Image, arrowPosition);
        }
    }
}

SingletonImages is just a "enum" to hold images in order to have just one instance of it.

I changed the DoubleBuffered property of the SlideButton class to true but that was unnecesary cause the SlideButton didn't flickr. The one that flickers is the Slide class. If you need more info ask for what you want. Any tip?

解决方案

One day I ran into this problem as well. The simplest (maybe not the most elegant) solution was to remove the OnPaintBackground() and add it into the normal OnPaint() method because otherwise the background is painted onto your last Gfx each time the control is invalidated what causes the flickering:

    public ctor()
    {
        // this does just work with OptimizedDoubleBuffer set to true
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        // do NOT paint the background here but in OnPaint() to prevent flickering!
        //base.OnPaintBackground(e);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        // do the background and the base stuff first (if required)
        base.OnPaintBackground(e);
        base.OnPaint(e);

        // ... custom paint code goes here ...
    }

You might give it a try, good luck.

这篇关于在C#中闪烁做一个SlideButton(DoubleBuffer显然不工作)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆