Kein Re-Paint nach Verdeckung des (eigenen) Controls


sVx

Grünschnabel
Hallo Forum,

such nun schon eine halbe Ewigkeit eine Lösung meines Problems, vermutlich eine ganz triviale Sache, aber ich kann einfach keine Ursache ausmachen; zumal viele Beispiele im Internet genauso aufgebaut sind und bei mir aber das gleiche Problem verursachen.

Ausgangslage: habe ein Control, daß ein Kästchin zeichnet (quasi ProgressBar) und dort hinein einen Text mittels DrawString Schreibt. (Und rechtsbündig noch einen Bruch der auch den Fortschrit angibt.)

Code:
Pulic Class myprogressbar
    Inherits Control

    ' // alle privaten Variablen stehen hier oben

    Public Sub New()
        MyBase.New()
        Me.BackColor = Drawing.SystemColors.Window
        ' // ....... und so weiter, rest der Standardeinstellungen
    End Sub

    ' // passende Eigenschaften (Property-s) der Klasse sind hier auch definiert

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        Dim g As Graphics = e.Graphics
        Dim v As String = Me.Value.ToString & IIf(Me.DrawMaxValue, "/" & Me.MaximumValue, "")
        Dim r As Rectangle = New Rectangle(Me.InnerBorder, Me.InnerBorder, (e.ClipRectangle.Width / Me.MaximumValue) * m_value - (Me.InnerBorder * 2), e.ClipRectangle.Height - (Me.InnerBorder * 2))
        Dim th As Int16 = g.MeasureString(v, Me.Font).Height / 2
        Dim tw As Int16 = g.MeasureString(v, Me.Font).Width
        Dim b As Rectangle = New Rectangle(0, 0, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1)
        ControlPaint.DrawVisualStyleBorder(g, b)
        g.FillRectangle(New SolidBrush(Me.FillColor), r)
        If Me.Text <> "" Then
            g.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), Me.InnerBorder + Me.Padding.Left, e.ClipRectangle.Height / 2 - th)
        End If
        If Me.DrawValue Then
            g.DrawString(v, Me.ValueFont, New SolidBrush(Me.ForeColor), e.ClipRectangle.Width - g.MeasureString(v, Me.ValueFont).Width - Me.InnerBorder - Me.Padding.Right, e.ClipRectangle.Height / 2 - g.MeasureString(v, Me.ValueFont).Height / 2)
        End If
    End Sub

    ' // nur zur Fehlersuche
    Private Sub s_klick(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.SizeChanged, MyBase.Click
        Me.Invalidate()
    End Sub
End Class
Problem: Wenn nun andere Fenster, aber auch schon alleine das Menü des eigenen Fensters, Bereiche meines Controls überdecken und diese Bereiche später wieder sichtbar werden, wird der entsprechende Bereich nicht neu gezeichnet. (Bilder 1 bis 3 zur Verdeutlichung: Bild 1: so wie es sein soll; Bild 2: Fenster verdeckt Controls; Bild 3: Fenster gibt Control wieder frei, jedoch wird das Control nicht neu gezeichnet.)

Zur Fehlersuche hatte ich mir auf das Ereignis "Click" ein "Invalidate()" gelegt, und dabei Festgestellt, daß die Fläche die OnPaint mit PaintEventArgs wohl auch "falsch" sein muß. (s. Bild 4)

Wäre super, wenn mir jemand weiter helfen könnte, damit, wie jedes andere "normale" Control auch, mein Control auch ordentlich gezeichnet wird, wenn nach einer Verdeckung wieder sichtbar wird.

Gruß
sVx
 

Anhänge

Zuletzt bearbeitet:

sVx

Grünschnabel
Ich kanns ja kaum glauben, aber habe nach "nur" vier Stunden den Fehler gefunden, weshalb OnPaint() das Control garnicht oder fehlerhaft an den stellen neu zeichnet an denen es von einem anderen Objekt überdeckt gewesen ist.

So hat es den Anschein, daß es OnPaint() nicht schnell genug e.ClipRectangle erhällt. So habe ich nun eine globale Variable r angelegt in der (nur) jedes mal, wenn sich die größe des Controls ändert, ich e.ClipRectangle lese und in r ablege. In OnPaint() ist dann die Größe des Controls sofort aus r erhältlich und kann sofort zu weiteren Berechnungen in OnPaint() verwendet werden. Seit dieser Änderung blieben jedenfalls zuvor vorhandenen Probleme aus.

Neue OnPaint(), zur Fehlersuche noch mal komplett neu geschrieben:
Code:
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        Dim rect As Rectangle = Nothing
        Dim border As Rectangle = Nothing
        Dim th As Integer = Nothing
        Dim hpos As Integer = Nothing
        Dim v As String = Nothing
        '--- Bereich säubern respektive mit hintergrundfarbe ausmalen
        e.Graphics.Clear(SystemColors.Window)
        '--- Ladebalken
        border = New Rectangle(0, 0, r.Width - 1, r.Height - 1)   ' // -1 here to get border on bottom and right side too!
        rect = New Rectangle(Me.InnerBorder, Me.InnerBorder, (Me.Value - Me.MinimumValue) / Me.MaximumValue * r.Width, Me.Height)
        e.Graphics.FillRectangle(New SolidBrush(SystemColors.Highlight), rect)
        ControlPaint.DrawVisualStyleBorder(e.Graphics, border)
        '--- Beschriftung
        v = Me.Value & IIf(Me.DrawMaxValue, "/" & Me.MaximumValue, "")
        ' XXX: could be unlcean, depending on the implementation of MeasureString() // for VS2005 it is okay
        th = e.Graphics.MeasureString("m", Me.Font).Height
        hpos = r.Height / 2 - th / 2
        If Me.Text <> "" Then
            e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), Me.Padding.Left + Me.InnerBorder, hpos)
        End If
        If Me.DrawValue Then
            e.Graphics.DrawString(v, Me.ValueFont, New SolidBrush(Me.ForeColor), r.Width - e.Graphics.MeasureString(v, Me.ValueFont).Width - Me.Padding.Right - Me.InnerBorder, hpos)
        End If
End Sub
r wird hier berechnet:
Code:
Private Sub s_sizechanged(ByVal sender As Object, ByVal e As EventArgs) Handles Me.SizeChanged
        r = Me.ClientRectangle
        Me.Invalidate()
End Sub
Gruß,
sVx

PS: Kann ich meinen Beitrag jetzt selbst positiv bewerten? :p
 
Zuletzt bearbeitet: