Reputation: 556
In order to draw a text over a ComboBox
(or whatever else), I override WndProc()
and catch 0x000F
message -- which is WM_PAINT
.
Code is like the following:
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If m.Msg = &HF Then
TextRenderer.DrawText(CreateGraphics, "The text over my control.", Font, _
ClientRectangle, ForeColor)
End If
End Sub
It works very well, but there is a problem: if I drag parent window on a side of the screen (in order to hide a part of the window form), the visible part of my control is infinitely redrawn. This makes the text redrawn over itself!
I suppose there is a way to draw only invalidated (hidden) part of the control. How can I do?
EDIT
Here is the problem in one picture: https://i.sstatic.net/WqGfI.png (it's a link since I can't post image for now.)
UPDATE
I tried using BeginPaint API, but the RECT structure included in the returned PAINTSTRUCT structure contains only zeros.
If m.Msg = WM_PAINT Then
Dim ps As PAINTSTRUCT = New PAINTSTRUCT
BeginPaint(Handle, ps)
Console.WriteLine(ps.rcPaint.right)
'painting goes here
EndPaint(Handle, ps)
End If
Can I do something with that? I don't know how to proceed, in order to paint only invalidated area.
Upvotes: 0
Views: 2561
Reputation: 1014
You might be attempting to paint when there has been no actual update. Part of the PAINTSTRUCT indicates whether the window should actually be erased.
Here's what I've used in the past. GetUpdateRect allows you to easily see if anything has actually been updated as well as get the updated region without having to call BeginPaint. Remember, BeginPaint is only when you're not passing the message down to your base class. (I'm subclassing using the NativeWindow class in this snippet.)
Dim hasUpdates As Boolean
Dim updRect As RECT
Dim r As Rectangle
hasUpdates = GetUpdateRect(_parentControl.Handle, updRect, False)
With updRect
r = New Rectangle(.Left, .Top, .Right - .Left, .Bottom - .Top)
End With
' Invalidate the control so that the whole thing will be redrawn since
' our custom painting routine could redraw the entire client area.
If hasUpdates Then _parentControl.Invalidate(r)
' Pass the message along to be handled by the default paint event.
MyBase.DefWndProc(m)
' Now draw extras over the existing control.
If hasUpdates Then Me.PaintExtras(r)
So what you would do is exit the routine if hasUpdates is False.
As far as the graphics to use to draw, I've had success using Graphics.FromHwnd(ctrl.Handle)
Upvotes: 0
Reputation: 81665
A good rule of thumb is, never use Me.CreateGraphics.
Try changing your code to this:
<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
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If m.Msg = &HF Then
Dim dc As IntPtr = GetWindowDC(m.HWnd)
Using g As Graphics = Graphics.FromHdc(dc)
TextRenderer.DrawText(g, "The text over my control.", Font, _
ClientRectangle, ForeColor)
End Using
ReleaseDC(m.HWnd, dc)
End If
End Sub
Upvotes: 1