Frage zu Set Form = Nothing

10/10/2008 - 21:28 von Wolfgang Bußmann | Report spam
Hallo an alle VB6-Freunde,

ich habe mal eine Prinzipfrage zu Formularen.

Angenommen ich habe eine Form1 = "Hauptform" und eine Form2 =
"Nebenform" und folgenden Beispielcode in der Hauptform(Auszug).

*****************
Option Explicit

Private Declare Function ShowWindow Lib "user32.dll" (ByVal hwnd As
long, ByVal nCmdShow As Long) As Long

Private Const SW_SHOWNOACTIVATE As Long = 4

private NeueForm2 as Form

Private Sub cmdCommand5_Click()
'Neue Form auf Grundlage von Nebenform erstellen und mit Dummys füllen
if neueform2 is nothing then
Set NeueForm2 = New Nebenform
NeueForm2.Left = 7000
NeueForm2.Top = 5000
NeueForm2.BackColor = vbYellow
Load NeueForm2 ' Form in Speicher laden

'Form anzeigen lassen, aber nicht aktivieren
ShowWindow NeueForm2.hwnd, SW_SHOWNOACTIVATE
NeueForm2.Print "Hallo" 'Testausgabe
endif
End Sub

Private Sub cmdCommand6_Click()
If Not NeueForm2 Is Nothing Then
Unload NeueForm2
Set NeueForm2 = Nothing
End If
End Sub
*************

Laut der Hilfe, wenn ich sie denn richtig verstehe, bleiben beim Unload
eines Formulars die "Entwurfswerte" des Formulars im Speicher und
könnten über Load wieder geladen werden. Nur die zwischenzeitlich durch
Programmcode durchgeführten Änderungen sind "verloren".

Was passiert aber im cmdCommand6_Click Ereignis beim Set Neueform2 =
Nothing. Ich möchte erreichen, dass bei mehrfachem Aufruf wirklich alle
Daten von Neueform2, freigegeben werden und der Speicher nicht
aufgeblàht wird. Die Daten der Nebenform sollen natürlich für den
wiederholten Aufruf vorhanden bleiben.

Für eine kurze Erklàrung wàre ich dankbar.

Wolfgang Bußmann
 

Lesen sie die antworten

#1 Ulrich Korndoerfer
13/10/2008 - 01:38 | Warnen spam
Hallo Wolfgang,

Wolfgang Bußmann schrieb:

...
ich habe mal eine Prinzipfrage zu Formularen.



Auf prinzipielle Fragen gibt es prinzipielle Antworten ;-)

Ausgangslage:

- im Projekt befindet sich eine Form namens MyForm
- MyForm hat folgende Controls:
- eine Textbox MyTextBox
- MyForm hat folgenden Code:

Public MyText As String

Private mMyCounter As Long

Public Property Let MyCounter(ByVal Value As Long)
mMyCounter = Value
End Property
Public Property Get MyCounter() As Long
MyCounter = mMyCounter
End Property

Public Sub ShowMyForm(Optional ByVal InitialText As String)
If Len(InitialText) > 0 Then MyText = InitialText
Load Me
Me.Show
End Sub

Private Sub Form_Load()
mMyCounter = mMyCounter + 1
MyTextBox.Text = MyText
End Sub

Private Sub Form_Unload(Cancel As Integer)
MyText = MyTextBox.Text
End Sub

Damit existiert im Projekt eine *Klasse* namens MyForm, deren
öffentliches Interface Zugriff bietet auf:

A) alle Methoden und Eigenschaften der (vordefinierten) Klasse Form.
Dazu gehören zB. die Move-Methode, die Font-Property, etc.

B) für jedes Control der Form eine Read-Only Eigenschaft, also für die
TextBox die Eigenschaft MyTextBox.

C) alle im Code von MyForm deklarierten öffentlichen Methoden und
Eigenschaften, also die Methode ShowMyForm und die Eigenschaften MyText
und MyCounter. Der Zugriff auf öffentlich erklàrte Variable wie MyText
wird intern über Eigenschaftenpàrchen realisiert.

Zusàtzlich wird intern und verborgen eine globale Variable des *Namens*
MyForm und des *Typs* MyForm angelegt. Würde der Entwickler diese selbst
deklarieren müssen, würde er in einem Modul schreiben:

Public MyForm As New MyForm

Die Variable MyForm ist auf Grund dieser Deklaration
*selbstinstantiierend*. Immer dann, wenn im Code eine Methode oder
Eigenschaft über diese Variable verwendet wird, prüft VB vorher, ob
diese Variable auf eine Instanz einer Klasse des Typs MyForm verweist,
also nicht Nothing ist. Falls die Variable MyForm Nothing ist, erzeugt
VB automatisch eine neue Instanz. Beispiele dafür (in den folgenden
Beispielen erzeugt VB also eine neue Instanz des Typs MyForm, wenn
MyForm Nothing ist):

A) MyForm.MyText = "Test"
B) Set TB = MyForm.MyTextBox
C) MyForm.Move 0, 0
D) MyForm.Show

In den Fàllen B) und C) wird zusàtzlich noch die neue Forminstanz
geladen (siehe weiter unten), im Fall D außerdem auch noch angezeigt.

Dagegen wird in den folgenden Beispielen *nicht* automatisch eine
Forminstanz erzeugt:

A) Set MyRef = MyForm
B) Set MyForm = Nothing

