Darstellungsproblem von eigener ComboBox / eigenen Controls

  • VB.NET

Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Darstellungsproblem von eigener ComboBox / eigenen Controls

    Guten Morgen Leute,

    ein neuer Tag, ein neues Problem.. :huh:

    Heute geht es darum, dass ich eine ComboBox neu gestalten möchte.
    Das Paint-Event funktioniert soweit, allerdings wird der Text sehr merkwüridg dargestellt (Siehe angefügte Screenshot).
    Des Weiteren wird ab und zu der Hintergrund, bei einem eingegebenen Text, komplett Schwarz wiedergegeben.

    Meine Frage daher, wie bekomme ich es hin, dass mir der Text richtig angezeigt wird und der Hintergrund sich nicht ändert?

    Zur Info - mein bisheriger Code:

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.Drawing
    3. Imports System.Drawing.Drawing2D
    4. Imports System.ComponentModel
    5. Imports System.Windows.Forms
    6. Imports System.ComponentModel.Design
    7. Imports System.Threading
    8. Imports System.Runtime.InteropServices
    9. Imports System.Windows.Forms.Design
    10. ' Hier könnte eine Beschreibung für die Toolbox stehen
    11. Public Class CustomCombo : Inherits ComboBox
    12. Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    13. MyBase.OnPaint(e)
    14. Dim g As Graphics = e.Graphics
    15. Dim cmbRect As Rectangle = New Rectangle(0, 0, MyBase.Width, MyBase.Height)
    16. g.FillRectangle(Brushes.White, cmbRect)
    17. g.DrawRectangle(New Pen(Color.Blue), 0, 0, MyBase.Width - 1, MyBase.Height - 1)
    18. End Sub
    19. Sub New()
    20. MyBase.New
    21. MyBase.Font = New Font("Verdana", 9, FontStyle.Regular)
    22. SetStyle(ControlStyles.UserPaint, True)
    23. SetStyle(ControlStyles.DoubleBuffer, True)
    24. SetStyle(ControlStyles.SupportsTransparentBackColor, True)
    25. End Sub
    26. Private Sub CustomComboBox_Resize(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Resize
    27. Invalidate()
    28. End Sub
    29. End Class


    Btw: Wie schaffe ich es den DropDown-Pfeil zu zeichnen? :D

    Mfg
    Bianco
    Bilder
    • Cmb1.jpg

      2,6 kB, 201×64, 592 mal angesehen
    .wife {right: 100%; margin: 0;}
    @Bianco der schwarze Hintergrund könnte hieran liegen: SetStyle(ControlStyles.SupportsTransparentBackColor, True).
    Und dann solltest Du mal dies hier ansehen:
    docs.microsoft.com/de-de/dotne…tem?view=netframework-4.8
    codeproject.com/Articles/1767/…ng-an-OwnerDrawn-ComboBox
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Danke @RodFromGermany, ich werde mir die Links jetzt mal in Ruhe zu Gemüte führen.

    Zu der Sache mit dem schwarzen Hintergrund hat dein Hinweis nichts gewirkt.
    Dazu sollte ich noch erwähnen, dass es bereits im Designer passiert, was so ausieht (siehe weiterer Screenshot).
    Bilder
    • Cmb2.JPG

      9,64 kB, 299×31, 91 mal angesehen
    .wife {right: 100%; margin: 0;}
    @Bianco Dann poste mal die Form mit dem Design-Code und ggf. .resx, alles in eine ZIP gepackt und als Forum-Anhang:
    Erweiterte Antwort => Dateianhänge => Hochladen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Viel ist dort nicht zu sehen. Nutze zum Test ein leeres Projekt.

    VB.NET-Quellcode

    1. <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
    2. Partial Class Form1
    3. Inherits MyCustomDesign.MyForm
    4. 'Das Formular überschreibt den Löschvorgang, um die Komponentenliste zu bereinigen.
    5. <System.Diagnostics.DebuggerNonUserCode()> _
    6. Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    7. Try
    8. If disposing AndAlso components IsNot Nothing Then
    9. components.Dispose()
    10. End If
    11. Finally
    12. MyBase.Dispose(disposing)
    13. End Try
    14. End Sub
    15. 'Wird vom Windows Form-Designer benötigt.
    16. Private components As System.ComponentModel.IContainer
    17. 'Hinweis: Die folgende Prozedur ist für den Windows Form-Designer erforderlich.
    18. 'Das Bearbeiten ist mit dem Windows Form-Designer möglich.
    19. 'Das Bearbeiten mit dem Code-Editor ist nicht möglich.
    20. <System.Diagnostics.DebuggerStepThrough()> _
    21. Private Sub InitializeComponent()
    22. Me.MyComboBox1 = New MyCustomDesign.MyComboBox()
    23. Me.SuspendLayout()
    24. '
    25. 'MyComboBox1
    26. '
    27. Me.MyComboBox1.FormattingEnabled = True
    28. Me.MyComboBox1.Location = New System.Drawing.Point(116, 140)
    29. Me.MyComboBox1.Name = "MyComboBox1"
    30. Me.MyComboBox1.Size = New System.Drawing.Size(229, 24)
    31. Me.MyComboBox1.TabIndex = 0
    32. Me.MyComboBox1.Themes = MyCustomDesign.MyComboBox.Theme.Default
    33. '
    34. 'Form1
    35. '
    36. Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
    37. Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
    38. Me.ClientSize = New System.Drawing.Size(800, 450)
    39. Me.Controls.Add(Me.MyComboBox1)
    40. Me.Name = "Form1"
    41. Me.Text = "Form1"
    42. Me.ResumeLayout(False)
    43. End Sub
    44. Friend WithEvents MyComboBox1 As MyCustomDesign.MyComboBox
    45. End Class


    Btw. Danke für die Links, habe jetzt auch das "Dreieck" zeichnen können.
    .wife {right: 100%; margin: 0;}
    @Bianco Machst Du zunächst als ersten Befehl in OnPaint():

    VB.NET-Quellcode

    1. g.Clear(Me.BackColor)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany bringt leider gar nichts. Eine weitere merkwürdige Sache ist mir aufgefallen.
    Packe ich noch eine MyComboBox auf die Form, übernimmt diese misteriöser Weise kurzerhand den gezeichneten Text aus der anderen MyComboBox.

    Edit:
    Habe ich das g.Clear(Me.BackColor) zum OnPaint() hinzugefügt, bleibt der schwarze Balken durchgehend angezeigt, obwohl die Me.BackColor = Color.White ist.
    Entferne ich es aus dem OnPaint() kommt er ab und an beim Aktivieren der ComboBox.

    Außerdem ist die Schriftart bzw. größe und der FontStyle nicht das, was angegeben ist.
    Angegeben ist MyBase.Font = New Font("Verdana", 9, FontStyle.Regular), aber ausgegeben wird etwas anderes in FontStyle.Bold..


    .wife {right: 100%; margin: 0;}

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Bianco“ ()

    @Bianco Im oben verlinkten codeproject-Projekt wird das ganze lediglich mit der Prozedur comboBox1_DrawItem() gelöst.
    Sieh Dir das Projekt an und probierma, ob Du damit klar kommst.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub comboBox1_DrawItem(ByVal sender As Object, ByVal e As DrawItemEventArgs) Handles comboBox1.DrawItem
    2. e.Graphics.FillRectangle(Brushes.Bisque, e.Bounds)
    3. e.Graphics.DrawString(Me.arr(e.Index), Me.myFont, Brushes.Blue, New Point(Me.imageArr(e.Index).Width * 2, e.Bounds.Y))
    4. e.Graphics.DrawImage(Me.imageArr(e.Index), New Point(e.Bounds.X, e.Bounds.Y))
    5. If (e.State And DrawItemState.Focus) = 0 Then
    6. e.Graphics.FillRectangle(Brushes.White, e.Bounds)
    7. e.Graphics.DrawString(Me.arr(e.Index), Me.myFont, Brushes.Blue, New Point(Me.imageArr(e.Index).Width * 2, e.Bounds.Y))
    8. e.Graphics.DrawImage(Me.imageArr(e.Index), New Point(e.Bounds.X, e.Bounds.Y))
    9. End If
    10. End Sub
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

    @RodFromGermany Hab es ausprobiert, allerdings ohne Erfolg. Der Hintergrund wird zwar zur Laufzeit bis jetzt nicht schwarz, allerdings ist die Schriftart immer noch sehr merkwürdig.
    Zudem werden bei beiden Möglichkeiten immer wieder andere Dinge die auf der Form oder Designer sind mit in die ComboBox gezeichnet.
    Was ich sehr merkwürdig finde ist das, dass ich bereits x-Controls selber zeichnen lasse und nirgendwo dieses Problem auftritt.
    Einzigallein die ComboBox macht mir das Leben schwer. Und der Code unterscheidet sich nicht viel zu den anderen Controls.
    .wife {right: 100%; margin: 0;}
    @Bianco Mit ausschließlich dem DrawItem (was in Deiner Lösung fehlt) dunktioniert das so, wie es soll.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Ich danke dir erstmal für deine Antworten, aber so richtig verstehe ich es nicht.
    Ich habe jetzt DrawItem() zum Code hinzugefügt und nach meinen "Vorstellungen angepasst".
    Dennoch bekomme ich hin und wieder den schwarzen Background und die Schrift ist immer noch nicht die richtige.
    Zudem zeichnet er mir noch etwas vom String zum DropDown-Icon(Screenshot). Tut mir echt leid, aber ich kann es grad nicht nachvollziehen, warum das so ist.
    Bilder
    • Cmb3.JPG

      9,94 kB, 166×43, 549 mal angesehen
    .wife {right: 100%; margin: 0;}
    @Bianco Hast Du außer DrawItem() noch weitere Prozeduren im Eingriff?
    Wenn ja, nimm die mal weg.
    ====
    Hast Du Dir den verlinkten Code angesehen?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Ja, den habe ich mir angesehen, aber wahrscheinlich nicht korrekt geschrieben.

    Ich kann einfach nochmal die Code-Schnipsel anfügen, die derzeit in meiner Klasse enthalten sind.

    OnPaint()

    VB.NET-Quellcode

    1. Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    2. MyBase.OnPaint(e)
    3. ' DrawString Parameter
    4. Dim y As Integer = CInt(e.Graphics.MeasureString(Text, Font).Height / 2)
    5. Dim x As Integer = CInt(e.Graphics.MeasureString(Text, Font).Width)
    6. Dim cmbRect As Rectangle = New Rectangle(0, 0, Width, Height)
    7. ' DropDown-Icon Parameter
    8. Dim Px As Integer = Width - 6
    9. Dim Py As Integer = CInt(Height / 2 - 3)
    10. ' Points für das DropItem-Icon
    11. Dim P1 As New Point(Px, Py)
    12. Dim P2 As New Point(Px - 12, Py)
    13. Dim P3 As New Point(Px - 6, Py + 6)
    14. Dim PolyP() As Point = {P1, P2, P3}
    15. e.Graphics.FillRectangle(Brushes.White, cmbRect)
    16. e.Graphics.DrawRectangle(New Pen(CT.BorderColor), 0, 0, Width - 1, Height - 1)
    17. e.Graphics.FillPolygon(New SolidBrush(CT.BorderColor), PolyP)
    18. If EnterBox Then
    19. e.Graphics.FillPolygon(New SolidBrush(CT.ControlSelectColor), PolyP)
    20. End If
    21. e.Graphics.DrawString(Text, Font, New SolidBrush(ForeColor), New Point(x, y))
    22. End Sub


    DrawItem()

    VB.NET-Quellcode

    1. Private Sub MyComboBox_DrawItem(ByVal sender As Object, ByVal e As DrawItemEventArgs) Handles Me.DrawItem
    2. MyBase.OnDrawItem(e)
    3. ' DrawString Parameter
    4. Dim y As Integer = CInt(e.Graphics.MeasureString(Text, Font).Height / 2)
    5. Dim x As Integer = CInt(e.Graphics.MeasureString(Text, Font).Width)
    6. Dim cmbRect As Rectangle = New Rectangle(0, 0, Width, Height)
    7. ' DropDown-Icon Parameter
    8. Dim Px As Integer = Width - 6
    9. Dim Py As Integer = CInt(Height / 2 - 3)
    10. ' Points für das DropItem-Icon
    11. Dim P1 As New Point(Px, Py)
    12. Dim P2 As New Point(Px - 12, Py)
    13. Dim P3 As New Point(Px - 6, Py + 6)
    14. Dim PolyP() As Point = {P1, P2, P3}
    15. e.Graphics.FillRectangle(Brushes.White, cmbRect)
    16. e.Graphics.DrawRectangle(New Pen(CT.BorderColor), 0, 0, Width - 1, Height - 1)
    17. e.Graphics.FillPolygon(New SolidBrush(CT.BorderColor), PolyP)
    18. If Me.FocusedThen
    19. e.Graphics.FillPolygon(New SolidBrush(CT.ControlSelectColor), PolyP)
    20. End If
    21. e.Graphics.DrawString(Text, Font, New SolidBrush(ForeColor), New Point(x, y))
    22. End Sub

    *CT.BorderColor o.ä. ist ein Struct mit verschiedenen voreingestellten Farben


    Mein Ziel ist es ja eine eigene DLL zu erstellen, welche ich in meine Projekte einbinden kann, um meine Controls usw. zu verwenden.
    Wie gesagt funktioniert alles, bis auf die doofe ComboBox.
    .wife {right: 100%; margin: 0;}

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bianco“ ()

    @Bianco OnPaint() hat da nix (mehr) zu suchen.
    Und dann so:

    VB.NET-Quellcode

    1. Protected Overrides Sub OnDrawItem(ByVal e As DrawItemEventArgs)
    2. MyBase.OnDrawItem(e)
    3. ' ...
    4. End Sub

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Jetzt zeichnet er aber garnichts mehr.. Muss ich dabei noch etwas berücksichtigen?

    Hab nochmal Screenshots angefügt..

    "Cmb4.JPG" - Designer-Ansicht || "Cmb5.JPG" - Zur Laufzeit

    Hier auch nochmal der Code.

    VB.NET-Quellcode

    1. Protected Overrides Sub OnDrawItem(e As DrawItemEventArgs)
    2. MyBase.OnDrawItem(e)
    3. ' DrawString Parameter
    4. Dim y As Integer = CInt(e.Graphics.MeasureString(Text, Font).Height / 2)
    5. Dim x As Integer = CInt(e.Graphics.MeasureString(Text, Font).Width)
    6. Dim cmbRect As Rectangle = New Rectangle(0, 0, Width, Height)
    7. ' DropDown-Icon Parameter
    8. Dim Px As Integer = Width - 6
    9. Dim Py As Integer = CInt(Height / 2 - 3)
    10. ' Points für das DropDown-Icon
    11. Dim P1 As New Point(Px, Py)
    12. Dim P2 As New Point(Px - 12, Py)
    13. Dim P3 As New Point(Px - 6, Py + 6)
    14. Dim PolyP() As Point = {P1, P2, P3}
    15. e.Graphics.FillRectangle(Brushes.White, cmbRect)
    16. e.Graphics.DrawRectangle(New Pen(CT.BorderColor), 0, 0, Width - 1, Height - 1)
    17. e.Graphics.FillPolygon(New SolidBrush(CT.BorderColor), PolyP)
    18. If Me.Focused Then
    19. e.Graphics.FillPolygon(New SolidBrush(CT.ControlSelectColor), PolyP)
    20. End If
    21. e.Graphics.DrawString(Text, Font, New SolidBrush(ForeColor), New Point(x, y))
    22. End Sub
    Bilder
    • Cmb4.JPG

      10,61 kB, 193×60, 503 mal angesehen
    • Cmb5.JPG

      9,17 kB, 167×40, 508 mal angesehen
    .wife {right: 100%; margin: 0;}
    @Bianco Verstehe das verlinkte Beispielprojekt.
    Das kann ich für Dich leider nicht tun.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany mittlerweile habe ich es verstanden wie es funktioniert, allerdings sind die Elemente in der DropDownList immer noch nicht richtig dargestellt.
    Aus irgendwelchen unbekannten Gründen, wird hier weiterhin die Schriftart, -größe und -style verändert.
    Bilder
    • Cmb6.JPG

      8,31 kB, 247×130, 514 mal angesehen
    .wife {right: 100%; margin: 0;}
    @Bianco Poste mal Deinen relevanten Code, so dass ich das Problem nachstellen kann.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany Sehr gerne. Zum einen habe ich den Code der OnPaint()-Sub, um den Rahmen und das DropDown-Icon zu zeichnen.

    VB.NET-Quellcode

    1. Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    2. MyBase.OnPaint(e)
    3. ' DrawString Parameter
    4. Dim y As Integer = CInt(e.Graphics.MeasureString(Text, Font).Height / 2)
    5. Dim x As Integer = CInt(e.Graphics.MeasureString(Text, Font).Width)
    6. Dim cmbRect As Rectangle = New Rectangle(0, 0, Width, Height)
    7. ' DropDownIcon Parameter
    8. Dim Px As Integer = Width - 6
    9. Dim Py As Integer = CInt(Height / 2 - 3)
    10. ' Points für das Dreieck
    11. Dim P1 As New Point(Px, Py)
    12. Dim P2 As New Point(Px - 12, Py)
    13. Dim P3 As New Point(Px - 6, Py + 6)
    14. Dim PolyP() As Point = {P1, P2, P3}
    15. e.Graphics.FillRectangle(Brushes.White, cmbRect)
    16. e.Graphics.DrawRectangle(New Pen(CT.BorderColor), 0, 0, Width - 1, Height - 1)
    17. e.Graphics.FillPolygon(New SolidBrush(CT.BorderColor), PolyP)
    18. If Me.Focused Then
    19. e.Graphics.FillPolygon(New SolidBrush(CT.ControlSelectColor), PolyP)
    20. End If
    21. e.Graphics.DrawString(Text, Font, New SolidBrush(ForeColor), New Point(2, CInt(Height / 2 - y)))
    22. End Sub


    Und zum anderen habe ich die DrawItem()-Sub, um das gewählte Item, der DropDownListe, in der Box zu zeichnen.

    VB.NET-Quellcode

    1. Protected Overrides Sub OnDrawItem(e As DrawItemEventArgs)
    2. MyBase.OnDrawItem(e)
    3. SetTheme(Themes)
    4. e.Graphics.DrawString(MyBase.Items(e.Index).ToString, Font, New SolidBrush(ForeColor), New Point(e.Bounds.X, CInt(e.Bounds.Y / 2)))
    5. End Sub
    .wife {right: 100%; margin: 0;}
    @Bianco Wie soll ich Dein Problem nachstellen mut zwei losgelösten Prozeduren?
    Poste mal die ganze Klasse. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!