Reputation: 20464
How I could paint a gradient on the titlbebar (just paint to a different color than the visual XP theme color) preserving the windows XP style?
I've tried to find examples but I don't found nothing even just to replace the titlebar gradient for a solid color, I've found a simple code to paint a solid color but it throws an exception at the Dim g As Graphics
saying that the value cannot be null:
<Runtime.InteropServices.DllImport("user32.dll")>
Private Shared Function GetDCEx(
ByVal hWnd As IntPtr,
ByVal hrgnClip As IntPtr,
ByVal DeviceContextValues As DeviceContextValues
) As IntPtr
End Function
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If (m.Msg = 133) Then
Dim DCX_CACHE As Integer = 2
Dim DCX_WINDOW As Integer = 1
Dim g As Graphics = Graphics.FromHdc(GetDCEx(Me.Handle, m.WParam, (DCX_WINDOW Or DCX_CACHE)))
g.DrawLine(Pens.Red, New Point(0, 0), New Point(30, 30)) 'Draw Here
End If
End Sub
Upvotes: 1
Views: 1055
Reputation: 129
Sometime after but here it goes:
a) You must remove the form's theme
SetWindowTheme(Me.Handle, String.Empty, String.Empty)
b) For m.WParam = 1, GetDCEx fails. So, GetWindowDC is what you need. Your override goes like this
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If (m.Msg = 133) Then
If m.WParam = 1 Then
Dim g As Graphics = Graphics.FromHdc(GetWindowDC(Me.Handle))
Using g
g.DrawLine(Pens.Red, New PointF(0, 0), New PointF(30, 30)) 'Draw Here
End Using
Me.Refresh()
Else
Dim DCX_CACHE As Integer = 2
Dim DCX_WINDOW As Integer = 1
Dim g As Graphics = Graphics.FromHdc(GetDCEx(Me.Handle, m.WParam, (DCX_WINDOW Or DCX_CACHE)))
Using g
g.DrawLine(Pens.Red, New PointF(0, 0), New PointF(30, 30)) 'Draw Here
End Using
Me.Invalidate()
Me.Refresh()
End If
End If
End Sub
The other two declares you need are as following
<Runtime.InteropServices.DllImport("user32.dll")>
Private Shared Function GetWindowDC(ByVal hWnd As IntPtr) As IntPtr
End Function
<Runtime.InteropServices.DllImport("uxtheme.dll")>
Private Shared Function SetWindowTheme(ByVal hWnd As IntPtr, ByVal appName As String, ByVal partList As String) As Integer
End Function
The SetThemeWindow I called it in the form_load event and it worked fine. The Using statement was for GC to deal with the graphics (cleaning up) and the Me.Refresh() as for the client area to not got hayhire in resizing the form (or maximizing).
Credits go to Mike (from How to set the client area (ClientRectangle) in a borderless form?) for his code in C#, that is fairly more complete and with a different direction then this is. His coding is directed to NC area sizes, but also painting them. Here it's more just the painting.
Hope it helps!
[EDIT]
I had a first edit, but futher investigation showed that it probably works in particular cases, not being a actual "final solution"!
So goes the recent findings. GetDCEx function actually fails because of the m.WParam doesn't provide needed information, and getting GetDCEx function to work, you don't need the "m.WParam = 1" IF test. Just use the following:
Using g As Graphics = Graphics.FromHdc(GetDCEx(Me.Handle, IntPtr.Zero, (DeviceContextValues.Window Or DeviceContextValues.Cache)))
g.ExcludeClip(New Rectangle((Me.Width - Me.ClientSize.Width) / 2, (Me.Height - Me.ClientSize.Height) - ((Me.Width - Me.ClientSize.Width) / 2), Me.ClientRectangle.Width, Me.ClientRectangle.Height))
g.FillRectangle(Brushes.DarkRed, New Rectangle(0, 0, Me.Width, Me.Height))
g.DrawRectangle(Pens.Blue, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1))
g.DrawString(Me.Text, New Font("Tahoma", 10), Brushes.LightCyan, New PointF(Me.Width / 2 - Len(Me.Text) / 2, 4))
End Using
instead of the IF block you have, and pass the second parameter of GetDCEx as Intptr.Zero. You never get a null return value. This also draws a border (kinda like some Office or MS software) and the forms text (or caption) titlebar horizontally centered. There is an add to the painting that is excluding the client area. This way, nothing goes wrong with this area (client one). Hope it helps.
Upvotes: 1
Reputation: 1017
There are a number of things you might do here to avoid using API calls within a dot net application.
Upvotes: 1
Reputation: 82
I really can't make much sense of the above code, considering I've never done what you're trying to do. As long as you don't mind not being able to change the gradient, you could make a Visual Studio theme and select it as your theme for each form in your code. I've never done that either, so I'm not sure how hard it would be either.
Upvotes: 0