65.9K
CodeProject 正在变化。 阅读更多。
Home

带阴影和动画的标签

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.38/5 (15投票s)

2008 年 3 月 12 日

CPOL

3分钟阅读

viewsIcon

46070

downloadIcon

2029

一个具有阴影效果的标签,可以使用旋转、透明度和缩放进行动画处理。

引言

文章中解释的控件是一个带有阴影效果的标签,并添加了透明度、缩放和旋转的动画。 这是用 C# 和 .NET 2.0 完成的(在 .NET 3.5 中测试并且工作正常)。

背景

我需要一个具有炫酷效果的文本控件来完成一个项目,所以我决定制作一个独立的控件。

使用代码

您可以使用两种标准方法使用该控件

  • 在您的解决方案中包含项目“dzzControls”,以便它自动出现在工具箱中(在 *dzzControls* 部分中),但它具有通用图标。
  • 在工具箱中,右键单击“常规”,然后单击“选择项...”。 单击“浏览”并找到“*dzzControls.dll*”。 确保选中“EffectsLabel”旁边的复选框,然后单击“确定”。

现在,将其拖放到窗体上。 在“属性”中,选择“分类”视图,然后转到“效果”部分。 摆弄属性(更改立即在设计器中可见)。

该控件公开了一些属性

  • ShadowColor,与 ForeColorBackColor 结合使用,会影响控件的着色。
  • 仅当 ShadowOffset 与默认值 0; 0 不同时,ShadowColor 才有意义。 X 和 Y 值可以为负!
  • 如果 MinZoom 低于 100,控件将使用 100% 和设置的最小百分比之间的渐变缩放进行动画处理。
  • 如果 MinAlpha 小于 MaxAlpha,控件将使用给定值之间的逐渐变化的透明度进行动画处理。
  • 如果 MinRotate 小于 MaxRotate,控件将使用指定角度(以度为单位)之间的逐渐旋转的文本进行动画处理。 注意:这些值限制为 sbyte(-128 到 +127),因此更改这些值以满足您自己的需求是一个简单的练习。
  • Letterwise 指定效果是应用于单个字母还是应用于整个字符串(从 Control 继承的 Text 属性)。

幕后花絮

继承的属性 TextFontForeColorEnabled 被重写以适应特定于控件的逻辑。

新的属性(如上所述)都使用私有变量实现,并且 setter 通常包含一些代码(用于刷新控件或类似操作)。 例如

private byte _MinZoom;
[Category("Effects"), DefaultValue((byte)100),
Description("Animate text zoom, in range MinZoom%-100%")]
public byte MinZoom
{
    get { return _MinZoom; }
    set
    {
        _MinZoom = value <= 100 ? value : (byte)100;
        if (_MinZoom == 0)
            _MinZoom = 1;
        if (_CurrentZoom < _MinZoom)
            _CurrentZoom = _MinZoom;
        if (_MinZoom < 100)
        {
            aTimer.Start();
        }
        else
            RecalculateTimer();
        Refresh();
    }
}

还有一些私有变量包含动画的当前状态,例如

private byte _CurrentZoom;
private sbyte _ZoomStep = 1;

动画是使用内部计时器(称为 aTimer,超时时间为 20 毫秒 - 相当于 50fps)实现的。 当计时器滴答时,执行动画的一个步骤

private void aTimer_Tick(object sender, EventArgs e)//animation timer tick
{
    ...
    if (_MinZoom < 100)//zoom animation enabled?
    {
        if (_CurrentZoom == 100)
            _ZoomStep = (sbyte)-1;
        if (_CurrentZoom == _MinZoom)
            _ZoomStep = (sbyte)1;
        _CurrentZoom = (byte)(_CurrentZoom + _ZoomStep);
    }
    Refresh();//redraw control
}

当文本、字体、最小或最大旋转更改时,内部过程 RecalculateSize 会重新调整控件的大小。 它还计算单个字符的大小,这些大小在 paint 事件处理程序中使用。

这个自定义控件的大脑是 OnPaint 事件处理程序,它太大了,无法在此处完全解释,但基本版本是

e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
//rotation is not smooth without anti-aliasing
e.Graphics.TranslateTransform(Size.Width / 2, Size.Height / 2);
//set coordinate system origin to center of the control
if (_CurrentRotate != 0)
    e.Graphics.RotateTransform(_CurrentRotate); //apply rotation ...
if (_CurrentZoom < 100)
    e.Graphics.ScaleTransform(_CurrentZoom / 100.0f, _CurrentZoom / 100.0f);
    //... and zoom
e.Graphics.DrawString(Text, Font, new SolidBrush(base.ForeColor), 
                      -tsize.Width / 2, -tsize.Height / 2);
//draw text in coordinate system, so text's 
//center matches coordinate system's center

注意:大多数属性都是整数类型(intbytesbyte)。 这足以满足我当前的需求,将这些更改为 float 应该是读者的一项不错的练习。

一些问题

当使用超长字符串时(我在使用此控件时遇到),如果启用动画,该控件往往会对处理器造成很高的负载。

如果在窗体上启用动画或控件在窗体上移动(因此重复重绘),则这些控件中的多个也往往会产生很高的处理器使用率。

关注点

MeasureCharacterRanges 限制为仅 32 个测量范围使我不得不重写字母顺序情况的 OnPaint(在花费一些时间进行调试后)。

由于这是我的第一个控件,我还花了很多时间使控件“对设计器友好”,例如

[Category("Effects"), DefaultValue(typeof(Point), "0, 0"),
Description("If differs from (0,0), creates shadow" + 
            " with specified offset from Left and Top")]
public Point ShadowOffset
{
    get { ...

... 因此,如果未设置,则此属性在 Visual Studio 属性网格中不会加粗。

历史

  • 本文的第一个版本写于 2008 年 3 月 11 日。
  • 2008 年 3 月 12 日:对源代码进行了小幅修改 + 一些不需要的属性从 Visual Studio 设计器属性网格中隐藏(使用了 Bob Powell 提供的代码)。
  • 2008 年 3 月 24 日:用新的演示应用程序替换了旧的演示应用程序(旧的演示应用程序需要带有控件的 DLL)。
© . All rights reserved.