Нарисуйте недействительный прямоугольник, используя WM_PAINT - PullRequest
1 голос
/ 23 сентября 2011

Чтобы нарисовать текст поверх ComboBox (или чего-либо еще), я перезаписываю WndProc() и ловлю сообщение 0x000F - WM_PAINT.

Код похож на следующий:

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

Это работает очень хорошо, но есть проблема: если я перетаскиваю родительское окно на боковой части экрана (чтобы скрыть часть формы окна), видимая часть моегоконтроль бесконечно перерисован.Это заставляет текст перерисовываться над собой!

Полагаю, есть способ нарисовать только недействительную (скрытую) часть элемента управления.Как я могу это сделать?

РЕДАКТИРОВАТЬ

Вот проблема на одном изображении: http://i.stack.imgur.com/WqGfI.png (это ссылка, так как я не могу опубликовать изображение длясейчас.)

ОБНОВЛЕНИЕ

Я пытался использовать API BeginPaint, но структура RECT, включенная в возвращенную структуру PAINTSTRUCT, содержит только нули.

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

Могу ли я что-нибудь сделать с этим?Я не знаю, как поступить, чтобы нарисовать только недействительную область.

Ответы [ 2 ]

0 голосов
/ 03 ноября 2011

Возможно, вы пытаетесь рисовать, когда не было актуального обновления. Часть PAINTSTRUCT указывает, действительно ли окно должно быть стерто.

Вот что я использовал в прошлом. GetUpdateRect позволяет вам легко увидеть, действительно ли что-либо было обновлено, а также получить обновленный регион, не вызывая BeginPaint . Помните, что BeginPaint только тогда, когда вы не передаете сообщение вашему базовому классу. (Я использую класс NativeWindow в этом фрагменте.)

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)

Итак, вы должны выйти из процедуры, если hasUpdates имеет значение False.

Что касается графики для рисования, я успешно использовал Graphics.FromHwnd(ctrl.Handle)

0 голосов
/ 24 сентября 2011

Хорошее практическое правило: никогда не используйте Me.CreateGraphics.

Попробуйте изменить код на:

<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
...