【问题标题】:Fade a color to white (increasing brightness)将颜色淡化为白色(增加亮度)
【发布时间】:2009-04-02 18:06:28
【问题描述】:

我想在 .NET 中制作一个文本框“发光”黄色,然后“淡化”为白色(基本上,通过逐渐增加亮度)。我认为 Stackoverflow 在您发布答案后会这样做。我知道增加亮度并不是那么简单(它不仅仅是均匀地增加/减少 RGB),但我不知道该怎么做。

完美的色彩准确度对此并不重要。我正在使用 C#,虽然 VB 示例也可以。

编辑:这是为 Winforms 准备的。

【问题讨论】:

    标签: c# .net winforms colors interpolation


    【解决方案1】:

    这可能比你需要的多,这是我使用的类的代码:

    public class ControlColorAnimator
    {
        private const int INTERVAL = 100;
    
        private readonly decimal _alphaIncrement;
        private readonly decimal _blueIncrement;
        private readonly Color _endColor;
        private readonly decimal _greenIncrement;
        private readonly int _iterations;
        private readonly decimal _redIncrement;
        private readonly Color _startColor;
    
        private decimal _currentAlpha;
        private decimal _currentBlueValue;
        private decimal _currentGreenValue;
        private decimal _currentRedValue;
    
        private Timer _timer;
    
        public ControlColorAnimator(TimeSpan duration, Color startColor, Color endColor)
        {
            _startColor = startColor;
            _endColor = endColor;
            resetColor();
    
            _iterations = duration.Milliseconds / INTERVAL;
            _alphaIncrement = ((decimal) startColor.A - endColor.A) / _iterations;
            _redIncrement = ((decimal) startColor.R - endColor.R) / _iterations;
            _greenIncrement = ((decimal) startColor.G - endColor.G) / _iterations;
            _blueIncrement = ((decimal) startColor.B - endColor.B) / _iterations;
        }
    
        public Color CurrentColor
        {
            get
            {
                int alpha = Convert.ToInt32(_currentAlpha);
                int red = Convert.ToInt32(_currentRedValue);
                int green = Convert.ToInt32(_currentGreenValue);
                int blue = Convert.ToInt32(_currentBlueValue);
    
                return Color.FromArgb(alpha, red, green, blue);
            }
        }
    
        public event EventHandler<DataEventArgs<Color>> ColorChanged;
    
        public void Go()
        {
            disposeOfTheTimer();
            OnColorChanged(_startColor);
    
            resetColor();
    
            int currentIteration = 0;
            _timer = new Timer(delegate
                {
                    if (currentIteration++ >= _iterations)
                    {
                        Stop();
                        return;
                    }
                    _currentAlpha -= _alphaIncrement;
                    _currentRedValue -= _redIncrement;
                    _currentGreenValue -= _greenIncrement;
                    _currentBlueValue -= _blueIncrement;
                    OnColorChanged(CurrentColor);
                }, null, TimeSpan.FromMilliseconds(INTERVAL), TimeSpan.FromMilliseconds(INTERVAL));
        }
    
        public void Stop()
        {
            disposeOfTheTimer();
            OnColorChanged(_endColor);
        }
    
        protected virtual void OnColorChanged(Color color)
        {
            if (ColorChanged == null) return;
            ColorChanged(this, color);
        }
    
        private void disposeOfTheTimer()
        {
            Timer timer = _timer;
            _timer = null;
    
            if (timer != null) timer.Dispose();
        }
    
        private void resetColor()
        {
            _currentAlpha = _startColor.A;
            _currentRedValue = _startColor.R;
            _currentGreenValue = _startColor.G;
            _currentBlueValue = _startColor.B;
        }
    }
    

    这使用DataEventArgs&lt;T&gt;(如下所示)

    /// <summary>
    /// Generic implementation of <see cref="EventArgs"/> that allows for a data element to be passed.
    /// </summary>
    /// <typeparam name="T">The type of data to contain.</typeparam>
    [DebuggerDisplay("{Data}")]
    public class DataEventArgs<T> : EventArgs
    {
        private T _data;
    
        /// <summary>
        /// Constructs a <see cref="DataEventArgs{T}"/>.
        /// </summary>
        /// <param name="data">The data to contain in the <see cref="DataEventArgs{T}"/></param>
        [DebuggerHidden]
        public DataEventArgs(T data)
        {
            _data = data;
        }
    
        /// <summary>
        /// Gets the data for this <see cref="DataEventArgs{T}"/>.
        /// </summary>
        public virtual T Data
        {
            [DebuggerHidden]
            get { return _data; }
            [DebuggerHidden]
            protected set { _data = value; }
        }
    
        [DebuggerHidden]
        public static implicit operator DataEventArgs<T>(T data)
        {
            return new DataEventArgs<T>(data);
        }
    
        [DebuggerHidden]
        public static implicit operator T(DataEventArgs<T> e)
        {
            return e.Data;
        }
    }
    

    像这样在你的表单中使用:

    private ControlColorAnimator _animator;
    
    private void runColorLoop()
    {
        endCurrentAnimation();
        startNewAnimation();
    }
    
    private void endCurrentAnimation()
    {
        ControlColorAnimator animator = _animator;
        _animator = null;
        if (animator != null)
        {
            animator.ColorChanged -= _animator_ColorChanged;
            animator.Stop();
        }
    }
    
    private void startNewAnimation()
    {
        _animator = new ControlColorAnimator(TimeSpan.FromSeconds(.6), Color.Yellow, BackColor);
        _animator.ColorChanged += _animator_ColorChanged;
        _animator.Go();
    }
    
    private void _animator_ColorChanged(object sender, DataEventArgs<Color> e)
    {
        invokeOnFormThread(delegate { setColor(e); });
    }
    
    private void setColor(Color color)
    {
        // code to set color of the controls goes here
    }
    
    private void invokeOnFormThread(MethodInvoker method)
    {
        if (IsHandleCreated)
            Invoke(method);
        else
            method();
    }
    

    【讨论】:

    • 这很聪明,谢谢 :) 我已经修改了它(传递一个 Hide 参数,所以当动画结束时,控件被隐藏)并将它添加到我的基类中,现在我所有的继承形式可能会覆盖 setColor 并使用它。我还没有找到一种优雅的方法来传递将发生动画的控件,而不是在 setColor 中“硬编码”它。有什么想法吗?
    • 没试过,但可能是控件上的扩展方法……那你可以这样称呼它“invokeOnFormThread(myControl.SetColor(e));”
    • 谢谢,会调查的。同时,我修改了 runColorLoop() 以便我可以传递颜色、持续时间、控件,如果我想在动画结束后隐藏,这样我就可以在我的基类中使用所有这些,并且每个继承form 可以使用 base.runColorLoop(x,y,z,f);
    【解决方案2】:

    只需根据时间在颜色之间进行插值。

    如果你的橙色是 (r1,g1,b1) 并且你希望淡化成不同的颜色 (r2,g2,b2),线性插值的公式是 (r1 + (r2-r1) * t, g1 + (g2-g1) * t, b1 + (b2-b1) * t),其中 t 在 [0.0 1.0] 范围内。

    在您的示例中,您的第一种颜色可能类似于 (255,200,0),而您的第二种颜色可能是 (255,255,255)。

    如果您希望过渡更平滑,请查找不同的插值方式。

    【讨论】:

      【解决方案3】:

      如果您想快速顺利地完成,请查看 ColorMatrix 类。

      【讨论】:

      • 不是 ColorMatrix 更多还是改变图像的颜色?
      【解决方案4】:

      当我提交此答案时,您最初并没有指定技术,但这里是您使用 jQuery 的方法。

      UI/Effects/Highlight.

      $("div").click(function () {
            $(this).effect("highlight", {}, 3000);
      });
      

      【讨论】:

      • 呸,显然未来是“电子伴侣”上“云”中的“网络应用程序”。所以他应该将 Webkit 包装在他的应用程序中,并使用它支持的 CSS 效果和动画!
      • 在编辑中,他说“winforms”。最初,当我回复时,它只提到了这里对 SO 的影响,没有提到 WinForms。
      • 这是因为人们用错误的技术来回答的危险。我建议限定答案以避免急切的投票者:“你没有说什么技术,但这是我在 jQuery 中的做法......”
      猜你喜欢
      • 1970-01-01
      • 2017-04-26
      • 2015-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-06
      • 2012-11-05
      • 1970-01-01
      相关资源
      最近更新 更多