GDI Controltechniken

    • VB.NET

    Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von LaMiy.

      GDI Controltechniken

      Ich habe dieses Thema mal in "GDI Controltechniken" geändert, da ich es doch irgendwie sinnvoller halte, mehr solche Techniker zu erklären.
      Die alten Codes befinden sich unten.

      1. Timer im Designer laufen lassen.
      Spoiler anzeigen

      Theorie:
      Wie möchten bei unserem Control gerne eine Visualisierung im Designer laufen lassen. Dazu können wir einen Timer benutzen, den wir im Designer starten.
      Mehr ist es eigentlich nicht. Hier ein simples Beispiel.

      VB.NET-Quellcode

      1. Option Strict On
      2. Public Class Progress
      3. Inherits Control
      4. Private WithEvents timer As New Timer With {.Interval = 10} 'Timer der im Designer läuft
      5. Private _VisualStyle As Style 'Style Private
      6. Public Property Value As Integer = 0 'Die Value
      7. Public Property VisualStyle As Style 'Die Style Property
      8. Get
      9. Return _VisualStyle
      10. End Get
      11. Set(ByVal value As Style)
      12. If value = Style.Normal Then
      13. Else
      14. Me.Value = 0 'Wenn Style = Visuell ist, dann starte den Timer
      15. timer.Start()
      16. End If
      17. End Set
      18. End Property
      19. Enum Style
      20. Normal
      21. Visuell
      22. End Enum
      23. Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
      24. MyBase.OnPaint(e)
      25. e.Graphics.FillRectangle(Brushes.Gainsboro, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1))
      26. e.Graphics.FillRectangle(Brushes.LimeGreen, New Rectangle(0, 0, CInt((Me.Value * Me.Width) / 100), Me.Height))
      27. e.Graphics.DrawRectangle(Pens.Silver, New Rectangle(0, 0, CInt((Me.Value * Me.Width) / 100), Me.Height))
      28. e.Graphics.DrawRectangle(Pens.Silver, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1))
      29. End Sub
      30. Private Sub timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles timer.Tick
      31. If Me.Value <> 100 Then
      32. Me.Value += 1 'Value erhöhen
      33. Else
      34. timer.Stop()
      35. End If
      36. Me.Invalidate() 'Neu zeichnen
      37. End Sub
      38. Sub New()
      39. Me.DoubleBuffered = True
      40. End Sub
      41. End Class


      2. Mouse-Events
      Spoiler anzeigen

      Theorie: Wir wollen bei MouseEvents im Control selber festlegen, was mit dem Aussehen passieren soll. Dafür wollen wir die Events vom geerbten Control benutzen.

      VB.NET-Quellcode

      1. Public Class Panel
      2. Inherits Control
      3. Private _MouseState As MouseState 'Das Attribut
      4. Public Enum MouseState As Byte 'Die Enumeration
      5. None
      6. Hover
      7. Pressed
      8. End Enum
      9. #Region "Mouse-Events"
      10. Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
      11. MyBase.OnMouseEnter(e)
      12. Me._MouseState = MouseState.Hover
      13. Me.Invalidate()
      14. End Sub
      15. Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
      16. MyBase.OnMouseEnter(e)
      17. Me._MouseState = MouseState.None
      18. Me.Invalidate()
      19. End Sub
      20. Protected Overrides Sub OnMouseDown(ByVal mevent As System.Windows.Forms.MouseEventArgs)
      21. MyBase.OnMouseDown(mevent)
      22. Me._MouseState = MouseState.Pressed
      23. Me.Invalidate()
      24. End Sub
      25. Protected Overrides Sub OnMouseUp(ByVal mevent As System.Windows.Forms.MouseEventArgs)
      26. MyBase.OnMouseUp(mevent)
      27. Me._MouseState = MouseState.Hover
      28. Me.Invalidate()
      29. End Sub
      30. #End Region
      31. Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
      32. MyBase.OnPaint(e)
      33. If _MouseState = MouseState.None Then
      34. e.Graphics.FillRectangle(New System.Drawing.Drawing2D.LinearGradientBrush(Me.ClientRectangle, Color.White, Color.White, 10), Me.ClientRectangle)
      35. ElseIf _MouseState = MouseState.Hover Then
      36. e.Graphics.FillRectangle(New System.Drawing.Drawing2D.LinearGradientBrush(Me.ClientRectangle, Color.Gray, Color.Silver, 10), Me.ClientRectangle)
      37. ElseIf _MouseState = MouseState.Pressed Then
      38. e.Graphics.FillRectangle(New System.Drawing.Drawing2D.LinearGradientBrush(Me.ClientRectangle, Color.Blue, Color.DodgerBlue, 10), Me.ClientRectangle)
      39. End If
      40. End Sub
      41. End Class


      3. Farbveränderung (Übergang)
      Spoiler anzeigen

      Theorie: Wir wollen z.B im Click, oder Hover, die Farbe verändern. Wir könnten einfach sagen: "Me.BackColor = Color.X" Das ist aber nicht gerade schön anzusehen.
      Wir wollen also die Farbe gleichmäßig verändern. Dafür bietet uns die Color-Klasse die ARGB-Funktion, mit dessen Hilfe wir kleine Veränderungen realisieren können.

      VB.NET-Quellcode

      1. Option Strict On
      2. Public Class Control_
      3. Inherits Control
      4. Public Property c As Color
      5. Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
      6. MyBase.OnPaint(e)
      7. e.Graphics.FillRectangle(New SolidBrush(c), Me.ClientRectangle)
      8. e.Graphics.DrawRectangle(Pens.DodgerBlue, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1))
      9. End Sub
      10. Sub New()
      11. Me.DoubleBuffered = True
      12. Me.BackColor = Color.White
      13. End Sub
      14. Public WithEvents timer As New Timer With {.Interval = 50}
      15. Private Sub timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles timer.Tick
      16. If c.A < 255 Then
      17. c = Color.FromArgb((c.A + 5), c.R, c.G, c.B)
      18. Me.Invalidate()
      19. Else
      20. timer.Stop()
      21. End If
      22. End Sub
      23. End Class


      4. Transparenz
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Sub New()
      2. MyBase.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
      3. End Sub
      4. Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
      5. MyBase.OnPaint(e)
      6. e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
      7. e.Graphics.FillPie(Brushes.DodgerBlue, New Rectangle(0, 0, Me.Width, Me.Height), 0, 360)
      8. End Sub
      9. Protected Overrides ReadOnly Property CreateParams() As CreateParams
      10. Get
      11. Dim cp As CreateParams = MyBase.CreateParams
      12. cp.ExStyle = cp.ExStyle Or &H20
      13. 'WS_EX_TRANSPARENT
      14. Return cp
      15. End Get
      16. End Property
      17. Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
      18. MyBase.OnPaintBackground(pevent)
      19. End Sub
      Dateien
      • Farbeffekt.dll

        (17,41 kB, 199 mal heruntergeladen, zuletzt: )

      Dieser Beitrag wurde bereits 31 mal editiert, zuletzt von „LaMiy“ ()

      Dein Button ist von Button abgeleitet, Deine ListBox von Control.
      Hast Du das Listen der Daten neu erfunden oder ist mir da was entgangen?
      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!

      LaMiy schrieb:

      Ist das "falsch" ?
      Nein, nur eine Frage, weil doch die ListBox eine Reihe von Funktionalität liefert.
      Du hast als Member eine List(Of String), da kannst Du nicht mal dem @ErfinderDesRades: seine FileInfo von DirectoryInfo reintun.
      Also: Überleg mal, ob Du von ListBox erbst oder eine List(Of Object) reintust.
      Ansonsten Dir ein frohes Fest. :thumbsup:
      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!
      Ähm - Jedes Control (in winForms) ist mit GDI.
      Was du mit "GDI" meinst, bezeichnet man korrekterweise mit "OwnerDrawing".

      Classic Listbox hat übrigens zusätzlich zum PaintEvent einen weiteren OwnerDrawing-Mechanismus: das DawItem-Event - sehr praktisch.

      Diese Listbox hier ist auch ziemlich unausgegoren: Es gibt zB ein ValueChanged-Event, aber keine Value-Property.
      Oder die anzahl-Property kann von aussen gesetzt werden.

      Es ist auch nix vorgesehen zum Löschen von Item, ja nichtmal abrufen kann man sie.
      Button:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Fertiger Code:
      2. Option Strict On
      3. Imports System.Drawing
      4. Imports System.Drawing.Drawing2D
      5. Imports System.Windows.Forms
      6. Imports System.ComponentModel
      7. Public Class Button
      8. Inherits System.Windows.Forms.Button
      9. Public Enum MouseState As Byte
      10. None
      11. Hover
      12. Pressed
      13. End Enum
      14. Private _MouseState As MouseState
      15. <Category("Style")> _
      16. Public Property colorNoneOne As Color = Color.DimGray
      17. <Category("Style")> _
      18. Public Property colorNoneTwo As Color = Color.DarkGray
      19. <Category("Style")> _
      20. Public Property colorHoverOne As Color = Color.Coral
      21. <Category("Style")> _
      22. Public Property colorHoverTwo As Color = Color.Gainsboro
      23. <Category("Style")> _
      24. Public Property colorPressedOne As Color = Color.White
      25. <Category("Style")> _
      26. Public Property colorPressedTwo As Color = Color.Gray
      27. <Category("Style")> _
      28. Public Property style As System.Drawing.Drawing2D.LinearGradientMode
      29. <Category("Style")> _
      30. Public Property imageBackground As Icon
      31. Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
      32. MyBase.OnPaint(e)
      33. ' install(e)
      34. Dim rect As New Rectangle(0, 0, Me.Width - 1, Me.Height - 1)
      35. Dim recta As New Rectangle(0, 0, Me.Width, Me.Height)
      36. Dim btnSize As Drawing.SizeF = e.Graphics.MeasureString(Me.Text, Me.Font, Me.Width)
      37. If _MouseState = MouseState.None Then
      38. e.Graphics.FillRectangle(New System.Drawing.Drawing2D.LinearGradientBrush(rect, colorNoneOne, colorNoneTwo, style), rect)
      39. ElseIf _MouseState = MouseState.Hover Then
      40. e.Graphics.FillRectangle(New System.Drawing.Drawing2D.LinearGradientBrush(rect, colorHoverOne, colorHoverTwo, style), rect)
      41. ElseIf _MouseState = MouseState.Pressed Then
      42. e.Graphics.FillRectangle(New System.Drawing.Drawing2D.LinearGradientBrush(rect, colorPressedOne, colorPressedTwo, style), rect)
      43. End If
      44. e.Graphics.DrawRectangle(Pens.Black, rect)
      45. e.Graphics.DrawRectangle(Pens.Black, recta)
      46. e.Graphics.DrawString(Me.Text, Me.Font, New Drawing.SolidBrush(Me.ForeColor), New Drawing.Point(CInt(Me.Width / 2) - CInt(btnSize.Width / 2), CInt(Me.Height / 2) - CInt(btnSize.Height / 2)))
      47. If imageBackground Is Nothing Then
      48. Else
      49. e.Graphics.DrawImage(imageBackground.ToBitmap, 0, 0)
      50. End If
      51. End Sub
      52. Protected Sub install(ByVal e As System.Windows.Forms.PaintEventArgs)
      53. With e.Graphics
      54. .SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
      55. .TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
      56. .PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
      57. .InterpolationMode = Drawing2D.InterpolationMode.HighQualityBilinear
      58. .CompositingQuality = Drawing2D.CompositingQuality.HighQuality
      59. End With
      60. Me.Invalidate()
      61. End Sub
      62. Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
      63. MyBase.OnMouseEnter(e)
      64. Me._MouseState = MouseState.Hover
      65. Me.Invalidate()
      66. End Sub
      67. Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
      68. MyBase.OnMouseEnter(e)
      69. Me._MouseState = MouseState.None
      70. Me.Invalidate()
      71. End Sub
      72. Protected Overrides Sub OnMouseDown(ByVal mevent As System.Windows.Forms.MouseEventArgs)
      73. MyBase.OnMouseDown(mevent)
      74. Me._MouseState = MouseState.Pressed
      75. Me.Invalidate()
      76. End Sub
      77. Protected Overrides Sub OnMouseUp(ByVal mevent As System.Windows.Forms.MouseEventArgs)
      78. MyBase.OnMouseUp(mevent)
      79. Me._MouseState = MouseState.Hover
      80. Me.Invalidate()
      81. End Sub
      82. End Class

      ListBox:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Class ListBoxMy
      2. Inherits System.Windows.Forms.Control
      3. Private Property item As New List(Of String) 'Soll die Liste der Items sein
      4. Public Property selectionColor As Color = Color.DodgerBlue 'Die selectionColor
      5. Public Property anzahl As Integer = 0 'Anzahl aller Elemente
      6. Private int As Integer = -1 'der Index
      7. Public Property Index() As Integer 'für bessere Behandlung:
      8. Get
      9. Return int
      10. End Get
      11. Set(ByVal value As Integer)
      12. If int <> value Then
      13. Me.Invalidate()
      14. End If
      15. int = value
      16. End Set
      17. End Property
      18. Public Event valueChanged() 'Ein Event was wir brauchen
      19. Dim yPosition As Integer = 0 'Die yZeichenposition
      20. Dim ft As New Font("Arial", 10) 'Font
      21. Dim rectl As New List(Of Rectangle) 'Liste von Rechtecken zu Überprüfung welches angeklickt wurde
      22. Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
      23. MyBase.OnPaint(e)
      24. Dim br As New SolidBrush(selectionColor) 'neue Farbe
      25. e.Graphics.FillRectangle(Brushes.White, 0, 0, Me.Width, Me.Height) 'Hintergrund
      26. If index <> -1 Then
      27. e.Graphics.FillRectangle(br, 0, ft.Height * (Index), Me.Width, ft.Height) 'Wenn der Index nicht nichts ist
      28. RaiseEvent valueChanged() 'dann eine Rechteck zeichnen und das Event auslösen
      29. End If
      30. e.Graphics.DrawRectangle(Pens.Black, 0, 0, Me.Width - 1, Me.Height - 1) 'Rahmen
      31. For i As Integer = 0 To item.Count - 1 'Für jedes Item
      32. e.Graphics.DrawString(item(i), ft, Brushes.Black, 0, yPosition) 'String zeichnen
      33. yPosition += ft.Height 'Position erhöhen
      34. Next
      35. yPosition = 0 'wieder 0 setzten
      36. End Sub
      37. Public Sub addItem(ByVal itema As String)
      38. rectl.Add(New Rectangle(0, (ft.Height * anzahl), Me.Width, ft.Height))
      39. item.Add(itema)
      40. anzahl += 1
      41. Me.Invalidate()
      42. End Sub
      43. Public Sub New()
      44. Me.DoubleBuffered = True
      45. End Sub
      46. Protected Overrides Sub OnMouseDown(ByVal a As System.Windows.Forms.MouseEventArgs)
      47. MyBase.OnMouseDown(a)
      48. For i As Integer = 0 To rectl.Count - 1
      49. Select Case a.Location.Y
      50. Case Is > rectl(i).Location.Y
      51. If a.Location.Y < rectl(i).Location.Y + rectl(i).Height Then Index = i
      52. Me.Invalidate()
      53. End Select
      54. Next
      55. End Sub
      56. End Class

      Waiter:
      Im Waiter sind nun neue Methoden und Funktionen eingebaut, .dll gibt es oben als Anhang.
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Class Waiter
      2. Inherits System.Windows.Forms.Control
      3. Private WithEvents tmr As New Timer With {.Interval = 50} 'Timer zur Anzeige des Fortschritts
      4. Private state As Boolean = False '_x > 360
      5. Property xColor As Color = Color.White 'Hintergrund
      6. Property clearColor As Color = Color.White 'Farbe des zweiten Kreises
      7. Dim sz As SizeF
      8. Public Event xChanged(ByVal sender As Object, ByVal e As EventArgs)
      9. Public Event yChanged(ByVal sender As Object, ByVal e As EventArgs)
      10. Public _x As Integer = 0
      11. Public _y As Integer = 0
      12. Public Property xValue() As Integer
      13. Get
      14. Return _x
      15. End Get
      16. Set(ByVal value As Integer)
      17. If _x <> value Then
      18. RaiseEvent xChanged(Me, EventArgs.Empty)
      19. End If
      20. _x = value
      21. End Set
      22. End Property
      23. Public Property yValue() As Integer
      24. Get
      25. Return _y
      26. End Get
      27. Set(ByVal value As Integer)
      28. If _y <> value Then
      29. RaiseEvent yChanged(Me, EventArgs.Empty)
      30. End If
      31. _y = value
      32. End Set
      33. End Property
      34. Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
      35. MyBase.OnPaint(e)
      36. Dim br As New SolidBrush(xColor) 'Hintergrund
      37. Dim _br As New SolidBrush(clearColor) 'Farbe des zweiten Kreises
      38. sz = e.Graphics.MeasureString(Me.Text, Me.Font) 'Textverarbeitung
      39. With e.Graphics
      40. .SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
      41. .TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
      42. .PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
      43. .InterpolationMode = Drawing2D.InterpolationMode.HighQualityBilinear
      44. .CompositingQuality = Drawing2D.CompositingQuality.HighQuality
      45. End With
      46. Me.DoubleBuffered = True
      47. e.Graphics.FillPie(Brushes.Silver, 0, 0, Me.Width, Me.Height, 0, _x) ' 1. Kreis
      48. e.Graphics.FillPie(br, 3, 3, Me.Width - 6, Me.Height - 6, 0, 360) 'Zweiter Kreis (überdeckt den 1.)
      49. If state = True Then e.Graphics.FillPie(_br, 0, 0, Me.Width, Me.Height, 0, _y) '3er Kreis, der alles überdeckt
      50. e.Graphics.DrawString(Me.Text, Me.Font, Brushes.Black, _
      51. (Me.Width - sz.Width) / 2, (Me.Height - sz.Height) / 2) 'Text in die Mitte schreiben
      52. End Sub
      53. Private Sub tmr_Tick() Handles tmr.Tick
      54. Select Case state
      55. Case False
      56. If _x < 360 Then
      57. _x += 10
      58. Me.Invalidate()
      59. Else
      60. _y = 0
      61. state = True
      62. End If
      63. Case True
      64. If _y < 360 Then
      65. _y += 10
      66. Me.Invalidate()
      67. Else
      68. _x = 0
      69. state = False
      70. tmr_Tick()
      71. End If
      72. End Select
      73. End Sub
      74. Public Sub startWork(ByVal rotation As Integer)
      75. If rotation <> Nothing Then
      76. tmr.Interval = rotation
      77. tmr.Start()
      78. End If
      79. End Sub
      80. Public Sub stopWork()
      81. tmr.Stop()
      82. _x = 0
      83. _y = 0
      84. Me.Invalidate()
      85. End Sub
      86. Public Function getRotationX() As Integer
      87. Return _x 'Gibt die Gradzahl zurück
      88. End Function
      89. Public Function getRotationY() As Integer
      90. Return _y 's.o.
      91. End Function
      92. Private Sub Waiter_BackColorChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.BackColorChanged
      93. xColor = Me.BackColor 'Hintergrundfarbe zuweisen
      94. clearColor = Me.BackColor
      95. End Sub
      96. Private Sub Waiter_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SizeChanged
      97. Me.Height = Me.Width 'nur Seitenverhältnis 1:1 zulassen
      98. End Sub
      99. Public Sub setX(ByVal x As Integer)
      100. _x = x
      101. Me.Invalidate()
      102. End Sub
      103. Public Sub setY(ByVal y As Integer)
      104. _y = y
      105. Me.Invalidate()
      106. End Sub
      107. Private Sub Waiter_xChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.xChanged
      108. Me.Invalidate()
      109. End Sub
      110. Private Sub Waiter_yChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.yChanged
      111. Me.Invalidate()
      112. End Sub
      113. End Class

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „LaMiy“ ()

      Ein kleiner Hinweis zu Deinem Waiter: :thumbup:
      Wenn ich den Timer (tmr - kein guter Name) im Designer auf Enabled = True schalte, ist er bei Programmstart auf Enabled = False.
      Vielleicht sollte bei jedem Umschalten des Timer-Enabled-Zustandes der Startwinkel (Leer-Kreis) vorgegeben werden.
      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!
      Es ist ziemlich performancefressend, einen Timer so schnell zu takten.
      Und im Designer sollte imo ein Timer immer stille stehen, jedenfalls mein Designer ist auch so schon träge genug.

      Selbes Problem mit dem Waiter: Wenn während der waited wirklich Massen-Verarbeitungen stattzufinden haben, dann erfolgen diese vmtl. wesentlich langsamer, weil der Waiter mit seinen ständingen Neu-Zeichnungen enorm Cpu-Power abzieht.
      @ErfinderDesRades
      Er läuft ja auch nicht durch, sondern wie bei der Original ProgressBar nur kurz.
      Apropos Original: Wie macht Microsoft das denn mit ihrer ProgressBar ?
      Enorm CPU ? Ich habe nicht sonderlich viel Ahnung von der Hardware, aber ich kann mir nicht vorstellen, dass das für einen PC im Jahr 2013 nicht auch nur ein winziges Problem darstellt.
      Die Listbox tut was sie soll, jedoch funktioniert die Verwaltung von Spalten die über den Controlrand gehen nicht (wenn mehr Einträge vorhanden sind als angezeigt werden können). Um dies zu optimieren müsste man doch noch eine Vertikale Scrollbar reinbauen oder?

      8-) faxe1008 8-)