.net - Paint 处理程序中的文本渲染大小错误
问题描述
该类继承 System.Windows.Forms.Label(此控件的最佳功能集)。
控件的大小由基类的 AutoSize 属性设置(必须刚好够用),但 DrawString 画得更宽或更窄,取决于使用的字体。对于大尺寸的字体,高度也可能是错误的。
我推测 Ladel 和 Graphics 使用不同的渲染模式,但无法理解这种差异。
还是代码有问题?
Public Class LabelProgressBar
Inherits Label
Private dProgress As Double = 0.0
Private nBackAlpha As Byte = 64
Private stBarColor0 As Color = Color.Maroon
Private stBarColor1 As Color = Color.ForestGreen
Public Property BackAlpha As Byte
Get
Return nBackAlpha
End Get
Set(value As Byte)
If value <> nBackAlpha Then
nBackAlpha = value
Invalidate()
End If
End Set
End Property
Public Property BarColor0 As Color
Get
Return stBarColor0
End Get
Set(value As Color)
If value <> stBarColor0 Then
stBarColor0 = value
Invalidate()
End If
End Set
End Property
Public Property BarColor1 As Color
Get
Return stBarColor1
End Get
Set(value As Color)
If value <> stBarColor1 Then
stBarColor1 = value
Invalidate()
End If
End Set
End Property
Public Property Progress As Double
Get
Return dProgress
End Get
Set(value As Double)
If value <> dProgress Then
Dim fOld = InnerProgress
dProgress = value
If InnerProgress <> fOld Then Invalidate()
End If
End Set
End Property
Private ReadOnly Property InnerProgress As Single
Get
If dProgress < 0.0 Then Return 0.0
If dProgress > 1.0 Then Return 1.0
Return CSng(Progress)
End Get
End Property
Private Sub LabelProgressBar_PaddingChanged(sender As Object, e As EventArgs) Handles Me.PaddingChanged
Invalidate()
End Sub
Private Sub LabelProgressBar_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
If Width - Padding.Left - Padding.Right > 0 AndAlso Height - Padding.Top - Padding.Bottom > 0 Then
e.Graphics.CompositingQuality = CompositingQuality.HighQuality
e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
e.Graphics.Clear(BackColor)
PaintGradient(e.Graphics, e.ClipRectangle, 1.0, nBackAlpha)
PaintGradient(e.Graphics, e.ClipRectangle, InnerProgress, 255)
Dim stNonPadded = New RectangleF(e.ClipRectangle.Location, e.ClipRectangle.Size)
stNonPadded.X = Padding.Left
stNonPadded.Width -= Padding.Left + Padding.Right
stNonPadded.Y = Padding.Top
stNonPadded.Height -= Padding.Top + Padding.Bottom
Using objBrush = New SolidBrush(ForeColor)
Using objFormat = New StringFormat()
Select Case TextAlign
Case ContentAlignment.TopLeft, ContentAlignment.MiddleLeft, ContentAlignment.BottomLeft
objFormat.Alignment = StringAlignment.Near
Case ContentAlignment.TopCenter, ContentAlignment.MiddleCenter, ContentAlignment.BottomCenter
objFormat.Alignment = StringAlignment.Center
Case Else
objFormat.Alignment = StringAlignment.Far
End Select
objFormat.Trimming = If(AutoEllipsis, StringTrimming.EllipsisWord, StringTrimming.Character)
Select Case TextAlign
Case ContentAlignment.MiddleLeft, ContentAlignment.MiddleCenter, ContentAlignment.MiddleRight
Dim stDrawSize = e.Graphics.MeasureString(Text, Font, stNonPadded.Size, objFormat)
stNonPadded.Y += (stNonPadded.Height - stDrawSize.Height) / 2
Case ContentAlignment.BottomLeft, ContentAlignment.BottomCenter, ContentAlignment.BottomRight
Dim stDrawSize = e.Graphics.MeasureString(Text, Font, stNonPadded.Size, objFormat)
stNonPadded.Y += stNonPadded.Height - stDrawSize.Height
End Select
e.Graphics.DrawString(Text, Font, objBrush, stNonPadded, objFormat)
End Using
End Using
End If
End Sub
Private Sub LabelProgressBar_TextAlignChanged(sender As Object, e As EventArgs) Handles Me.TextAlignChanged
Invalidate()
End Sub
Private Sub PaintGradient(surface As Graphics, bounds As Rectangle, progress As Single, alpha As Byte)
Dim stColor0 = Color.FromArgb(alpha, stBarColor0)
Dim stColor1 = Color.FromArgb(alpha, stBarColor1)
Using objBrush = New LinearGradientBrush(bounds, stColor0, stColor1, LinearGradientMode.Horizontal)
surface.FillRectangle(objBrush, New RectangleF(bounds.Left, bounds.Top, bounds.Width * progress, bounds.Height))
End Using
End Sub
End Class
解决方案
你为什么不让标签为你做拉绳工作?
Protected Overrides Sub OnPaintBackground(e As PaintEventArgs)
MyBase.OnPaintBackground(e)
If Width - Padding.Left - Padding.Right > 0 AndAlso Height - Padding.Top - Padding.Bottom > 0 Then
e.Graphics.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
e.Graphics.Clear(BackColor)
PaintGradient(e.Graphics, e.ClipRectangle, 1.0, nBackAlpha)
PaintGradient(e.Graphics, e.ClipRectangle, InnerProgress, 255)
End If
End Sub
MeasureString/DrawString 比你想象的要复杂一点。当使用带有矩形参数的 DrawString 时,我可以看到最后一个字符被剥离(未渲染)。您可以通过使用此行来避免这种情况
e.Graphics.DrawString(Text, Font, objBrush, stNonPadded.Location, objFormat)
但我不确定这是否是你的问题,因为你的描述不是很清楚。
同样根据 ClipRectangle 对齐也不是一个好主意,因为当窗体移动、隐藏、部分隐藏、移出屏幕等时,它可能是您控件的一半。
推荐阅读
- java - 当我在我的网站中部署 Web 服务时,我的架构位置和地址位置发生了变化
- firefox - Firefox 无法正确显示导航栏图像 其他浏览器没有此问题
- excel - 用于插入列和公式的 VBA 代码
- ubuntu - 可以以 root 身份而不是 ubuntu 用户身份 SSH 到 EC2 ubuntu 服务器
- azure - 无法从 Azure 容器注册表中拉取映像 - 拉取被拒绝
- python - 在 Python 应用程序中调用自定义 C 子例程
- python-2.7 - 我可以在 Mininet 仿真期间动态修改链接特性吗?
- python - python中的多行输入
- javascript - HTML 表单计算 - JS 还是 PHP?(多个变量)
- mongodb - MongoDB - 查找匹配一个字段但不匹配第二个字段的帐户