[英]How can I fade in/out an image to make effect that the screen get dark slowly?
[英]How can i make on the pixels fade in/out like effect?
今天,即时通讯正在绘制事件中的像素闪烁。 在form1中,我在计时器滴答事件中将此代码设置为1000ms。
private void timer1_Tick(object sender, EventArgs e)
{
CloudEnteringAlert.cloudColorIndex = (CloudEnteringAlert.cloudColorIndex + 1) % CloudEnteringAlert.cloudColors.Length;
pictureBox1.Invalidate();
}
在CloudEntering类中,我位于顶部:
public static Brush[] cloudColors = new[] { Brushes.Yellow, Brushes.Transparent };
然后在paint方法中,此paint方法是从form1 pictureBox1 paint事件调用的:
foreach (PointF pt in clouds)
{
e.FillEllipse(cloudColors[cloudColorIndex], pt.X * (float)currentFactor, pt.Y * (float)currentFactor, 7f, 7f);
}
所以我现在看到的是像素为黄色的一秒钟,像素为透明的一秒钟。
现在我想做的是:
每个像素将从半径5开始。
每个像素半径将增大到25。
动画将自上而下。
到达半径25的每个像素将开始变小,回到半径5。
当第一个像素从5开始时将变为半径15,下一个像素将开始变得更大。
因此,如果第一个像素从5开始,现在是15,那么下一个像素将开始变大,第一个像素将继续增加到25,而第一个像素是25时它将变小。 第二个在其15时变大,第三个将变大,依此类推。
所有像素将以半径5开始,但是只有第一个像素开始变大,然后变为15,然后是下一个像素;当第一个为25时,它将变小。
这是每个像素之间的时间。
并且每个像素半径大小的变化应花费300ms!
我该怎么做 ?
首先,您需要将渲染单个椭圆所需的所有信息封装到一个单独的类中。 就像这样:
public class Ellipse
{
public PointF Center { get; set; }
public Brush Brush { get; set; }
public float Diameter { get; set; }
public float DiameterDelta { get; set; }
public Ellipse(float x, float y)
{
Center = new PointF(x, y);
Brush = Brushes.Blue;
Diameter = 5;
DiameterDelta = 1;
}
}
Ellipse.DiameterDelta
属性是将用于动画的delta值,它可以是正值(从直径5
到直径25
),也可以是负值(反向时)。 此属性的值(我在上面使用过1
)和Timer.Interval
一起将影响动画的速度。
更好的OOP设计可能会主张将动画相关的属性移出此类,但为简单起见,最好从此开始。
在您的计时器事件中,您可能会遇到以下情况:
private void timer_Tick(object sender, EventArgs e)
{
// presuming that you made a separate user control
// which has a collection of ellipses in a `Clouds` property
foreach (var c in cloudBox.Clouds)
Animate(c);
cloudBox.Invalidate();
}
private void Animate(Ellipse c)
{
// update diameter
c.Diameter += c.DiameterDelta;
// when you reach bounds, change delta direction
if ((c.DiameterDelta < 0 && c.Diameter <= 5) ||
(c.DiameterDelta > 0 && c.Diameter >= 25))
c.DiameterDelta = -c.DiameterDelta;
}
为了获得平滑,不闪烁的动画,您很可能必须使用在其构造函数中设置了ControlStyles.AllPaintingInWmPaint
和ControlStyles.OptimizedDoubleBuffer
的自定义控件,所以我要做的不是PictureBox
,而是:
public partial class CloudBox : UserControl
{
public CloudBox()
{
InitializeComponent();
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw, true);
}
private readonly List<Ellipse> _clouds = new List<Ellipse>();
public List<Ellipse> Clouds
{
get { return _clouds; }
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
foreach (var cloud in _clouds)
{
e.Graphics.FillEllipse(
cloud.Brush, cloud.Center.X, cloud.Center.Y,
cloud.Diameter, cloud.Diameter);
}
base.OnPaint(e);
}
}
我尚未对此进行测试,但我相信您可以填写详细信息。 将Timer.Interval
设置为10或20 ms应该会产生非常流畅的动画恕我直言。
[编辑]要用一些测试数据实例化整个事情(我不知道从哪里获得),可以在Form.Load
事件处理程序中使用类似以下内容的东西:
for (int i = 0; i < 400; i += 50)
for (int j = 0; j < 400; j += 50)
cloudBox.Clouds.Add(new Ellipse(i, j));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.