2016-07-26 62 views
0

不知何故,我设法让自己重新找到一个地方,Google或我的问题的措辞都不能解决问题。将定时器添加到自定义控件以创建闪烁光标

因此,要这样说,我要创建一个TextBox从零开始,从System.Windows.Forms.Control派生。到目前为止,我已经能够绘制Text变量,并且还添加了编辑功能(正常的TextBox通常会这样做)。

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

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

我可以绘制一条静态线,该线从左至右移动,具体取决于CursorPosition拍摄的位置。向控件添加了一个计时器(因此if(blinker))到System.Timers.Timer并且还尝试了System.Windows.Forms.Timer,但是通过不允许我在将控件添加到表单时设置我的任何属性并且仍然无法启动绘图事件。我确实在Tick事件中放置了Invalidate(_Cursor),以确保只有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

所以你的问题是只有在VS设计师?您可以添加一个条件来启动计时器,如下所示:'if(!DesignMode)yourtimer.Start();' – TaW

+0

只有当控件第一次获得焦点时才启动计时器,然后在焦点丢失时停止。只是添加计时器到课堂的事实阻止我使用VS Desinger,我会添加我的设计器的截图到原始文章并添加。 – Hurly

+0

计时器应该是* static *,以便它可以闪烁任何控制。最好创建它(如果为null),并在OnEnter/OnLeave()的重载中取消/订阅其Tick事件。同时确保它不会在设计时使用,也不会“搞砸”任何东西。 –

回答

0

好吧,所以在我决定放弃并停止尝试之后,我删除了我所有的光标,并开始重新绘制它。得到了修复。然后我回去拜访定时器,并且认为当不使用从System.Windows.Forms.Form派生的类时,System.Windows.Forms.Timer会破坏你认为的每一盎司。所以,我转到了System.Timers.Timer(我以前在移动开发中使用过,取得了巨大的成功)。

我现在解决了所有的问题,再次感谢您的帮助!我喜欢这个地方。

下面是代码的变化:

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(); 
    }