gpt4 book ai didi

c# - C#中的淡入淡出控制

转载 作者:太空狗 更新时间:2023-10-29 22:01:12 26 4
gpt4 key购买 nike

我正在尝试构建一个支持 Opcacity 属性的 Control 派生类。
此控件可以承载文本和图像,并且能够淡出和淡入它们。
这是我的代码:

internal class FadeControl : Control
{
private int opacity = 100;

public FadeControl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
}

public int Opacity
{
get
{
return opacity;
}
set
{
if (value > 100) opacity = 100;
else if (value < 1) opacity = 1;
else opacity = value;

if (Parent != null)
Parent.Invalidate(Bounds, true);
}
}

protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | 0x20;
return cp;
}
}

protected override void OnPaintBackground(PaintEventArgs e)
{
//do nothing
}

protected override void OnMove(EventArgs e)
{
RecreateHandle();
}

protected override void OnPaint(PaintEventArgs e)
{
using (Graphics g = e.Graphics)
{
Rectangle bounds = new Rectangle(0, 0, Width - 1, Height - 1);
int alpha = (opacity * 255) / 100;

using (Brush bckColor = new SolidBrush(Color.FromArgb(alpha, BackColor)))
{
if (BackColor != Color.Transparent)
g.FillRectangle(bckColor, bounds);
}

ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.Matrix33 = (float)alpha / 255;
ImageAttributes imageAttr = new ImageAttributes();
imageAttr.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

if (BackgroundImage != null)
g.DrawImage(BackgroundImage, bounds, 0, 0, Width, Height, GraphicsUnit.Pixel, imageAttr);

if (Text != string.Empty)
{
using (Brush txtBrush = new SolidBrush(Color.FromArgb(alpha, ForeColor)))
{
g.DrawString(Text, Font, txtBrush, 5, 5);
}
}
}
}

protected override void OnBackColorChanged(EventArgs e)
{
if (Parent != null)
Parent.Invalidate(Bounds, true);

base.OnBackColorChanged(e);
}

protected override void OnParentBackColorChanged(EventArgs e)
{
Invalidate();

base.OnParentBackColorChanged(e);
}
}

我已将控件放在一个带有计时器的窗体上。
计时器将控件的不透明度从 0 设置为 100 并返回,并且运行良好。
我试图解决的问题是控件在更改其不透明度时会闪烁。
将控件设置为 ControlStyles.DoubleBuffer 将使控件在窗体上不可见。

我们欢迎任何建议。

最佳答案

我无法同时使用双缓冲区和 WS_EX_TRANSPARENT (0x20) 作为透明背景。所以我决定通过复制父控件的内容来实现透明背景,并使用双缓冲区来防止闪烁。

以下是最终的源代码,经过测试可以正常工作:

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

internal class FadeControl : Control
{
private int opacity = 100;
private Bitmap backgroundBuffer;
private bool skipPaint;

public FadeControl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint, true);
}

public int Opacity
{
get
{
return opacity;
}
set
{
if (value > 100) opacity = 100;
else if (value < 1) opacity = 1;
else opacity = value;

if (Parent != null)
Parent.Invalidate(Bounds, true);
}
}

protected override void OnPaintBackground(PaintEventArgs e)
{
//do nothig
}

protected override void OnMove(EventArgs e)
{
RecreateHandle();
}

private void CreateBackgroundBuffer(Control parent)
{
int offsetX;
int offsetY;
GetOffsets(out offsetX, out offsetY, parent);
backgroundBuffer = new Bitmap(Width + offsetX, Height + offsetY);
}

protected override void OnResize(EventArgs e)
{
var parent = Parent;
if (parent != null)
{
CreateBackgroundBuffer(parent);
}
base.OnResize(e);
}

private void GetOffsets(out int offsetX, out int offsetY, Control parent)
{
var parentPosition = parent.PointToScreen(Point.Empty);
offsetY = Top + parentPosition.Y - parent.Top;
offsetX = Left + parentPosition.X - parent.Left;
}

private void UpdateBackgroundBuffer(int offsetX, int offsetY, Control parent)
{
if (backgroundBuffer == null)
{
CreateBackgroundBuffer(parent);
}
Rectangle parentBounds = new Rectangle(0, 0, Width + offsetX, Height + offsetY);
skipPaint = true;
parent.DrawToBitmap(backgroundBuffer, parentBounds);
skipPaint = false;
}

private void DrawBackground(Graphics graphics, Rectangle bounds)
{
int offsetX;
int offsetY;
var parent = Parent;
GetOffsets(out offsetX, out offsetY, parent);
UpdateBackgroundBuffer(offsetX, offsetY, parent);
graphics.DrawImage(backgroundBuffer, bounds, offsetX, offsetY, Width, Height, GraphicsUnit.Pixel);
}

private void Draw(Graphics graphics)
{
Rectangle bounds = new Rectangle(0, 0, Width, Height);
DrawBackground(graphics, bounds);

int alpha = (opacity * 255) / 100;

using (Brush bckColor = new SolidBrush(Color.FromArgb(alpha, BackColor)))
{
if (BackColor != Color.Transparent)
{
graphics.FillRectangle(bckColor, bounds);
}
}

ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.Matrix33 = (float)alpha / 255;
ImageAttributes imageAttr = new ImageAttributes();
imageAttr.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

if (BackgroundImage != null)
{
graphics.DrawImage(BackgroundImage, bounds, 0, 0, Width, Height, GraphicsUnit.Pixel, imageAttr);
}

if (Text != string.Empty)
{
using (Brush txtBrush = new SolidBrush(Color.FromArgb(alpha, ForeColor)))
{
graphics.DrawString(Text, Font, txtBrush, 5, 5);
}
}
}

protected override void OnPaint(PaintEventArgs e)
{
if (!skipPaint)
{
Graphics graphics = e.Graphics;
Draw(graphics);
}
}

protected override void OnBackColorChanged(EventArgs e)
{
if (Parent != null)
{
Parent.Invalidate(Bounds, true);
}
base.OnBackColorChanged(e);
}

protected override void OnParentBackColorChanged(EventArgs e)
{
Invalidate();
base.OnParentBackColorChanged(e);
}
}

请注意,CreateParams 方法不再存在,我也更改了构造函数。

字段 skipPaint 是为了能够告诉父级在 OnPaint 期间将自己绘制到位图而无需无限递归来知道何时不绘制.

backgroundBuffer 不是实现双缓冲,而是在没有呈现控件的情况下保留父级内容的副本。它会在每次绘制时更新,我知道有更有效的解决方案...* 但这种方法保持简单并且不应该成为瓶颈,除非您在同一个容器上有太多这样的控件。

*:更好的解决方案是每次父级失效时更新它。此外,在同一父级中的所有 FadeControl 之间共享它。

关于c# - C#中的淡入淡出控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15501501/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com