Tipp-Upload: VB.NET 0384: Gummiband in VB.Net
von AtaRist
Über den Tipp
Dieser Tippvorschlag wird übernommen.
Der Vorschlag ist in den folgenden Kategorien zu finden:
- Grafik
Dem Tippvorschlag wurden folgende Schlüsselwörter zugeordnet:
Gummiband, Rubberband, Auswahlrechteck, ControlPaint, Drawmode, XOR
Der Vorschlag wurde erstellt am: 03.01.2010 07:19.
Die letzte Aktualisierung erfolgte am 15.01.2010 16:38.
Beschreibung
Dieser Tip zeigt wie man unter .Net das bekannte 'Gummiband' (auch 'Rubberband' oder 'Auswahlrechteck' genannt) realisiert.
In VB-Classic war das alles kein Problem da man dort einfach den DrawMode auf XOR stellen konnte und damit
durch nochmaliges Zeichnen an der gleichen Stelle das Rechteck/ die Linie wieder löschen konnte.
Aber wie geht das in .Net da es die Eigenschaft DrawMode nicht mehr gibt?
Microsoft hat zum Glück eine statische Klasse bereit gestellt mit der so etwas
(wie auch einige andere Dinge) leicht zu bewerkstelligen ist: [b]Die Klasse ControlPaint[/b].
Zu beachten ist das diese Klasse mit Screen-Koordinaten arbeitet und somit alle Koordinaten mit Hilfe
der von Control zur Verfügung gestellten Funktion PointToScreen in Screen-Koordinaten umgewandelt werden müssen.
Der Tip enthält eine Klasse die eine Linie bzw. ein Auswahlrechteck zeichnet und nach Abschluß die entsprechenden Punkte
bzw. den ausgewählten Bereich (auf ein Control bezogen) zurück liefert.
Sie demonstriert wie man das 'Gummiband' auf einen bestimmten Bereich begrenzen kann, mit verschiedenen
Maustasten arbeitet sowie unterschiedliche Darstellungsvarianten.
Schwierigkeitsgrad |
Verwendete API-Aufrufe: |
Download: |
' Dieser Source stammt von http://www.activevb.de ' und kann frei verwendet werden. Für eventuelle Schäden ' wird nicht gehaftet. ' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum. ' Ansonsten viel Spaß und Erfolg mit diesem Source! ' ' Beachten Sie, das vom Designer generierter Code hier ausgeblendet wird. ' In den Zip-Dateien ist er jedoch zu finden. ' --------- Anfang Projektgruppe RubberbandDemo.sln --------- ' -------- Anfang Projektdatei RubberbandDemo.vbproj -------- ' ------------------ Anfang Datei Form1.vb ------------------ Public Class Form1 Private ObjectList As New List(Of GraphicObject) ' Speichert alle zu zeichnenden Objekte Private WithEvents _Rubberband As Rubberband Public Sub New() ' Dieser Aufruf ist für den Windows Form-Designer erforderlich. InitializeComponent() ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu. _Rubberband = New Rubberband(PictureBox1) _Rubberband.Style = Rubberband.Styles.Line _Rubberband.ClientRectOnly = True _Rubberband.RestrictionRect = Rectangle.Empty _Rubberband.Mode = Rubberband.Modes.MouseDown End Sub Private Sub rbLine_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles _ rbLine.Click _Rubberband.Style = Rubberband.Styles.Line btnSelCol.Enabled = False End Sub Private Sub rbFrame_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles _ rbFrame.Click _Rubberband.Style = Rubberband.Styles.Frame btnSelCol.Enabled = False End Sub Private Sub rbRect_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles _ rbRect.Click _Rubberband.Style = Rubberband.Styles.Rectangle btnSelCol.Enabled = True End Sub Private Sub rbNone_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles _ rbNone.Click _Rubberband.RestrictionRect = Rectangle.Empty _Rubberband.ClientRectOnly = False End Sub Private Sub rbForm_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles _ rbForm.Click _Rubberband.RestrictionRect = Me.ClientRectangle _Rubberband.ClientRectOnly = False End Sub Private Sub rbPicture_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles _ rbPicture.Click _Rubberband.RestrictionRect = Rectangle.Empty _Rubberband.ClientRectOnly = True End Sub Private Sub btnSelCol_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnSelCol.Click cdBackground.Color = picColor.BackColor cdBackground.AllowFullOpen = True cdBackground.FullOpen = True If cdBackground.ShowDialog() = Windows.Forms.DialogResult.OK Then picColor.BackColor = cdBackground.Color _Rubberband.BackColor = cdBackground.Color End If End Sub Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnStart.Click Dim btns As MouseButtons = Windows.Forms.MouseButtons.None Dim cbtns As MouseButtons = Windows.Forms.MouseButtons.None If chkLeft.Checked Then btns = btns Or Windows.Forms.MouseButtons.Left End If If chkMiddle.Checked Then btns = btns Or Windows.Forms.MouseButtons.Middle End If If chkRight.Checked Then btns = btns Or Windows.Forms.MouseButtons.Right End If If chkCLeft.Checked Then cbtns = cbtns Or Windows.Forms.MouseButtons.Left End If If chkCMiddle.Checked Then cbtns = cbtns Or Windows.Forms.MouseButtons.Middle End If If chkCRight.Checked Then cbtns = cbtns Or Windows.Forms.MouseButtons.Right End If If btns = Windows.Forms.MouseButtons.None Then Exit Sub _Rubberband.Start(btns, cbtns) End Sub Private Sub _Rubberband_Aborted(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles _Rubberband.Aborted MessageBox.Show("Rubberband wurde abgebrochen", "Abbruchmeldung") End Sub Private Sub _Rubberband_Finished(ByVal sender As Object, ByVal e As RubberBandEventArgs) _ Handles _Rubberband.Finished ' GraphicObject erstellen Dim go As New GraphicObject If _Rubberband.Style <> Rubberband.Styles.Line Then go.Shape = GraphicObject.Shapes.Rectangle go.Rectangle = e.Area Else go.Shape = GraphicObject.Shapes.Line go.Point1 = e.StartedAt go.Point2 = e.EndedAt go.Rectangle = e.Area End If ' der liste hinzufügen ObjectList.Add(go) ' Zeichnung ausgeben PictureBox1.Invalidate(e.Area) End Sub Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As _ System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint For Each go As GraphicObject In ObjectList go.Draw(e.Graphics) Next End Sub Private Sub rbMouseDown_Click(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles rbMouseDown.Click _Rubberband.Mode = Rubberband.Modes.MouseDown End Sub Private Sub rbMouseclick_Click(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles rbMouseclick.Click _Rubberband.Mode = Rubberband.Modes.Click End Sub End Class ' ------------------- Ende Datei Form1.vb ------------------- ' -------------- Anfang Datei GraphicObject.vb -------------- ''' <summary> ''' Sehr einfache Klasse die graphische Objekte speichert und zeichnet (zu Demozwecken nur Linen und gefüllte Rechtecke) ''' </summary> Public Class GraphicObject Public Enum Shapes Line = 0 Rectangle = 1 End Enum Private _Point1 As Point Private _Point2 As Point Private _Rectangle As Rectangle Private _Shape As Shapes Public Property Point1() As Point Get Return _Point1 End Get Set(ByVal value As Point) _Point1 = value End Set End Property Public Property Point2() As Point Get Return _Point2 End Get Set(ByVal value As Point) _Point2 = value End Set End Property Public Property Rectangle() As Rectangle Get Return _Rectangle End Get Set(ByVal value As Rectangle) _Rectangle = value End Set End Property Public Property Shape() As Shapes Get Return _Shape End Get Set(ByVal value As Shapes) _Shape = value End Set End Property Public Sub Draw(ByVal gr As Graphics) Select Case _Shape Case Shapes.Line Dim pn As New Pen(Color.Red) gr.DrawLine(pn, _Point1, _Point2) Case Shapes.Rectangle Dim br As Brush = New SolidBrush(Color.Blue) gr.FillRectangle(br, _Rectangle) End Select End Sub End Class ' --------------- Ende Datei GraphicObject.vb --------------- ' ---------------- Anfang Datei Rubberband.vb ---------------- Imports System.ComponentModel ''' <summary> ''' Zeichnet ein Rubberband auf einem Control und liefert den ausgewählten Bereich zurück ''' </summary> ''' <remarks></remarks> Public NotInheritable Class Rubberband ''' <summary> ''' Enumeration welche die möglichen Stile auflistet ''' </summary> Public Enum Styles ''' <summary> ''' Zeichnet einen gestrichelten Rahmen ''' </summary> Frame = 0 ''' <summary> ''' Zeichnet ein gefülltes Rechteck ''' </summary> Rectangle = 1 ''' <summary> ''' Zeichnet eine gestrichelte Linie ''' </summary> Line = 2 End Enum ''' <summary> ''' Enumeration welche die möglichen Modi auflistet ''' </summary> ''' <remarks></remarks> Public Enum Modes ''' <summary> ''' Rubberband wird nach drücken der Maustaste/n gestartet und durch loslassen wieder beendet ''' </summary> ''' <remarks></remarks> MouseDown = 0 ''' <summary> ''' Rubberband wird durch einen Click gestartet und durch einen weiteren Click beendet ''' </summary> ''' <remarks>In diesem Modus kann eine Maustaste definiert werden durch die ein Abbruch statt findet und kein Finished-Ereignis ausgelöst wird</remarks> Click = 1 End Enum Private _Mode As Modes ' Lokale Varable die den eingestellten Mode speichert Private _Style As Styles = Styles.Frame ' lokale Variable die den eingestellen Stil speichert Private _IsActive As Boolean = False ' darf ich aktiv werden? Private _ClientRectOnly As Boolean = True ' darf das Rubberband nur im ClientRectangle ' des Controls gezeichnet werden? Private _Buttons As MouseButtons ' Auf welche Maustasten soll reagiert werden? Private _CancelButtons As MouseButtons ' Maustaste/n bei der/denen die Aktion im Modus ' 'Click' abgebrochen werden soll Private _visible As Boolean ' wurde ein Gumminband gezeichnet? Private _RubberOrigin As Point ' Ausgangspunkt für das Rubberband Private _RubberCurrent As Point ' Endpunkt für das Rubberband Private _Rect As Rectangle ' Optionales Begrenzungsrechteck für das Rubberband Private _Backcolor As Color = Color.Yellow ' Hintergrundfarbe für das Rubberband im ' Rechteck Modus Private WithEvents _Control As Control ' Das Control auf dem das Rubberband gezeichnet ' werden soll ''' <summary> ''' Ereignis welches die Beendigung von Rubberband meldet und die Koordinaten liefert ''' </summary> ''' <param name="sender">Das Rubberband-Objekt von dem das Ereignis ausgelöst wurde</param> ''' <param name="e">Ein RubberbandEventArgs-Objekt mit den Koordinaten des ausgewählten Bereichs und er gedrückten Maustasten</param> Public Event Finished(ByVal sender As Object, ByVal e As RubberBandEventArgs) ''' <summary> ''' Ereignis welches den Abbruch von Rubberband meldet ''' </summary> ''' <param name="sender">Das Rubberband-Objekt von dem das Ereignis ausgelöst wurde</param> ''' <param name="e">Ein leeres EventArgs-Objekt</param> ''' <remarks></remarks> Public Event Aborted(ByVal sender As Object, ByVal e As EventArgs) ''' <summary> ''' Initialisiert eine neue Instanz eines Rubberband ''' </summary> Public Sub New() End Sub ''' <summary> ''' Initialisiert eine neue Instanz eines Rubberband ''' </summary> ''' <param name="Control">Ein von Control abgeleitetes Objekt auf dessen MausDown-Ereignis reagiert werden soll</param> Public Sub New(ByVal Control As Control) _Control = Control End Sub ''' <summary> ''' Legt das von Control abgeleitete Objekt fest auf dessen MausDown-Ereignis reagiert werden soll oder gibt es zurück ''' </summary> Public Property Control() As Control Get Return _Control End Get Set(ByVal value As Control) _Control = value End Set End Property ''' <summary> ''' Legt den Stil fest oder gibt ihn zurück ''' </summary> Public Property Style() As Styles Get Return _Style End Get Set(ByVal value As Styles) _Style = value End Set End Property ''' <summary> ''' Legt die Füllfarbe für den Modus Rechteck fest oder gibt sie zurück ''' </summary> ''' <remarks>Entspricht der angezeigten Farbe wenn das Rechteck über einem schwarzen Hintergrund liegt</remarks> Public Property BackColor() As Color Get Return _Backcolor End Get Set(ByVal value As Color) _Backcolor = value End Set End Property ''' <summary> ''' Legt einen Wert fest der bestimmt ob das Rubberband auf den Clientbereich des Controls begrenzt sein soll, oder gibt ihn zurück ''' </summary> ''' <value>True wenn eine Begrenzung erfolgen soll, sonst False</value> Public Property ClientRectOnly() As Boolean Get Return _ClientRectOnly End Get Set(ByVal value As Boolean) _ClientRectOnly = value End Set End Property ''' <summary> ''' Legt ein Begrenzungsrechteck fest oder gibt es zurück ''' </summary> Public Property RestrictionRect() As Rectangle Get If _Rect.IsEmpty Then Return _Control.ClientRectangle Else Return _Rect End If End Get Set(ByVal value As Rectangle) _Rect = value End Set End Property ''' <summary> ''' Liefert True wenn Rubberband auf Maustasten reagieren soll. ''' </summary> Public ReadOnly Property IsActive() As Boolean Get Return _IsActive End Get End Property ''' <summary> ''' Legt einen Wert für den Modus fest oder gibt ihn zurück ''' </summary> ''' <value>Ein gülter Modes-Wert </value> ''' <remarks></remarks> Public Property Mode() As Modes Get Return _Mode End Get Set(ByVal value As Modes) _Mode = value End Set End Property ''' <summary> ''' Setzt Rubberband in den Aktiv-Modus und legt die Maustasten fest auf die reagiert werden soll ''' </summary> ''' <param name="Button">Ein Wert aus der MouseButtons-Enumeration der die Maustaste/n bestimmt auf die reagiert werden soll</param> ''' <param name="CancelButton">Ein Wert aus der MouseButtons-Enumeration der die Maustaste/n bestimmt mit der Rubberband abgerochen wird</param> Public Sub Start(ByVal Button As MouseButtons, ByVal CancelButton As MouseButtons) _Buttons = Button _CancelButtons = CancelButton _IsActive = True End Sub ''' <summary> ''' Bricht den Aktiv-Modus ab und beendet Rubberband ''' </summary> ''' <remarks>Es wird kein Abort-Ereignis ausgelöst</remarks> Public Sub Abort() If _IsActive Then If _visible Then DrawRubberband() _visible = False End If _IsActive = False End If End Sub Private Sub _Control_MouseClick(ByVal sender As Object, ByVal e As _ System.Windows.Forms.MouseEventArgs) Handles _Control.MouseClick If _Mode = Modes.Click Then If _IsActive Then If _visible = True Then ' Rubberband löschen DrawRubberband() _visible = False If (e.Button And _Buttons) > MouseButtons.None Then ' Rubberband wurde korrekt beendet RaiseEvent Finished(Me, New RubberBandEventArgs(_RubberOrigin, _ _RubberCurrent, e.Button)) End If If (e.Button And _CancelButtons) > MouseButtons.None Then ' Rubberband wurde abgebrochen RaiseEvent Aborted(Me, New EventArgs) End If ' nicht mehr auf Mause-Ereignisse reagieren _IsActive = False Else If (e.Button And _Buttons) > MouseButtons.None Then ' Startpunkt merken _RubberOrigin = e.Location ' aktuelle Mausposition speichern _RubberCurrent = e.Location ' Rubberband anzeigen DrawRubberband() ' merken das Rubberband gezeichnet wurde _visible = True End If End If End If End If End Sub Private Sub _Control_MouseDown(ByVal sender As Object, ByVal e As _ System.Windows.Forms.MouseEventArgs) Handles _Control.MouseDown If _Mode = Modes.MouseDown Then ' Ist Rubberband aktiv und einer der richtigen MouseButton gedrückt ? If _IsActive And (_Buttons And e.Button) <> MouseButtons.None Then ' Startpunkt merken _RubberOrigin = e.Location ' aktuelle Mausposition speichern _RubberCurrent = e.Location ' Rubberband anzeigen DrawRubberband() ' merken das Rubberband gezeichnet wurde _visible = True End If End If End Sub Private Sub _Control_MouseMove(ByVal sender As Object, ByVal e As _ System.Windows.Forms.MouseEventArgs) Handles _Control.MouseMove If _Mode = Modes.MouseDown Then ' Ist Rubberband aktiv und einer der richtige Button gedrückt? If _IsActive And (e.Button And _Buttons) <> MouseButtons.None And _visible Then ' vorher gezeichnetes Rubberband löschen DrawRubberband() ' aktuelle Mausposition speichern _RubberCurrent = CalcPoint(e.Location) ' Rubberband wieder anzeigen DrawRubberband() End If ElseIf _Mode = Modes.Click Then If _visible = True Then ' vorher gezeichnetes Rubberband löschen DrawRubberband() ' aktuelle Mausposition speichern _RubberCurrent = CalcPoint(e.Location) ' Rubberband wieder anzeigen DrawRubberband() End If End If End Sub Private Sub _Control_MouseUp(ByVal sender As Object, ByVal e As _ System.Windows.Forms.MouseEventArgs) Handles _Control.MouseUp If _Mode = Modes.MouseDown Then ' Ist Rubberband aktiv und einer der richtige Button gedrückt? If _IsActive And (e.Button And _Buttons) <> MouseButtons.None Then ' Rubberband löschen falls eins gezeichnet wurde If _visible Then DrawRubberband() End If ' nicht mehr auf Mause-Ereignisse reagieren _IsActive = False ' Über die korrekte Fertigstellung benachrichtigen und den ausgewählten ' Bereich zurück liefern RaiseEvent Finished(Me, New RubberBandEventArgs(_RubberOrigin, _ _RubberCurrent, e.Button)) End If End If End Sub ''' <summary> ''' Liefert abhängig von den Einstellungen für RestrictionRect und ClientRectOnly gültiges Point-Objekt ''' </summary> ''' <param name="pt">Point mit den Mauskoordinaten</param> ''' <remarks>RestrictionRect hat immer Vorrang vor ClientRectOnly</remarks> Private Function CalcPoint(ByVal pt As Point) As Point ' Auf das ClientRectangle des Controls begrenzen? Dim rct As Rectangle If ClientRectOnly Then If _Rect.IsEmpty Then rct = _Control.ClientRectangle Else rct = _Rect End If End If If Not rct.IsEmpty Then If pt.X < _Control.ClientRectangle.Left Then pt.X = _Control.ClientRectangle.Left End If If pt.X > _Control.ClientRectangle.Right Then pt.X = _Control.ClientRectangle.Right End If If pt.Y < _Control.ClientRectangle.Top Then pt.Y = _Control.ClientRectangle.Top End If If pt.Y > _Control.ClientRectangle.Bottom Then pt.Y = _Control.ClientRectangle.Bottom End If End If Return pt End Function ''' <summary> ''' Zeichnet auf den Screen oder löscht ein vorher gezeichnetes Objekt. ''' </summary> ''' <remarks>Es wir im XOR-Modus auf den Screen gezeichnet, daher wird eine vorherige Zeichnung an geleicher Stelle wieder umgekehrt.</remarks> Private Sub DrawRubberband() ' Koordinaten der Punkte von Client-Koordinaten in Screen-Koordinaten umrechnen Dim pt1 As Point = _Control.PointToScreen(_RubberOrigin) Dim pt2 As Point = _Control.PointToScreen(_RubberCurrent) ' Rechteck für die Stile 'Frame' und 'Rectangle' erstellen Dim Rect As New Rectangle(pt1, New Size(pt2.X - pt1.X, pt2.Y - pt1.Y)) Select Case _Style Case Styles.Frame ControlPaint.DrawReversibleFrame(Rect, Color.Transparent, FrameStyle.Dashed) Case Styles.Rectangle ControlPaint.FillReversibleRectangle(Rect, _Backcolor) Case Styles.Line ControlPaint.DrawReversibleLine(pt1, pt2, Color.Transparent) End Select End Sub End Class ' ----------------- Ende Datei Rubberband.vb ----------------- ' ----------- Anfang Datei RubberBandEventArgs.vb ----------- ''' <summary> ''' Klasse für das Rubberband.Finished-Event ''' </summary> Public Class RubberBandEventArgs Inherits EventArgs Private _Buttons As MouseButtons Private _Area As Rectangle Private _StartedAt As Point Private _EndedAt As Point ''' <summary> ''' Liefert ein Point-Objekt mit den Koordiaten an dem Rubberband gestartet wurde ''' </summary> ''' <remarks></remarks> Public ReadOnly Property StartedAt() As Point Get Return _StartedAt End Get End Property ''' <summary> ''' Liefert ein Point-Objekt mit den Koordinaten an dem Rubberband beendet wurde ''' </summary> ''' <remarks></remarks> Public ReadOnly Property EndedAt() As Point Get Return _EndedAt End Get End Property ''' <summary> ''' Initialisert eine neue Instanz von RubberbandEventArgs ''' </summary> ''' <param name="StartedAt">ein Point-Objekt mit den Koordinaten an denen Rubberband gestartet wurde</param> ''' <param name="EndedAt">ein Point-Objekt mit den Koordinaten an denen Rubberband beendet wurde</param> ''' <param name="Button">ein Wert der die Maustaste/n angibt mit denen Rubberband gestartet wurde</param> Public Sub New(ByVal StartedAt As Point, ByVal EndedAt As Point, ByVal Button As MouseButtons) MyBase.New() _StartedAt = StartedAt _EndedAt = EndedAt _Area = NormalizedRectangle() _Buttons = Buttons End Sub ''' <summary> ''' Liefert einen Wert der die Maustaste/n angibt mit denen Rubberband gestartet wurde ''' </summary> Public ReadOnly Property Buttons() As MouseButtons Get Return _Buttons End Get End Property ''' <summary> ''' Liefert ein normalisiertes Rectangle-Objekt mit den Koordinaten des ausgewählten Bereichs ''' </summary> Public ReadOnly Property Area() As Rectangle Get Return _Area End Get End Property ''' <summary> ''' Liefert ein normalisiertes Rectangle berechnet aus StartedAt und EndedAt ''' </summary> ''' <returns>Ein normalisiertes Rectangle-Objekt</returns> ''' <remarks>Erstellt ein Rectangle dessen Location-Eigenschaft die linke obere Ecke bestimmt und positive Werte für Width und Height enthält</remarks> Private Function NormalizedRectangle() As Rectangle Dim pt1 As New Point Dim pt2 As New Point If (_StartedAt.X - _EndedAt.X) < 0 Then pt1.X = _StartedAt.X pt2.X = _EndedAt.X Else pt1.X = _EndedAt.X pt2.X = _StartedAt.X End If If (_StartedAt.Y - _EndedAt.Y) < 0 Then pt1.Y = _StartedAt.Y pt2.Y = _EndedAt.Y Else pt1.Y = _EndedAt.Y pt2.Y = _StartedAt.Y End If Return New Rectangle(pt1, New Size(pt2.X - pt1.X, pt2.Y - pt1.Y)) End Function End Class ' ------------ Ende Datei RubberBandEventArgs.vb ------------ ' --------- Ende Projektdatei RubberbandDemo.vbproj --------- ' ---------- Ende Projektgruppe RubberbandDemo.sln ----------
Diskussion
Diese Funktion ermöglicht es, Fragen, die die Veröffentlichung des Tipps betreffen, zu klären, oder Anregungen und Verbesserungsvorschläge einzubringen. Nach der Veröffentlichung des Tipps werden diese Beiträge nicht weiter verlinkt. Allgemeine Fragen zum Inhalt sollten daher hier nicht geklärt werden.
Folgende Diskussionen existieren bereits
Um eine Diskussion eröffnen zu können, müssen sie angemeldet sein.