2011-11-29 9 views
1

tldr - Textbox의 하위 클래스를 만들었습니다. 텍스트에 포커스가있을 때 텍스트가 흐려집니다. 그것을 처리하는 적절한 방법은 무엇입니까?VB.Net의 사용자 지정 텍스트 상자

내 회사의 VB.Net 응용 프로그램의 경우 텍스트 상자가 Google의 텍스트 상자처럼 작동하도록 요청되었습니다. 즉, 텍스트 상자는 포커스가있을 때 주위에 파란색 테두리가 있어야하며 테두리가 회색이면 회색 테두리가 있어야합니다. 하지 마라. 필자는 이미 텍스트 상자의 BorderStyle을 'None'으로 설정 한 다음 폼의 Paint 이벤트 내에서 적절한 사각형을 그려서이 작업을 수행 할 수 있습니다. 그러나, 내가 사용하는 각각의 모든 텍스트 상자에 대해이 작업을 수행해야합니다. 그리고 우리의 응용 프로그램은 꽤 많이 있습니다. 말할 것도없이, 이것은 고통이며 차라리 내가 부를 수있는 코드가 하나 있습니다.

그래서 두 가지 옵션이 있다고 생각했습니다. 위의 메서드를 사용하는 단일 텍스트 상자가 포함 된 사용자 정의 컨트롤을 만들거나 TextBox 클래스에서 상속 받고 내 표준 클래스를 작성할 수 있습니다. 나는 후자의 접근 방식을 사용하기로했고, OnPaint 메서드를 재정 의하여 원하는 동작을 얻었습니다. 하지만 지금은 새로운 함정을 만나고 있습니다.

중요한 문제는 텍스트 상자에 포커스가있을 때 텍스트 상자 내의 텍스트가 제대로 렌더링되지 않는다는 것입니다. 텍스트는 다른 글꼴을 사용하고 굵게 표시되며 강조 표시가 어색해 보입니다. 텍스트 상자에 포커스가 없으면 텍스트가 올바르게 보입니다. 다르게 강조 표시된 텍스트의 그리기를 처리해야한다고 생각하지만 필요한 작업을 확신 할 수 없습니다. OnPaint 메서드에서 처리합니까? 아니면 다른 곳에서 잡아야합니까? 이 접근 방식을 포기하고 사용자를 제어해야합니까?

보너스 질문 : 사용자 지정 텍스트 상자를 만드는 경험이있는 사람이라면 알아 두어야 할 팁이나 잡기가 있습니까? 이것은 처음으로 사용자 정의 컨트롤을 만드는 것이므로 무엇을 모두 기대해야하는지 정말로 알지 못합니다.

편집 : 나는 UserPaint 플래그를 true로 설정 했으므로 OnPaint를 재정의 할 수 있음을 잊어 버렸습니다. 나는 이것이 분명했음을 짐작하지만 나는 철저히하고 싶다.

edit2 : 다음은 클래스 전체입니다.

Imports System.Drawing 

Public Class MyCustomTextBox 
    Inherits TextBox 

    Public Sub New() 
     MyBase.New() 
     Me.BorderStyle = BorderStyle.None 
     SetStyle(ControlStyles.UserPaint, True) 
    End Sub 

    Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs) 
     'I want these textboxes to highlight all text by default 
     Me.SelectAll() 
     MyBase.OnGotFocus(e) 
    End Sub 

    Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs) 
     Me.SelectionLength = 0 
     MyBase.OnLostFocus(e) 
    End Sub 

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs) 
     Dim p As Pen = Nothing 

     'MyBase.OnPaint(e) 

     e.Graphics.FillRectangle(Brushes.White, Me.ClientRectangle) 

     If Me.Focused Then 
     p = New Pen(Brushes.CornflowerBlue) 
     Else 
     p = New Pen(Brushes.Gainsboro) 
     End If 

     e.Graphics.DrawRectangle(p, 0, 0, Me.ClientSize.Width - 1, Me.ClientSize.Height - 1) 
     e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), Me.ClientRectangle) 
    End Sub 

End Class 
+0

OnPaint가 유일한 변경이라고 가정하면 해당 코드를 게시 할 수 있습니까? – Timiz0r

+0

TextBox는 근본적으로 UserPaint 스타일을 켜는 것을 지원하지 않습니다. –

답변

2

한스가 언급했듯이 TextBox는 텍스트를 그릴 때 OnPaint 메서드를 사용하지 않습니다.

WM_NCPAINT 메시지에서 컨트롤의 3D 테두리 위에 페인트하는 방법 중 하나입니다. 나는 그것이 완전히 무료로 깜박의 주장하지 않습니다

Imports System.Runtime.InteropServices 

Public Class TextBoxWithBorder 
    Inherits TextBox 

    Public Const WM_NCPAINT As Integer = &H85 

    <Flags()> _ 
    Private Enum RedrawWindowFlags As UInteger 
    Invalidate = &H1 
    InternalPaint = &H2 
    [Erase] = &H4 
    Validate = &H8 
    NoInternalPaint = &H10 
    NoErase = &H20 
    NoChildren = &H40 
    AllChildren = &H80 
    UpdateNow = &H100 
    EraseNow = &H200 
    Frame = &H400 
    NoFrame = &H800 
    End Enum 

    <DllImport("User32.dll")> _ 
    Public Shared Function GetWindowDC(ByVal hWnd As IntPtr) As IntPtr 
    End Function 

    <DllImport("user32.dll")> _ 
    Private Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Boolean 
    End Function 

    <DllImport("user32.dll")> _ 
    Private Shared Function RedrawWindow(hWnd As IntPtr, lprcUpdate As IntPtr, hrgnUpdate As IntPtr, flags As RedrawWindowFlags) As Boolean 
    End Function 

    Public Sub New() 
    MyBase.BorderStyle = Windows.Forms.BorderStyle.Fixed3D 
    End Sub 

    Protected Overrides Sub OnResize(e As System.EventArgs) 
    MyBase.OnResize(e) 
    RedrawWindow(Me.Handle, IntPtr.Zero, IntPtr.Zero, RedrawWindowFlags.Frame Or RedrawWindowFlags.UpdateNow Or RedrawWindowFlags.Invalidate) 
    End Sub 

    Protected Overrides Sub WndProc(ByRef m As Message) 
    MyBase.WndProc(m) 

    If m.Msg = WM_NCPAINT Then 
     Dim hDC As IntPtr = GetWindowDC(m.HWnd) 
     Using g As Graphics = Graphics.FromHdc(hDC) 
     If Me.Focused Then 
      g.DrawRectangle(Pens.CornflowerBlue, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1)) 
     Else 
      g.DrawRectangle(Pens.Gainsboro, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1)) 
     End If 
     g.DrawRectangle(SystemPens.Window, New Rectangle(1, 1, Me.Width - 3, Me.Height - 3)) 
     End Using 
     ReleaseDC(m.HWnd, hDC) 
    End If 

    End Sub 
End Class 

나는 기본적으로 컨트롤이 비 클라이언트 영역의 무효화하게 RedrawWindow 메시지를 보내도록하여 onResize 이벤트를 무시합니다.

필요에 따라 리 팩터링합니다.