将Timer添加到Custom Control以制作闪烁光标

时间:2016-07-26 15:46:35

标签: c# winforms timer controls custom-controls

不知何故,我设法让自己再次进入一个地方,Google或我的问题措辞都没有给我一个解决方案。

所以,就这样说,我从头开始创建TextBox,派生自System.Windows.Forms.Control。到目前为止,我已经能够绘制Text变量,并且还为其添加了编辑功能(通常像普通TextBox一样)。

可怕的耗时练习的想法是创建我自己的自定义控件库,这些控件具有最大的主题功能,可以与我开发的软件一起使用。

所以,我的问题:TextBox中绘制闪烁的光标。

我能够绘制一条静态线,它根据CursorPosition所取的位置从左向右移动。通过if(blinker)向控件添加了一个计时器(因此System.Timers.Timer)并尝试了System.Windows.Forms.Timer但是在添加控件时不允许我设置任何属性而弄乱了我的Designer到一个表格,仍然没有启动我的绘图事件。我确实在Invalidate(_Cursor)事件中放置了Tick,以确保只重绘Cursor位置,即使没有参数也尝试过,但仍无济于事。

protected override void OnPaint(PaintEventArgs e)
{
    ...
    if (Focused)
    {
        if (blinker)
            e.Graphics.FillRectangle(new SolidBrush(_CursorColor), _Cursor);
        foreach (Rectangle border in Borders)
        {
            if(_DrawBorders[Borders.IndexOf(border)])
                e.Graphics.FillRectangle(new SolidBrush(BorderColor), border);
        }
    }
    ...
}

我也设置了

DoubleBuffered = true;
SetStyle(ControlStyles.UserPaint | ControlStyles.Selectable | ControlStyles.ResizeRedraw | 
ControlStyles.OptimizedDoubleBuffer | ControlStyles.StandardClick | ControlStyles.AllPaintingInWmPaint, true);

这有助于我遇到的可怕的闪烁和输入问题。

EDIT **(REMOVED AS IT IS FIXED USING COMMENT BY Hans Passant's SUGGESTION )**

好的,现在定时器正在工作,解决了我上面提到的问题。绘制光标。

    private void _CursorBlinkTime_Tick(object sender, EventArgs e)
    {
        blinker = !blinker;
        Console.WriteLine("Blink!");
        Invalidate();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Height = TextRenderer.MeasureText("A", Font).Height + (2 * BorderWidth) + (2 * TextPadding);
        CursorPosition = (BorderWidth + TextPadding) + (_SelectedStart * (TextRenderer.MeasureText("_", Font).Width));
        _InputBounds = new Rectangle(BorderWidth + TextPadding, BorderWidth + TextPadding, Width - (2 * BorderWidth) - (2 * TextPadding), Height - (2 * BorderWidth));
        base.OnPaint(e);
        e.Graphics.Clear(BackColor);

        e.Graphics.DrawString(Text, Font, new SolidBrush(TextColor), _InputBounds.Location);
        foreach (Rectangle border in Borders)
        {
            if (_DrawBorders[Borders.IndexOf(border)])
                e.Graphics.FillRectangle(new SolidBrush(InactiveBorderColor), border);
        }

        if (Focused)
        {
            // This is where the Cursor is drawn, right before the borders.
            // I've tried to move it to after the border is drawn but same result, nothing is drawn.
            // I've ran through the entire OnPaint using Step-by-Step and while it does
            // fire the draw event, nothing is drawn.
            // BackColor = FromArgb(40,40,40), _CursorColor = Color.Red
            // _Cursor is a Rectangle that reads at this moment:
            // Rectangle(5,0,2,21) Which given all other variables should show result?
            if (blinker)
                e.Graphics.FillRectangle(new SolidBrush(_CursorColor), _Cursor);
            foreach (Rectangle border in Borders)
            {
                if(_DrawBorders[Borders.IndexOf(border)])
                    e.Graphics.FillRectangle(new SolidBrush(BorderColor), border);
            }
        }
        else if (!Focused)
        {
            if(string.IsNullOrWhiteSpace(Text))
                e.Graphics.DrawString(WaterMarkText, Font, new SolidBrush(WaterMarkColor), _InputBounds.Location);
        }
    }

1 个答案:

答案 0 :(得分:0)

好吧,所以在我决定放弃并停止尝试之后,我删除了光标的每一条痕迹,并开始重新绘制它。得到了修复。然后我回去看望计时器,并认为当不使用从System.Windows.Forms.Form派生的类时,System.Windows.Forms.Timer会让你认为自己已经拥有的每一盎司都变得混乱。所以,我转到了System.Timers.Timer(我之前在Mobile Development上使用过,取得了巨大的成功)。

我遇到的所有问题现已解决,再次感谢您的帮助!我爱这个地方。

以下是代码更改:

    private double _CursorInterval;
    /// <summary>
    /// Values below 500ms not recommended, due to safety hazards on epilepsy.
    /// </summary>
    public double CursorInterval
    {
        get { return _CursorInterval; }
        set { _CursorInterval = value; }
    }

    private bool blink = false;

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        Height = TextRenderer.MeasureText("A", Font).Height + (2 * BorderWidth) + (2 * TextPadding);
        _InputBounds = new Rectangle(BorderWidth + TextPadding, BorderWidth + TextPadding, Width - (2 * BorderWidth) - (2 * TextPadding), Height - (2 * BorderWidth) - (2 * TextPadding));

        if (blink)
            e.Graphics.FillRectangle(new SolidBrush(BorderColor), new Rectangle(_InputBounds.Location, new Size(1, _InputBounds.Height)));
    }

    System.Timers.Timer blinkTimer;
    protected override void OnGotFocus(EventArgs e)
    {
        if (!DesignMode)
        {
            blinkTimer = new System.Timers.Timer(CursorInterval);
            blinkTimer.Elapsed += TimerElapsed;
            blinkTimer.Start();
            Console.WriteLine("OnGotFocus - I was here.");
        }
        blink = true;
        Invalidate();
        base.OnGotFocus(e);
    }

    private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        blink = !blink;
        Console.WriteLine("TimerElapsed - I was here.");
        Invalidate();
    }

    protected override void OnLostFocus(EventArgs e)
    {
        if(!DesignMode)
        {
            blink = false;
            blinkTimer.Stop();
            blinkTimer.Elapsed -= TimerElapsed;
            Console.WriteLine("OnLostFocus - I was here.");
        }
        Invalidate();
        base.OnLostFocus(e);
    }

    protected override void OnClick(EventArgs e)
    {
        base.OnClick(e);
        Focus();
    }