Ideen gesucht, bessere Effekte eines eigenen Buttons

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

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

    Ideen gesucht, bessere Effekte eines eigenen Buttons

    Hallo Ihr Lieben,

    ich hab mal wieder eine Frage zum guten alten GDI, ich habe eine neue Klasse erstellt, diese von Button erben lassen und zeichne natürlich auch etwas drauf ^^

    Ich habe versucht einen "Hover-Effect" und einen "Klick-Effekt einzubauen" hierfür wechsle ich aktuell einfach bei "MouseEnter", "MouseDown", "MouseLeave" und "MouseUP" die Hintergrundfarbe. Das Problem ist, wenn ich mit dem Button z.B. eine MessageBox öffne, bleibt nach dem schließen der MessageBox, die Farbe auf der "KlickFarbe", da der Button anscheinend das MouseLeaveEvent nicht mehr mitkriegt. Kennt jemand zufällif einen Weg um dieses Verhalten zu Umgehen ?


    Hier der Aktuell verwendete Code (Neue Klasse, erbt von Button)

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Drawing
    2. Imports System.Drawing.Drawing2D
    3. Imports System.Drawing.Text
    4. Public Class DKButton
    5. Inherits Windows.Forms.Button
    6. Private MouseState As MouseState = MouseState.None
    7. Public Sub New()
    8. Me.SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)
    9. DoubleBuffered = True
    10. Me.UpdateStyles()
    11. End Sub
    12. Dim _HoverColor As Color = Color.DimGray
    13. Public Property HoverColor As Color
    14. Get
    15. Return _HoverColor
    16. End Get
    17. Set(value As Color)
    18. _HoverColor = value
    19. Invalidate()
    20. End Set
    21. End Property
    22. Dim _ClickColor As Color = Color.OrangeRed
    23. Public Property ClickColor As Color
    24. Get
    25. Return _ClickColor
    26. End Get
    27. Set(value As Color)
    28. _ClickColor = value
    29. Invalidate()
    30. End Set
    31. End Property
    32. Dim _Border As Boolean = True
    33. Property Border As Boolean
    34. Get
    35. Return _Border
    36. End Get
    37. Set(value As Boolean)
    38. _Border = value
    39. Invalidate()
    40. End Set
    41. End Property
    42. Dim _BorderColor As Color = Color.Black
    43. Public Property BorderColor As Color
    44. Get
    45. Return _BorderColor
    46. End Get
    47. Set(value As Color)
    48. _BorderColor = value
    49. Invalidate()
    50. End Set
    51. End Property
    52. Dim _Hatch As Boolean = True
    53. Property Hatch As Boolean
    54. Get
    55. Return _Hatch
    56. End Get
    57. Set(value As Boolean)
    58. _Hatch = value
    59. Invalidate()
    60. End Set
    61. End Property
    62. Dim _HatchColor As Color = Color.Gray
    63. Property HatchColor As Color
    64. Get
    65. Return _HatchColor
    66. End Get
    67. Set(value As Color)
    68. _HatchColor = value
    69. Invalidate()
    70. End Set
    71. End Property
    72. Dim _GlassEffect As Boolean = True
    73. Property GlassEffect As Boolean
    74. Get
    75. Return _GlassEffect
    76. End Get
    77. Set(value As Boolean)
    78. _GlassEffect = value
    79. Invalidate()
    80. End Set
    81. End Property
    82. Dim _GlassEffectColor As Color = Color.White
    83. Property GlassEffectColor As Color
    84. Get
    85. Return _GlassEffectColor
    86. End Get
    87. Set(value As Color)
    88. _GlassEffectColor = value
    89. Invalidate()
    90. End Set
    91. End Property
    92. Private Function GetTextPosition(ByVal TextSize As SizeF) As PointF
    93. Dim DrawToRect As Rectangle = New Rectangle(0, 0, Me.Width, Me.Height)
    94. Return New PointF(((DrawToRect.Width \ 2) - (CInt(TextSize.Width) \ 2)), ((DrawToRect.Height \ 2) - (CInt(TextSize.Height) \ 2)))
    95. End Function
    96. Protected Overrides Sub OnPaint(e As PaintEventArgs)
    97. With e.Graphics
    98. .TextRenderingHint = TextRenderingHint.ClearTypeGridFit
    99. .SmoothingMode = SmoothingMode.AntiAlias
    100. .InterpolationMode = InterpolationMode.HighQualityBicubic
    101. .CompositingQuality = CompositingQuality.HighQuality
    102. .PixelOffsetMode = PixelOffsetMode.HighQuality
    103. Dim tmp_Color As Color = Color.DarkGray
    104. Select Case MouseState
    105. Case Helpers.MouseState.None
    106. tmp_Color = Me.BackColor
    107. Case Helpers.MouseState.Over
    108. tmp_Color = _HoverColor
    109. Case Helpers.MouseState.Pressed
    110. tmp_Color = _ClickColor
    111. End Select
    112. Using BackgroundBrush As New SolidBrush(tmp_Color)
    113. .FillRectangle(BackgroundBrush, New Rectangle(0, 0, Width, Height))
    114. End Using
    115. If _Hatch Then
    116. Using HatchBrush As New HatchBrush(HatchStyle.DarkDownwardDiagonal, Color.FromArgb(75, _HatchColor), Color.Transparent)
    117. .FillRectangle(HatchBrush, New Rectangle(0, 0, Width, Height))
    118. End Using
    119. End If
    120. If _GlassEffect Then
    121. Using GlassEffectBrush As New LinearGradientBrush(New Rectangle(0, 0, Me.Width, Me.Height \ 2), Color.FromArgb(180, _GlassEffectColor), Color.FromArgb(25, _GlassEffectColor), LinearGradientMode.Vertical)
    122. .FillRectangle(GlassEffectBrush, New Rectangle(0, 0, Width, Height \ 2))
    123. End Using
    124. End If
    125. If _Border Then
    126. Using BorderBrush As New SolidBrush(_BorderColor)
    127. Using BorderPen As New Pen(BorderBrush, 2)
    128. .DrawRectangle(BorderPen, New Rectangle(0, 0, Width, Height))
    129. End Using
    130. End Using
    131. End If
    132. Using ButtonTextBrush As New SolidBrush(ForeColor)
    133. .DrawString(Text, Font, ButtonTextBrush, GetTextPosition(.MeasureString(Text, Font)), StringFormat.GenericDefault)
    134. End Using
    135. End With
    136. End Sub
    137. Protected Overrides Sub OnMouseEnter(e As EventArgs)
    138. MyBase.OnMouseEnter(e)
    139. Invalidate()
    140. MouseState = Helpers.MouseState.Over
    141. Invalidate()
    142. End Sub
    143. Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
    144. MyBase.OnMouseDown(e)
    145. Invalidate()
    146. MouseState = Helpers.MouseState.Pressed
    147. Invalidate()
    148. End Sub
    149. Protected Overrides Sub OnMouseLeave(e As EventArgs)
    150. MyBase.OnMouseEnter(e)
    151. Invalidate()
    152. MouseState = Helpers.MouseState.None
    153. Invalidate()
    154. End Sub
    155. Protected Overrides Sub OnMouseUp(e As MouseEventArgs)
    156. Dim R As Rectangle = New Rectangle(0, 0, Width, Height)
    157. If R.Contains(e.Location) Then
    158. MyBase.OnMouseUp(e)
    159. Invalidate()
    160. MouseState = Helpers.MouseState.Over
    161. Invalidate()
    162. Else
    163. MyBase.OnMouseUp(e)
    164. Invalidate()
    165. MouseState = Helpers.MouseState.None
    166. Invalidate()
    167. End If
    168. End Sub
    169. End Class
    170. Public Class Helpers
    171. Public Enum MouseState
    172. None
    173. Over
    174. Pressed
    175. End Enum
    176. End Class

    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Ich kapier's gerade nicht. Der Button ist hellgrau. Ich geh mit der Maus drüber -> dunkelgrau. Wenn ich den Button anklicke, wird er bei mir rot, dann hellgrau, dann taucht die MessageBox auf. Und wenn ich die Box schließe, wird das Ding dunkelgrau, wenn die Maus noch über dem Button ist oder bleibt hellgrau, wenn die Maus nicht drüber ist. Was soll anders sein? Denn so verhält sich der normale Button auch (bei mir).
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hm om, wenn ich mit der maus draufgehe wird er dunkelgrau, dann beim klick rot, nun wird er weiss und die Messagebox geht auf, aber sobald ich diese schließe, ist der Button Dunkelgrau, als wäre der Hover noch gegeben...
    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    Wenn die Maus beim Schließen über dem Button ist, ist das ja auch korrekt. Genauso verhält sich der normale Button auch:
    • Maus drüber: Hover
    • Klick: Klick
    • MessageBox: wie Maus-nicht-über-Button
    • MB zumachen: Farbe abhängig von Mausposition (Hover oder Deselect)
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @asusdk Was mir noch auffällt:
    Buttons klicken ja auch, wenn sie den Fokus habewn und man die Leertaste drückt.
    Ein "normaler" Button zeigt das an, Deiner nicht.
    Da müsstest Du noch ein paar Key-Events überladen.
    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!
    Mir sind zwei Dinge aufgefallen.

    Zum ersten, würde ich noch zwei Public Propertys anlegen, nähmlich HatchStyle und HatchOpacity (Alpha Wert von Color).

    Zum zweiten, liefert Graphics.DrawString() unschöhne Ergebnisse, verwende lieber TextRenderer.DrawText().


    1. Zeile: Graphics.DrawString(..., StringFormat.GenericDefault)
    2. Zeile: Graphics.DrawString(..., StringFormat.GenericTypographic)
    3. Zeile: TextRenderer.DrawTex(...)
    4. Zeile: Label
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Drawing.Text
    2. Public Class Form1
    3. Private TestString As String = "abcdefghijklmnopqrstuvwxyz"
    4. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. Dim label As New Label
    6. With label
    7. .AutoSize = True
    8. .Location = New Point(10, 70)
    9. .Text = TestString
    10. End With
    11. Controls.Add(label)
    12. End Sub
    13. Protected Overrides Sub OnPaint(e As PaintEventArgs)
    14. With e.Graphics
    15. .TextRenderingHint = TextRenderingHint.ClearTypeGridFit
    16. Using ButtonTextBrush As New SolidBrush(ForeColor)
    17. .DrawString(TestString,
    18. Font,
    19. ButtonTextBrush,
    20. New Point(10, 10),
    21. StringFormat.GenericDefault)
    22. .DrawString($"Width: { .MeasureString(TestString, Font).Width.ToString}",
    23. Font,
    24. ButtonTextBrush,
    25. New Point(CInt(.MeasureString(TestString, Font).Width) + 20, 10),
    26. StringFormat.GenericDefault)
    27. End Using
    28. Using ButtonTextBrush As New SolidBrush(ForeColor)
    29. .DrawString(TestString,
    30. Font,
    31. ButtonTextBrush,
    32. New Point(10, 30),
    33. StringFormat.GenericTypographic)
    34. .DrawString($"Width: { .MeasureString(TestString, Font).Width.ToString}",
    35. Font,
    36. ButtonTextBrush,
    37. New Point(CInt(.MeasureString(TestString, Font).Width) + 20, 30),
    38. StringFormat.GenericTypographic)
    39. End Using
    40. TextRenderer.DrawText(e.Graphics,
    41. TestString,
    42. Font,
    43. New Point(10, 50), ForeColor)
    44. TextRenderer.DrawText(e.Graphics,
    45. $"Width: {TextRenderer.MeasureText(TestString, Font).Width.ToString}",
    46. Font, New Point(TextRenderer.MeasureText(TestString, Font).Width + 20, 50),
    47. ForeColor)
    48. End With
    49. End Sub
    50. End Class

    Graphics.MeasureString() und TextRenderer.MeasureText() liefern auch unterschiedliche Ergebnisse.

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

    Hm. mit Textrenderer, passiert goar nix, der Button bleibt leer ?


    VB.NET-Quellcode

    1. Using ButtonTextBrush As New SolidBrush(_TextColor)
    2. TextRenderer.DrawText(e.Graphics, $"Width: {TextRenderer.MeasureText(ButtonText, Font).Width.ToString}", Font, New Point(TextRenderer.MeasureText(ButtonText, Font).Width, 50), ForeColor)
    3. End Using

    If Energy = Low Then
    Drink(aHugeCoffee)
    Else
    Drink(aHugeCoffeeToo)
    End If
    @asusdk Lass mal das Using weg und verwende _TextColor statt ForeColor.
    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!
    Genau.

    Einfach ....

    VB.NET-Quellcode

    1. Using ButtonTextBrush As New SolidBrush(ForeColor)
    2. .DrawString(Text, Font, ButtonTextBrush, GetTextPosition(.MeasureString(Text, Font)), StringFormat.GenericDefault)
    3. End Using

    ... durch ...

    VB.NET-Quellcode

    1. TextRenderer.DrawText(e.Graphics, Text, Font, GetTextPosition(GetTextSize(Text, Font)), ForeColor)

    ... ersetzen.

    Und was ich vergessen habe, zu erwähnen, ist daß TextRenderer.DrawText() Point anstatt PointF erwartet, ergo ...

    VB.NET-Quellcode

    1. Private Function GetTextPosition(ByVal TextSize As SizeF) As PointF
    2. Dim DrawToRect As Rectangle = New Rectangle(0, 0, Me.Width, Me.Height)
    3. Return New PointF(((DrawToRect.Width \ 2) - (CInt(TextSize.Width) \ 2)), ((DrawToRect.Height \ 2) - (CInt(TextSize.Height) \ 2)))
    4. End Function

    ... durch ...

    VB.NET-Quellcode

    1. Private Function GetTextPosition(ByVal _textSize As Size) As Point
    2. Dim DrawToRect As Rectangle = New Rectangle(0, 0, Me.Width, Me.Height)
    3. Return New Point((DrawToRect.Width \ 2) - (_textSize.Width) \ 2,
    4. (DrawToRect.Height \ 2) - (_textSize.Height) \ 2)
    5. End Function

    ... ersetzen.
    Positiver Nebeneffekt ist dabei, daß keine Typenumwandlung nötig ist.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „FormFollowsFunction“ ()