Listbox .DrawRectangle zeichnet nicht über die Items

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von Sekki.

    Listbox .DrawRectangle zeichnet nicht über die Items

    Ich beginne den Thread mit dem Code:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ​Class MyListbox: Inherits Control
    2. #Region " Variables"
    3. Private WithEvents ListBx As New ListBox
    4. Private _items As String() = {""}
    5. #End Region
    6. #Region " Poperties"
    7. <Category("Options")>
    8. Public Property items As String()
    9. Get
    10. Return _items
    11. End Get
    12. Set(value As String())
    13. _items = value
    14. ListBx.Items.Clear()
    15. ListBx.Items.AddRange(value)
    16. Invalidate()
    17. End Set
    18. End Property
    19. <Category("Colors")>
    20. Public Property SelectedColor As Color
    21. Get
    22. Return _SelectedColor
    23. End Get
    24. Set(value As Color)
    25. _SelectedColor = value
    26. End Set
    27. End Property
    28. Public ReadOnly Property SelectedItem() As String
    29. Get
    30. Return ListBx.SelectedItem
    31. End Get
    32. End Property
    33. Public ReadOnly Property SelectedIndex() As Integer
    34. Get
    35. Return ListBx.SelectedIndex
    36. If ListBx.SelectedIndex < 0 Then Exit Property
    37. End Get
    38. End Property
    39. Public Sub Clear()
    40. ListBx.Items.Clear()
    41. End Sub
    42. Public Sub ClearSelected()
    43. For i As Integer = (ListBx.SelectedItems.Count - 1) To 0 Step -1
    44. ListBx.Items.Remove(ListBx.SelectedItems(i))
    45. Next
    46. End Sub
    47. Sub Drawitem(ByVal sender As Object, ByVal e As DrawItemEventArgs) Handles ListBx.DrawItem
    48. If e.Index < 0 Then Exit Sub
    49. e.DrawBackground()
    50. e.DrawFocusRectangle()
    51. e.Graphics.SmoothingMode = 2
    52. e.Graphics.PixelOffsetMode = 2
    53. e.Graphics.InterpolationMode = 7
    54. e.Graphics.TextRenderingHint = 5
    55. If InStr(e.State.ToString, "Selected,") > 0 Then '-- if selected
    56. '-- Base
    57. e.Graphics.FillRectangle(New SolidBrush(_SelectedColor), New Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height))
    58. '-- Text
    59. e.Graphics.DrawString(" " & ListBx.Items(e.Index).ToString(), New Font("Segoe UI", 8), Brushes.White, e.Bounds.X, e.Bounds.Y + 2)
    60. Else
    61. '-- Base
    62. e.Graphics.FillRectangle(New SolidBrush(Color.FromArgb(30, 39, 44)), New Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height))
    63. '-- Text
    64. e.Graphics.DrawString(" " & ListBx.Items(e.Index).ToString(), New Font("Segoe UI", 8), Brushes.White, e.Bounds.X, e.Bounds.Y + 2)
    65. End If
    66. e.Graphics.Dispose()
    67. End Sub
    68. Protected Overrides Sub OnCreateControl()
    69. MyBase.OnCreateControl()
    70. If Not Controls.Contains(ListBx) Then
    71. Controls.Add(ListBx)
    72. End If
    73. End Sub
    74. Sub AddRange(ByVal items As Object())
    75. ListBx.Items.Remove("")
    76. ListBx.Items.AddRange(items)
    77. End Sub
    78. Sub AddItem(ByVal item As Object)
    79. ListBx.Items.Remove("")
    80. ListBx.Items.Add(item)
    81. End Sub
    82. #End Region
    83. #Region " Colors"
    84. Private BaseColor As Color = Color.FromArgb(30, 39, 44)
    85. Private _SelectedColor As Color = _FlatColor
    86. Private _BorderColor As Color = Color.FromArgb(85, 117, 140)
    87. #End Region
    88. Sub New()
    89. SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or
    90. ControlStyles.ResizeRedraw Or ControlStyles.OptimizedDoubleBuffer, True)
    91. DoubleBuffered = True
    92. ListBx.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed
    93. ListBx.ScrollAlwaysVisible = False
    94. ListBx.HorizontalScrollbar = False
    95. ListBx.BorderStyle = BorderStyle.None
    96. ListBx.BackColor = BaseColor
    97. ListBx.ForeColor = Color.White
    98. ListBx.Location = New Point(3, 3)
    99. ListBx.Font = New Font("Segoe UI", 8)
    100. ListBx.ItemHeight = 20
    101. ListBx.Items.Clear()
    102. ListBx.IntegralHeight = False
    103. Size = New Size(131, 101)
    104. BackColor = BaseColor
    105. End Sub
    106. Protected Overrides Sub OnPaint(e As PaintEventArgs)
    107. B = New Bitmap(Width, Height) : G = Graphics.FromImage(B)
    108. Dim Base As New Rectangle(0, 0, Width, Height)
    109. With G
    110. .SmoothingMode = 2
    111. .PixelOffsetMode = 0
    112. .TextRenderingHint = 5
    113. .Clear(BackColor)
    114. '-- Size
    115. ListBx.Size = New Size(Width - 6, Height - 2)
    116. '-- Base
    117. .FillRectangle(New SolidBrush(BaseColor), Base)
    118. ' '-- Border
    119. ' .DrawRectangle(New Pen(_BorderColor), Base)
    120. End With
    121. MyBase.OnPaint(e)
    122. G.Dispose()
    123. e.Graphics.InterpolationMode = 7
    124. e.Graphics.DrawImageUnscaled(B, 1, 1)
    125. B.Dispose()
    126. End Sub
    127. End Class



    Guten Tab Community,

    ich brauche mal wieder eure Hilfe wenn es ums Zeichnen vom Rand eines Controls geht. Ich habe mich nun ca. 2 Stunden damit beschäftigt und finde auch nichts im Internet. Ich habe einen Border für meine Listbox gezeichnet, jedoch akzeptiert die Listbox den Border nur halb. Ich glaube, dass Problem ist, dass der Border nicht über die Items gezeichnet werden kann. Dies hat sich in einem Test erwiesen, indem ich die Höhe und Weite der Border verkleinert habe. So sieht das ganze aktuell aus:



    Die Border geht nicht komplett um das Control. Und hier mein "Beweis", dass es wahrscheinlich die Items sein könnten, die stören:



    Man sieht hier sehr gut, dass die Kanten existieren, sie aber nicht durch das Control durchzeichnen können. Ich vermute, dass liegt daran, dass die Items ÜBER dem Border liegen. Jedoch konnte ich bisher noch nicht herausfinden, wie ich über die Items zeichnen kann. Könnt ihr dies bereits anhand des Codes sehen? Ich habe es damals nach meinem belieben abgeändert, ist ein komplett normaler Listbox Code, denke ich.

    Das hier ist der zuständige Code für den Border:

    VB.NET-Quellcode

    1. '-- Border
    2. .DrawRectangle(New Pen(_BorderColor), Base)


    Ich hoffe, ihr könnt mir helfen! Natürlich werde ich versuchen, mein bestes zu geben um selbst drauf zu kommen. Wäre aber super, wenn ihr mir die Zeit erspart, da ich wirklich überhaupt keinen Anhang habe.
    Wenn ich eine Frage stelle, habe ich sie bereits gegooglet. Ja, es kommt vor, dass ich die Antwort übersehe. Ja, es kommt vor, dass ich sie nicht verstehe. Deshalb bin ich hier. Wenn dies eure Frage war, dann antwortet bitte nicht. Es stiehlt sämtliche Motivation.

    Sekki schrieb:

    e.Graphics.Dispose()
    Du solltest das als Parameter übergebene Graphics Objekt nicht einfach disposen. Was wenn das noch an andere weiter gereicht werden soll? Das unterliegt hier gar nicht deiner Kontrolle.

    Sekki schrieb:

    Dim Base As New Rectangle(0, 0, Width, Height)

    Es müsste für den Rahmen Width -1 und Height -1 sein, denn DrawRectangle Zeichnet rechts vom angegebenen Rectangle:
    Leider funktioniert das nicht. So sieht das aus:


    Und das mit dem Dispose verstehe ich nicht ganz. Ich werde es mir aber für die Zukunft merken, danke.
    Wenn ich eine Frage stelle, habe ich sie bereits gegooglet. Ja, es kommt vor, dass ich die Antwort übersehe. Ja, es kommt vor, dass ich sie nicht verstehe. Deshalb bin ich hier. Wenn dies eure Frage war, dann antwortet bitte nicht. Es stiehlt sämtliche Motivation.

    Bluespide schrieb:

    Was ist wenn du das auf "0, 0" stellst?


    Auch hier zeigt sich kein Effekt. Gar nichts verändert sich, alles wie auch davor. Meines Wissens ist der PixelOffsetMode für sowas zuständig, den habe ich jedoch schon auf 0 gestellt. Wenn du magst, kannst du den Code in eine Class kopieren und das Projekt einmal erstellen/starten, um dann das Control links nutzen zu können. Selbstverständlich nur, falls du die Zeit dazu hast, ich möchte hier keinem zu große Umstände machen. Ich habe bereits an jeder Zahl gerüttelt, kein Effekt. Entweder wird der Effekt der Border gespiegelt(statt oben und links Border, nur rechts und unten) oder es passiert nichts.
    Wenn ich eine Frage stelle, habe ich sie bereits gegooglet. Ja, es kommt vor, dass ich die Antwort übersehe. Ja, es kommt vor, dass ich sie nicht verstehe. Deshalb bin ich hier. Wenn dies eure Frage war, dann antwortet bitte nicht. Es stiehlt sämtliche Motivation.
    Jo, mit meinen beiden Änderungen und ​ListBx.Size = New Size(Width - 6, Height - 4) klappt das jetzt. Ich habe einfach kurz im Sub New() ein ​ListBx.BackColor = Color.Red unten dran gehangen um die Position der Listbox zu sehen. Die ging bis zum unteren Rand und hat deswegen die Linie unten verdeckt.
    Super! Es hat funktioniert!
    Nun habe ich noch ein kleines Problemchen, welches aber nicht all zu schlimm ist, falls man es nicht fixxen kann. Ich würde gerne .PixelOffsetMode = 0 nutzen können, damit der Border etwas dicker ist und man die Farbe schön erkennt(so wie auf den Screenshots). Jedoch habe ich dann wieder das selbe Problem. Aktuell ist der Border viel zu dünn. Ist das irgendwie möglich?
    Wenn ich eine Frage stelle, habe ich sie bereits gegooglet. Ja, es kommt vor, dass ich die Antwort übersehe. Ja, es kommt vor, dass ich sie nicht verstehe. Deshalb bin ich hier. Wenn dies eure Frage war, dann antwortet bitte nicht. Es stiehlt sämtliche Motivation.

    Bluespide schrieb:

    New Pen(_BorderColor, 3)




    Super! Es hat perfekt geklappt, dass war die Lösung! Ich bedanke mich sehr bei dir, ging super schnell!

    Wenn ich eine Frage stelle, habe ich sie bereits gegooglet. Ja, es kommt vor, dass ich die Antwort übersehe. Ja, es kommt vor, dass ich sie nicht verstehe. Deshalb bin ich hier. Wenn dies eure Frage war, dann antwortet bitte nicht. Es stiehlt sämtliche Motivation.