Anfängerfrage: Klasseneigenschaften über eine Form ändern, ist das möglich?

  • VB.NET

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Anfängerfrage: Klasseneigenschaften über eine Form ändern, ist das möglich?

    Hallo,

    ich arbeite mich gerade erst in VB.net ein und stehe gerade vor einem Problem. Eine Lösung hierfür habe ich auch nach längerem Suchen nicht finden können. Vielleicht fehlt mir einfach das richtige Schlagwort.

    Bsp.: Ich habe eine Regler-Klasse geschrieben, welche einige Klasseneigenschaften aufweist, die genullt sind

    Public Class Regler

    Dim IstWert As Double = 0
    Dim SollWert As Double = 0
    Dim ZulAbweichung As Double = 0
    Dim AusgangsZust As Boolean = False

    Public Sub Verarbeitung ( usw.
    ...
    End Sub
    End Class

    Nun möchte ich 2 oder mehrere Instanzen dieses Reglers instantiieren, was auch klappt. Allerdings möchte ich dem Nutzer die Möglichkeit geben, z.B. den SollWert und die ZulAbweichung zur Laufzeit jeder der Instanzen zu verändern. Ich möchte also für jede Instanz eine Form öffnen, in der der Nutzer die zugänglichen Klaseneigenschaften konfigurieren kann.

    Wie kann ich das anstellen?

    Aus der Klasseninstanz heraus ein Formular aufzurufen, welches entsprechende Einstellfunktionen hätte,klappt nicht, weil der Kompiler natürlich noch nicht die instantiierten Klasseneigenschaften kennt, z.B. ReglerA.SollWert = ...

    Kann mir einer von euch einen Fingerzeit in die richtige Richtung geben?

    Mit Dank und Gruß

    Joseph
    Willkommen Joseph, schöner Name.

    Ich glaube was du suchst sind sogenannte Modifizierer, die die Zugriffsrechte auf Eigenschaften oder Methoden einer Klasse kontrollieren.

    Wenn ich dich richtig verstanden habe , ist das was du suchst das Public-Schlüsselwort...einfach das Dim mit Public ersetzen, dann kannst du den Wert der Eigenschaft ReglarA.SollWert auch zur Laufzeit modifizieren.
    Und Gott alleine weiß alles am allerbesten und besser.
    Hallo (phi)-Const (mir ist die Phi-Taste abhanden gekommen...)

    Danke für deine Nachricht.

    Mein Gedanke bei dem "DIM" war, dass diese Größen außerhalb der Klassen nicht modifiziert werden können sollen. So schreiben es zumindest die Bücher. Daher war mein Gedanke, eine Form aus meiner Klasse selbst heraus aufzurufen. Damit hätte diese Form dann ja Zugriffsrechte.

    Ich glaube das Problem ist, dass die Form nicht "sieht", dass Sie aus der Klasse Regler heraus instantiiert wird, also nicht dazugehört. Es müsste irgendwie mitgeteilt werden, dass sie aus dem gleichen Raum wie die Reglerklasse kommt.

    Ich habe es gerade mal probiert. Auch ein Public bringt hier keinen Fortschritt.


    Mit Dank und Gruß

    Joseph
    @JosephP
    Ah.. ich weiß was dein Problem ist.

    Du musst die Klasse natürlich instanziieren...
    also Dim ReglerKlasseMeineInstanz As new ReglerA ... wenn du es aber ohne Instanziierung tun willst, benutze public shared.

    Das sind fundamentale Dinge : Klassen und Objekte, mit dem New-Schlüsselwort generierst du ein Objekt der Klasse A.. auf dessen Member du dann zugreifen kannst, sofern der Modifizierer dies permittiert.
    Und Gott alleine weiß alles am allerbesten und besser.

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

    Hallo,

    nein, das ist nicht mein Problem. Klar, dass ich die Klasse erst instantiieren muss wenn ich sie nutzen möchte.

    Mein Problem ist: wie kann ich eine Form aus einer instantiierten Klasse heraus aufrufen, um mit dieser dann seine Klasseneigenschaften zu verändern. Das Formular soll zunächst den aktuellen Zustand der gewünschten Klasseneigenschaften anzeigen und dann ggf. die über Steuerelemente geänderten Werte wieder zurück schreiben.

    Mein Ansatz bislang stark vereinfacht:

    Public Class Regler

    Dim IstWert As Double = 0
    Dim SollWert As Double = 0
    Dim ZulAbweichung As Double = 0
    Dim AusgangsZust As Boolean = False

    PrivateSub Verarbeitung ( ) 'Funktion, die irgendwas mit den Werten macht
    ...
    End Sub

    Public Sub SollWertSetzen (ByVal wert As Double)
    'Prozedur, welche die Eigenschaft SollWert für jede Instanz nach außen schreibbar macht
    SollWert = wert
    End Sub

    Public Function SollWertLesen () As Double
    'Funktion, welche die Eigenschaft SollWert für jede Instanz nach außen lesbar macht
    return SollWert
    End Function

    Public Sub WerteAendern ()
    'Formularaufruf, welches über SollWertLesen und SollWertSchreiben die jeweiligen Objekteigenschaften verändern soll
    Form_Konfig.ShowDialog()
    End Sub

    End Class


    Die aufzurufende Formularklasse habe ich erzeugt und in der Datei steht grob

    Public Class Form_Konfig

    Private Form_Konfig_Load(....)

    'Der NumericUpDown soll den aktuellen SollWert aus der jeweiligen Instanz anzeigen
    NumericUpDown_SollWert.Value =SollWertLesen()

    End Sub
    End Class

    Natürlich kann das Formular außerhalb der Laufzeit die Methode SollWertLesen() noch nicht erkennen -> der Kompiler meckert.

    Doch wie mache ich das richtig? Im Idealfall sollen n Instanzen der Klasse Regler instanziiert sein und jedes Reglerobjekt auf ein eigenes, unabhängiges Formular zugreifen und darüber konfiguriert werden können.

    Prozedural programmiert hätte ich das über ein globales Array gelöst, in welches die Regler-Methode (dann ja Funktion) und die Konfigurations-Form gleichberechtigt schreiben und lesen können. Unter OOP wird das umständlicher.

    Ich hoffe, dass ich mich etwas klarer ausgedrückt habe.

    Mit Dank und Gruß

    Joseph
    Nein, du machst das wie du es jetzt machst ganz seltsam.


    Folgendes:

    Du hast eine Klasse Regler.. die größte Frage die ich mir persönlich stelle ist, wieso du Form_Konfig.ShowDialog() aufrufst, ohne ein Objekt der Klasse Form_Konfig zu haben.

    VB.NET-Quellcode

    1. Dim knfg As New Form_Konfig


    Kennst du Konstruktoren?

    Generiere in der Klasse Form_Konfig einen Konstruktor:

    VB.NET-Quellcode

    1. public Sub New(Regler regler)
    2. End Sub



    Deklariere eine globale Variable , Regler:

    VB.NET-Quellcode

    1. Dim Regler As Regler
    2. public Sub New(Regler regler)
    3. Regler = regler
    4. End Sub


    VB.NET-Quellcode

    1. Dim knfg As New Form_Konfig
    wird zu

    VB.NET-Quellcode

    1. Dim knfg As New Form_Konfig(Me)


    Nun kannst du

    VB.NET-Quellcode

    1. Private Form_Konfig_Load(....)
    2. 'Der NumericUpDown soll den aktuellen SollWert aus der jeweiligen Instanz anzeige
    3. nNumericUpDown_SollWert.Value =Regler.SollWertLesen()
    4. End Sub
    , und es muss klappen.
    Und Gott alleine weiß alles am allerbesten und besser.
    Hallo,

    "Du hast eine Klasse Regler.. die größte Frage die ich mir persönlich stelle ist, wieso du Form_Konfig.ShowDialog() aufrufst, ohne ein Objekt der Klasse Form_Konfig zu haben."

    Genau das ist ja auch der wunde Punkt. Ich wollte verdeutlichen, was ich erreichen möchte. Aber so kann es nicht klappen.

    Ja, die Funktion von Konstruktoren ist mir bekannt. Nein, oft verwendet habe ich sie noch nicht. Wenn, dann in der Form

    Dim Reglerobjekt As New Regler

    Ich werde mir deinen Ansatz morgen mit klarerem Kopf ansehen. Ich glaube, dass das der gesuchte Ansatz sein könnte.

    Ich melde mich morgen.

    Vielen Dank!

    Mit Gruß

    Joseph

    JosephP schrieb:

    Ich glaube, dass das der gesuchte Ansatz sein könnte.
    Sry - Glaub ich weniger. Vlt im weitesten Sinne, aber zunächstmal kompiliert das ühaupt nicht, was @const präsentiert.
    Und von globalen Instanzierungen sollte man auch weitestgehend absehen.

    Ich sehe dein Problem eher so: Deine Regler-Objekte sind Datensätze, und was du proggst ist eine Datenverwaltung.
    Imo solltest du nicht für jeden Regler ein eigenes Form anlegen, weil bei 50 Datensätzen dürfte der User da unfröhlich werden.
    Fasse deine Regler in einer List(of Regler) zusammen, und zeige die List(Of Regler) im MainForm an. Dabei zeigt sich, dass so ein Regler auch einen Namen braucht, sonst kann man sie als User nicht unterscheiden. Dann jedenfalls - im Form_Load:

    VB.NET-Quellcode

    1. Private _Reglers As New List(Of Regler)
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    3. For i = 0 To 4
    4. Dim rgl = New Regler With {.Name = "Regler" & i}
    5. '... weitere Voreinstellungen
    6. _Reglers.Add(rgl)
    7. Next
    8. lstReglers.DisplayMember = "Name" '"Name" ist die Property, die die Listbox anzeigt
    9. lstReglers.DataSource = _Reglers
    10. End Sub
    11. Private Sub lstReglers_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstReglers.SelectedIndexChanged
    12. Dim rgl = _Reglers(lstReglers.SelectedIndex)
    13. If MessageBox.Show(String.Format("{0}: Soll: {1}, Ist: {2}", rgl.Name, rgl.SollWert, rgl.IstWert), _
    14. "verarbeiten?", _
    15. MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
    16. rgl.Verarbeitung()
    17. End If
    18. End Sub
    19. Public Class Regler
    20. Public Property IstWert As Double = 0
    21. Public Property SollWert As Double = 0
    22. Public Property ZulAbweichung As Double = 0
    23. Public Property AusgangsZust As Boolean = False
    24. Public Property Name As String
    25. Public Sub Verarbeitung()
    26. End Sub
    27. End Class
    Das wäre der erste Einstieg in Datenverarbeitung - tatsächlich würde man sehr anders vorgehen, mit einem auf Datenverarbeitung spezialisierten Instrumentarium.
    Aber das Sample beinhaltet auch so schon jede Menge wichtiger Grundlagen:
    • List(Of T)
    • With {} - Initialisierung
    • primitives Databinding
    • String.Format-Methode
    • Messagebox mit Auswertung
    • AutoProperties
    • Vor allem: Benamung!, denn
      Nomen est Omen!
      - die Regler-Liste und auch die Listbox haben einen richtigen Namen - wer Listbox1, Button1 etc verwendet, wird erschossen - dass du das gleich weißt.

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

    @EDR , ich glaube du hast mich missverstanden.

    Es ging mir gar nicht darum, zu zeigen, wie es implementiert werden soll, aber der @TE hat folgendes gemacht:

    VB.NET-Quellcode

    1. Public Class Form_Konfig
    2. Private Form_Konfig_Load(....)'
    3. Der NumericUpDown soll den aktuellen SollWert aus der jeweiligen Instanz
    4. anzeigenNumericUpDown_SollWert.Value =SollWertLesen()
    5. End Sub
    6. End Class

    die Methode SollWertLesen, ist nicht in dieser Klasse vertreten, sondern in der anderen.ich habe mir deswegen gedacht, die Klasse Form_Konfig erhält über den Konstruktor die Klasse
    Regler,wodurch er nun auf die Methoden zugreifen kann( Objekt einer Klasse ).

    Im Beitrag #4 habe ich ihm die Stichwörter Getter und Setter vorgeworfen, doch das soll es auch nicht gewesen sein( vor dem Edit ).

    Im Übrigen hast du eine globale Variable in deinem Exempel... wieso auch nur lokale, werden doch direkt vom GC bereinigt.

    Zugegeben, ich programmiere grundsätzlich in C#, deswegen entschuldige ich mich natürlich an dieser Stelle für Fehlinformationen.
    Und Gott alleine weiß alles am allerbesten und besser.
    Hallo,

    wow, vielen Dank für die Antworten.

    @EaranMaleasi:

    Ich hoffe, du meintest mit deinem Hinweis nur die Darstellungsform, also die Formatierung meines Beitrages. Sonst sag mir bitte, wie ich meine Beiträge verbessern kann.
    Was die Formatierung anbelangt: ich hoffe, dass ich das nun besser mache :)

    φConst:

    Ich kann deinen Code leider nicht nachvollziehen. Die Stelle verstehe ich und der Kompiler nicht.

    VB.NET-Quellcode

    1. Dim Regler As Regler
    2. public Sub New(Regler regler)
    3. Regler = regler
    4. End Sub


    Was machst du in der Zeile?

    VB.NET-Quellcode

    1. public Sub New(Regler regler)


    Ich konnte eine solche Form auch nicht nachschlagen.

    @ErfinderDesRades:

    Danke für deine Arbeit. Ich hoffe, das hilft.

    Ich würde deinen Ansatz gerne verstehen, denn offenbar verfolgst du einen ganz anderen Ansatz als ich.

    VB.NET-Quellcode

    1. Private _Reglers As New List(Of Regler)
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    3. For i = 0 To 4
    4. Dim rgl = New Regler With {.Name = "Regler" & i}
    5. '... weitere Voreinstellungen
    6. _Reglers.Add(rgl)
    7. Next
    8. lstReglers.DisplayMember = "Name" '"Name" ist die Property, die die Listbox anzeigt
    9. lstReglers.DataSource = _Reglers
    10. End Sub


    Du erzeugst ein List(of T) Objekt _Reglers mit den Eigenschaften der Klasse Regler. Gut.
    Dann übergibst du dem Klassenkonstruktor eine Klasseneigenschaft "Name", mit der du die Instanzen unterscheiden kannst. Dafür legst du in der Klasse Regler eine zusätzliche Public Eigenschaft "Name" an.

    VB.NET-Quellcode

    1. Public Class Regler
    2. Public Property IstWert As Double = 0
    3. Public Property SollWert As Double = 0
    4. Public Property ZulAbweichung As Double = 0
    5. Public Property AusgangsZust As Boolean = False
    6. Public Property Name As String
    7. Public Sub Verarbeitung()
    8. End Sub
    9. End Class


    Soweit gut. Jede Instanz bekommt nun über den Konstruktor einen mit i indizierten Namen. Jedes erzeugte Objekt wird dann in die List (of T) übernommen. Anschließend kann man die entsprechenden Members der Instanzen über die ListBox ansehen.

    VB.NET-Quellcode

    1. Private Sub lstReglers_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstReglers.SelectedIndexChanged
    2. Dim rgl = _Reglers(lstReglers.SelectedIndex)
    3. If MessageBox.Show(String.Format("{0}: Soll: {1}, Ist: {2}", rgl.Name, rgl.SollWert, rgl.IstWert), _
    4. "verarbeiten?", _
    5. MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
    6. rgl.Verarbeitung()
    7. End If
    8. End Sub


    Wie die Verarbeitung der Objekteigenschaften nun genau aussieht, ist zunächst zweitrangig. Was mich aber interessiert ist:
    Das jeweilige Reglerobjekt ist instantiiert unter einem Objektnamen rgl.

    VB.NET-Quellcode

    1. Dim rgl = New Regler With {.Name = "Regler" & i}


    Die instantiierten Objekte unterscheiden sich nach der Instantiierung nur durch die Eigenschaft ".Name".
    Nach seiner Erschaffung wird jedes der Objekte in die List(of T) aufgenommen oder nur seine Eigenschaft in diese Liste abgebildet?

    VB.NET-Quellcode

    1. _Reglers.Add(rgl)


    Wenn sie nur zum Instantiierungszeitpunkt abgebildet würde, so könnte zwar auf die Eigenschaften im Instanziierungszustand als Kopie zugegriffen werden, eine Veränderung der Eigenschaften über einen Listenzugriff wäre aber nicht möglich.
    Oder ist die Abbildung der Objekteigenschaften über die List(of T) transparent, also eine Art Zeiger auf das Objekt zur Laufzeit? Das wäre natürlich eine mächtige Sache.

    Ich habe nur eine Ahnung was List(of T) grob macht aber so tief ist mein Verständnis noch nicht. Ich habe es bislang für Protokolllisten verwendet, bei denen statische Größen abgelegt wurden.

    Wie könnte ich nach deinem Beispiel schreibend z.B. die Objekteigenschaft

    VB.NET-Quellcode

    1. Public Property ZulAbweichung As Double = 0


    während der Lebenszeit z.B. des Reglerobjekts mit rgl.Name = Regler1 verändern?

    Ich danke dir sehr für die ausführliche Darstellung. Als Anfänger ist ein konkretes Beispiel viel mehr Wert als eine abstrakte Darstellung.

    Mit Dank

    Joseph
    Du kannst mein Sample direkt in einem Form von dir einsetzen. Nur die Listbox musst du hinzufügen, und so benennen, dass mein Code sie anspricht.

    Zu deiner Frage zur List(Of T):
    Sowas ist eine Liste. Da tut man Sachen rein, und kann sie auch wieder abrufen. Und darin hab ich nicht ReglerEigenschaften getan, sondern Regler, also die Regler-Objekte selbst.

    JosephP schrieb:

    VB.NET-Quellcode

    1. Dim rgl = New Regler With {.Name = "Regler" & i}
    Das jeweilige Reglerobjekt ist instantiiert unter einem Objektnamen rgl.
    Es ist instanziert, und einer Variable zugewiesen, der Variable rgl. "Unter einem Namen instanziieren" ist ein Ausdruck, der in vb.net keinen Sinn ergibt.
    Mit der Variable kann ich was machen, etwa sie einer List(Of Regler) zufügen.
    Dann ist das Regler-Objekt nicht nur in der Variablen drin (als einziges), sondern ausserdem auch in der Liste (als eins von vielen).
    Es geht also nicht verloren, wenn im nächsten Schliefendurchgang der rgl-Variable ein neues (New) Regler-Objekt zugewiesen wird.