自定义绘制 DataGridView 列标题(Excel 2007 风格)
重写 DataGridView 的 cellpaint 事件,使其具有渐变背景。
引言
我一直在使用 CodeProject 作为一个可靠的资源,因为它帮助我提高了开发技能。我觉得现在是我自己发布内容的时候了。最近我下载了新的 Office 2007,并且对新的布局感到非常兴奋。我经常处理数据,并且想改进 DataGridView
的界面,使其列标题类似于 Excel 2007 中的列标题,并具有一些渐变颜色。
概述
我首先尝试了列标题,并且发现我必须关闭 EnableHeadersVisibleStyle
选项才能获得背景颜色。然而,单一的颜色看起来并不像 Office 2007 中的渐变标题。
所以,我更深入地研究,并在重写 DataGridView
的 cell paint 事件中找到了解决方案。列标题的 rowindex 为 -1,这使得将该方法限制为仅在列标题上执行变得容易。在重写 cell paint 事件时,有很多选项可供选择,以便获得自定义绘制的列标题。我选择使用 Graphics
对象和 DrawImage
方法,这允许我使用图像资源作为背景。这为将代码重新用作皮肤项目的一部分提供了可能性,但目前这超出了我的需求。
由于使用了 Graphics
对象,因此有其他选择来自定义绘制 DataGridView
列标题,例如使用 LinearGradientBrush
。要做到这一点,只需将方法的 DrawImage
部分替换为 FillRectangle
方法。
代码
在窗体的打开事件中,我编写了一些代码来填充 DataGridView
。我们在这里跳过这部分。
您可以选择创建一个继承自 DataGridView
的类,并在那里重写 cell paint 事件,或者您可以直接在窗体类中重写该事件(我在示例中选择了第二种选择)。
代码如下:
Private Sub DataGridView1_CellPainting(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) _
Handles DataGridView1.CellPainting
If e.RowIndex = -1 Then
Dim img As Image
img = My.Resources.Header
TekenAchtergrond(e.Graphics, img, e.CellBounds, 1)
Dim format1 As StringFormat
format1 = New StringFormat
format1.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show
Dim ef1 As SizeF = e.Graphics.MeasureString(e.Value, Me.Font, _
New SizeF(CType(e.CellBounds.Width, Single), _
CType(e.CellBounds.Height, Single)), format1)
Dim txts As Size
txts = Drawing.Size.Empty
txts = Drawing.Size.Ceiling(ef1)
e.CellBounds.Inflate(-4, -4)
Dim txtr As Rectangle = e.CellBounds
txtr = HAlignWithin(txts, txtr, ContentAlignment.MiddleCenter)
txtr = VAlignWithin(txts, txtr, ContentAlignment.MiddleCenter)
Dim brush2 As Brush
format1 = New StringFormat
format1.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show
brush2 = New SolidBrush(Color.FromArgb(21, 66, 139))
e.Graphics.DrawString(e.Value, Me.Font, brush2, _
CType(txtr, RectangleF), format1)
brush2.Dispose()
Dim recBorder As New Rectangle(e.CellBounds.X - 1, e.CellBounds.Y, _
e.CellBounds.Width, e.CellBounds.Height - 1)
e.Graphics.DrawRectangle(Pens.LightSlateGray, recBorder)
e.Handled = True
End If
End Sub
在 CellPaint
事件中,我从资源文件中获取标题背景,并将其与 Graphics
对象、绘制矩形和一个索引参数一起传递给 Tekenachtergrond
方法。如果图像文件包含多个模板,该索引参数可以用于皮肤目的。(我来自比利时,tekenachtergrond 是荷兰语,意思是类似于绘制背景)。由于在此示例中我只使用一个模板,所以我将索引设置为 1。
该方法基于我在本网站上找到的一篇文章,它处理控件的皮肤(链接到文章),以及一些额外的对齐方法和变量,如下所示:
Private Sub TekenAchtergrond(ByVal g As Graphics, _
ByVal obj As Image, ByVal r As Rectangle, _
ByVal index As Integer)
If (obj Is Nothing) Then
Return
End If
Dim oWidth As Integer = obj.Width
Dim lr As Rectangle = Rectangle.FromLTRB(0, 0, 0, 0)
Dim r2 As Rectangle
Dim r1 As Rectangle
Dim x As Integer = ((index - 1) _
* oWidth)
Dim y As Integer = 0
Dim x1 As Integer = r.Left
Dim y1 As Integer = r.Top
If ((r.Height > obj.Height) _
AndAlso (r.Width <= oWidth)) Then
r1 = New Rectangle(x, y, oWidth, lr.Top)
r2 = New Rectangle(x1, y1, r.Width, lr.Top)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
r1 = New Rectangle(x, (y + lr.Top), oWidth, (obj.Height _
- (lr.Top - lr.Bottom)))
r2 = New Rectangle(x1, (y1 + lr.Top), r.Width, (r.Height _
- (lr.Top - lr.Bottom)))
If ((lr.Top + lr.Bottom) _
= 0) Then
r1.Height = (r1.Height - 1)
End If
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
r1 = New Rectangle(x, (y _
+ (obj.Height - lr.Bottom)), oWidth, lr.Bottom)
r2 = New Rectangle(x1, (y1 _
+ (r.Height - lr.Bottom)), r.Width, lr.Bottom)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
ElseIf ((r.Height <= obj.Height) _
AndAlso (r.Width > oWidth)) Then
r1 = New Rectangle(x, y, lr.Left, obj.Height)
r2 = New Rectangle(x1, y1, lr.Left, r.Height)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
r1 = New Rectangle((x + lr.Left), y, (oWidth _
- (lr.Left - lr.Right)), obj.Height)
r2 = New Rectangle((x1 + lr.Left), y1, (r.Width _
- (lr.Left - lr.Right)), r.Height)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
r1 = New Rectangle((x _
+ (oWidth - lr.Right)), y, lr.Right, obj.Height)
r2 = New Rectangle((x1 _
+ (r.Width - lr.Right)), y1, lr.Right, r.Height)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
ElseIf ((r.Height <= obj.Height) _
AndAlso (r.Width <= oWidth)) Then
r1 = New Rectangle(((index - 1) _
* oWidth), 0, oWidth, (obj.Height - 1))
g.DrawImage(obj, New Rectangle(x1, y1, r.Width, r.Height), _
r1, GraphicsUnit.Pixel)
ElseIf ((r.Height > obj.Height) _
AndAlso (r.Width > oWidth)) Then
'top-left
r1 = New Rectangle(x, y, lr.Left, lr.Top)
r2 = New Rectangle(x1, y1, lr.Left, lr.Top)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
'top-bottom
r1 = New Rectangle(x, (y _
+ (obj.Height - lr.Bottom)), lr.Left, lr.Bottom)
r2 = New Rectangle(x1, (y1 _
+ (r.Height - lr.Bottom)), lr.Left, lr.Bottom)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
'left
r1 = New Rectangle(x, (y + lr.Top), lr.Left, (obj.Height _
- (lr.Top - lr.Bottom)))
r2 = New Rectangle(x1, (y1 + lr.Top), lr.Left, (r.Height _
- (lr.Top - lr.Bottom)))
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
'top
r1 = New Rectangle((x + lr.Left), y, (oWidth _
- (lr.Left - lr.Right)), lr.Top)
r2 = New Rectangle((x1 + lr.Left), y1, (r.Width _
- (lr.Left - lr.Right)), lr.Top)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
'right-top
r1 = New Rectangle((x _
+ (oWidth - lr.Right)), y, lr.Right, lr.Top)
r2 = New Rectangle((x1 _
+ (r.Width - lr.Right)), y1, lr.Right, lr.Top)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
'Right
r1 = New Rectangle((x _
+ (oWidth - lr.Right)), (y + lr.Top), lr.Right, (obj.Height _
- (lr.Top - lr.Bottom)))
r2 = New Rectangle((x1 _
+ (r.Width - lr.Right)), (y1 + lr.Top), lr.Right, (r.Height _
- (lr.Top - lr.Bottom)))
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
'right-bottom
r1 = New Rectangle((x _
+ (oWidth - lr.Right)), (y _
+ (obj.Height - lr.Bottom)), lr.Right, lr.Bottom)
r2 = New Rectangle((x1 _
+ (r.Width - lr.Right)), (y1 _
+ (r.Height - lr.Bottom)), lr.Right, lr.Bottom)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
'bottom
r1 = New Rectangle((x + lr.Left), (y _
+ (obj.Height - lr.Bottom)), (oWidth _
- (lr.Left - lr.Right)), lr.Bottom)
r2 = New Rectangle((x1 + lr.Left), (y1 _
+ (r.Height - lr.Bottom)), (r.Width _
- (lr.Left - lr.Right)), lr.Bottom)
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
'Center
r1 = New Rectangle((x + lr.Left), (y + lr.Top), (oWidth _
- (lr.Left - lr.Right)), (obj.Height _
- (lr.Top - lr.Bottom)))
r2 = New Rectangle((x1 + lr.Left), (y1 + lr.Top), (r.Width _
- (lr.Left - lr.Right)), (r.Height _
- (lr.Top - lr.Bottom)))
g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)
End If
End Sub
您可以在本文顶部的附件屏幕截图中看到结果如何,或者您可以直接下载代码并在Release文件夹中执行 exe 文件。
我希望这段小代码对某些人有用,就像我在本网站上找到的许多优秀的示例代码一样。