Im Fall A ist MyRef Nothing, wenn MyForm Nothing war, ansonsten hàlt
MyRef einfach einen weiteren Verweis auf die von MyForm referenzierte
Instanz. Im Fall B ist MyForm auf jedenfall Nothing.

Eine Instanz des Typs MyForm setzt sich aus mehreren Teilen zusammen
(das macht VB hinter den Kulissen automatisch):

Mit

Dim f As MyForm: Set f = New MyForm

wird der Teil C instantiiert und initialisiert, der den Teil C (von
oben) des öffentlichen Interfaces realisiert. Es wird auch der
Form_Initialize Event ausgelöst. In diesem Zustand verhàlt sich die
Instanz wie jede andere Instanz von gewöhnlichen (nicht Form) Klassen.
Solange noch eine Referenz auf diese Instanz existiert, "lebt" das
Objekt noch. Alle Daten bleiben erhalten. Erst wenn die letzte Referenz
auf diese Instanz entfàllt, wird die Instanz zerstört (dabei wird der
Form_Terminate Event ausgelöst).

Die "ganze" Form mit allen Teilen (inklusive der Controls) entsteht erst
dann, wenn die Instanz geladen wird:

Load f

Dabei wird der Form_Load Event ausgelöst.

Ab jetzt stehen auch die Teile A und B von oben zur Verfügung. VB hat
hier (leider) auch einen Autoload-Mechanismus: sobald auf eine Methode
oder Eigenschaft der Teile A oder B zugegriffen wird, làdt VB die
Instanz automatisch.

Dim f As MyForm: Set f = New MyForm
f.Move 0, 0

ist also àquivalent zu

Dim f As MyForm: Set f = New MyForm
Load f: f.Move 0, 0

Beim Laden werden nicht nur die noch fehlenden Teile der Form erzeugt.
Es wird eine Referenz auf die Instanz in die global verfügbare Forms
Auflistung (im wesentlichen eine Collection) aufgenommen. Die Aussagen
"eine Forminstanz ist geladen" und "eine Referenz auf eine Forminstanz
ist in der Forms Auflistung" sind dabei synonym: das eine bedingt das
andere und umgekehrt.

Ebenso wird eine Instanz einer Form dadurch entladen, daß sie aus der
Forms - Auflistung entfernt wird:

Unload f

entfernt die Referenz aus der Forms-Auflistung. Es wird erst das
Form_Unload Ereignis gefeuert, dann werden die Teile A und B zerstört.
Damit ist dann die Textbox samt Inhalt weg. Alle Eigenschaftswerte der
Teile A und B, die ziwschenzeitlich per Code gesetzt wurden, sind
ebenfalls weg. Aber:

der Teil C der Instanz, die f referenziert, ist noch unveràndert
vorhanden! Nach obigem Unload liefert zB.

Print f.MyText den Inhalt von Mytext!

Ein erneutes Load f erzeugt nur die Teile A und B neu, Teil C samt
seinem Inhalt bleibt erhalten! Erst wenn f zu Nothing gesetzt wird, und
f die einzige Referenz ist, wird der Teil C zerstört!

Dim f As MyForm: Set f = New MyForm
Load f: Set f = Nothing

erzeugt eine komplette Forminstanz (alle drei Teile), die auch nach dem
Nothing setzen von f noch existiert! Der Grund ist, daß durch das Load
eine weitere Referenz in der Forms-Auflistung existiert!

Dim f As MyForm: Set f = New MyForm
Load f: Unload f

dagegen làßt die Referenz in f unveràndert, und die der Teil C der
Instanz lebt immer noch.

Damit zum Schluß:

wenn man State (also Information) zwischen dem Zerstören einer Form und
dem Wiederneumachen aufheben will, hebt man diese im Teil C einer Form
auf: also in privaten Variablen, die per Property öffentlich zugànglich
gemacht werden oder gleich in öffentlichen Variablen. Und man sorgt
dafür, daß beim Zerstören der Teile A und B die zu rettenden
Informationen aus diesen Teilen zB im Form_Unload in den Teil C
transferiert werden und beim Neuerzeugen der Teile A und B aus dem Teil
C wieder zurückgeschrieben werden. Obiger Code zB. rettet den Inhalt der
TextBox und stellt ihn beim Neuerzeugen wieder her.

Anwendung in einer anderen Form wàre dann zB:

Private mMyForm As MyForm

Private Sub cmdShowMyForm_Click()
If mMyForm Is Nothing Then
Set mMyForm = New MyForm
mMyForm.ShowMyForm "This is the starting text"
Else
mMyForm.ShowMyForm
End If
End Sub

Wenn MyForm geschlossen wird, rettet diese automatisch ihren state. Wird
sie wieder erzeugt, wird der alte Zustand wieder hergestellt.

Das Schließen von MyForm kann wie gewöhnlich über den Schließen-Knopf
des Fenster veranlasst werden, oder über den Aufruf von Unload Me im
Code von MyForm oder auch in der anderen Form über zB:

Private Sub cmdCloseMyForm_Click()
If mMyForm Is Nothing Then Exit Sub
Unload mMyForm
End Sub

Unload wirft hier keinen Fehler, wenn es die Referenz in der
Forms-Auflistung nicht findet (also mMyForm nicht geladen ist).

Ulrich Korndoerfer

VB tips, helpers, solutions -> http://www.proSource.de/Downloads/

Ähnliche fragen