最近因做一个项目需要,需要让文本框能够垂直居中。老惯例,百度,虽然这个问题老旧就有人问,但都没有很好答案。网上有个vb6的例程,通过sendmessage发送EM_SETRECTNP消息重新设置文本编辑区域位置来实现垂直居中,但例程有bus。偶重新修改下并用vb。net实现。详细请看代码
Imports System.ComponentModel
''' <summary>
''' 实现垂直居中并可以设置水印文本框
''' </summary>
''' <remarks></remarks>
Public Class textboxEx
Inherits TextBox
''' <summary>
''' 文本框水印
''' </summary>
''' <remarks></remarks>
<Category("自定义属性"), DefaultValue(""), Description("设置或获取文本框水印。")> _
Property EmptyTextTip() As String
Get
Return _EmptyTextTip
End Get
Set(ByVal value As String)
_EmptyTextTip = value
End Set
End Property
Private _EmptyTextTip As String
Private EmptyTextTipColor As Color = Color.DarkGray
''' <summary>
''' 设置是否垂直显示
''' </summary>
''' <remarks></remarks>
<Category("自定义属性"), DefaultValue(True), Description("设置或获取文本框是否垂直居中。")> _
Property VerticalMiddle() As Boolean
Get
Return _VerticalMiddle
End Get
Set(ByVal value As Boolean)
_VerticalMiddle = value
End Set
End Property
Private _VerticalMiddle As Boolean
' Private mHostCell As tbCell = Nothing
#Region " 垂直居中"
Dim rc As RECT
Dim nlines As Integer
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Int32, ByVal wParam As Int32, ByRef lParam As RECT) As Int32
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Int32, ByVal wParam As Int32, ByRef lParam As Int32) As Int32
Private Const EM_GETRECT = &HB2
Private Const EM_SETRECTNP = &HB4
Private Const EM_GETLINECOUNT = &HBA
Private Const WM_PAINT As Integer = &HF
Private Structure RECT
Public Left As Int32
Public Top As Int32
Public Right As Int32
Public Bottom As Int32
End Structure
'计算居中
Private Sub textboxex_Layout(ByVal sender As Object, ByVal e As System.Windows.Forms.LayoutEventArgs) Handles Me.Layout
SetVCenterText()
End Sub
Private Sub textboxex_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.TextChanged
Dim i As Long = SendMessage(Handle, EM_GETLINECOUNT, 0, 0)
If nlines <> i Then
SetVCenterText()
nlines = Lines.Count
End If
End Sub
'设置垂直居中
Private Sub SetVCenterText()
If Not Multiline Then Return
'计算新高度
Dim sz As SizeF
Using g As Graphics = Me.CreateGraphics
sz = g.MeasureString(Text, Font, Me.Size)
If sz.Height = 0 Then
sz = g.MeasureString("H", Font, Me.Size)
End If
End Using
Dim rect As RECT = rc
rect.Top = (Me.ClientSize.Height - sz.Height) / 2 - 2
rect.Bottom = Me.ClientRectangle.Bottom
rect.Left = 1 'Me.ClientRectangle.Left
rect.Right = Me.ClientRectangle.Right - 1
If rect.Top < 1 Then Return
Console.WriteLine(rect.Right)
Call SendMessage(Handle, EM_SETRECTNP, 0&, rect)
Refresh()
End Sub
#End Region
#Region " 绘制水印"
''' <summary>
''' 绘制水印
''' </summary>
''' <remarks></remarks>
Private Sub WmPaint()
Using graphics__1 As Graphics = Graphics.FromHwnd(MyBase.Handle)
If Text.Length = 0 AndAlso Not String.IsNullOrEmpty(_EmptyTextTip) AndAlso Not Focused Then
Dim format As TextFormatFlags = TextFormatFlags.EndEllipsis Or TextFormatFlags.VerticalCenter
If RightToLeft = RightToLeft.Yes Then
format = format Or TextFormatFlags.RightToLeft Or TextFormatFlags.Right
End If
TextRenderer.DrawText(graphics__1, _EmptyTextTip, Font, MyBase.ClientRectangle, EmptyTextTipColor, format)
End If
End Using
End Sub
#End Region
Private Sub textboxex_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Leave
'绘制水印
WmPaint()
End Sub
'获取文本编辑区大小
Private Sub textboxex_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SizeChanged
Call SendMessage(Me.Handle, EM_GETRECT, 0, rc)
End Sub
Public Sub New()
End Sub
End Class