2016-07-26 24 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(); 
    }