# Private Objektmodule dürfen in öffentlichen...



## DrMueller (14. November 2007)

Hallo Leute mal wieder,
folgendes, merkwürdiges Problem, das, nachdem mir jemand die Lösung gesagt hat, mir sicher ein Kopfschütteln bereiten wird. Also folgendes ist die Messagebog:
Private Objektmodule dürfen in öffentlichen 
Objektmodulen nicht als Parameter oder Rückgabetypen 
für öffentliche Prozeduren, als öffentliche Datenmitglieder, 
oder als Felder öffentlicher, benutzerdefinerter Typen verwendet werden.
Der Code lautet wie folgt:


```
Public Sub putfensterinMiddle(ByRef f As Form)
  Dim iScreenBreite As Integer
  Dim iScreenHoehe As Integer
  Dim iFensterBreite As Integer
  Dim iFensterHoehe As Integer
  Dim iFensterTop As Integer
  Dim iFensterLeft As Integer
  
  iScreenBreite = Screen.Width
  iScreenHoehe = Screen.Height
  
  iFensterBreite = f.Width
  iFensterHoehe = f.Height
  
  iFensterLeft = iScreenBreite / 2
  iFensterLeft = iFensterLeft - (iFensterBreite / 2)
  
  iFensterTop = iScreenHoehe / 2
  iFensterTop = iFensterTop - (iFensterHoehe / 2)
  
  f.Top = iFensterTop
  f.Left = iFensterLeft
End Sub
```

Diese Funktion ist bei einem Klassenmodul (cls) eingefügt.
Doch irgendwie motzt das Programm wegen dem f as form und gibt eben die oben genannte Fehlermeldung aus.
Ich kenne mich nicht so genau damit aus, aber ich dachte Form sei eigentlich frei benutzbar oder gibts da irgendwie Einschränkungen?


----------



## Elvan (14. November 2007)

Hi
schreib mal anstatt "Public Sub", "Private Sub" dann sollte es gehen.
Nein keine Einschränkungen, er motzt auch nicht weger der Form, sondern wegen irgendwelcher "Deklarierungen".
Wenn das nicht hinhaut - mach mal byref weg.
Aber je mehr ich darüber nachdenke, stelle ich fest... eigendlich dürfte er gar nicht meckern. Hmm egal.
Cu


----------



## DrMueller (14. November 2007)

Public darf ich leider nicht wegnehmen, da ich das ja dann in allen Forms benutzen will.
Ohne byref funktionierts auch nicht. Aber auch das Byref ist ja Pflicht, da sonst gar nix passiert.
Schön blöd, bei nem anderen CLS gehts, aber dann stimmt die Strukturierung nicht mehr. tt


----------



## deepthroat (14. November 2007)

Hi.

Kann es sein, das du den Typ Form in deiner Klasse als privat deklariert hast? Oder eine private Klasse namens Form?

Versuch mal 
	
	
	



```
Public Sub putfensterinMiddle(ByRef f As VB.Form)
```
Gruß


----------



## DrMueller (14. November 2007)

War eine sehr gute Idee, leider kommt die Fehlermeldung immer noch.
Ich kapier schon net wieso in der Fehlermeldung zwei mal hintereinander Objektmodul steht.
Naja muss ich wohl weiter testen, wäre aber natürlich für jede Idee, egal was für Eine, froh.


----------



## ronaldh (14. November 2007)

Es funktioniert, wenn Du die Sub in ein Modul anstatt in eine Klasse tust. Gibt es einen triftigen Grund, dies unbedingt in eine Klasse zu tun?

Wenn Du es in eine Klasse tust, muss der Aufruf wie folgt sein:


```
Private Sub Command1_Click()
   Dim Cl As New Class1
   Cl.putfensterinMiddle frmMain
End Sub
```

Ich habe mir hier eben mal eine nackste Klasse "Class1" angelegt, da klappt es so auch. 

Vermutlich hängt das eher mit dem Aufruf zusammen. Die Prozedur selbst ist in Ordnung.

Ronald


----------



## DrMueller (15. November 2007)

Bei uns herscht eigentlich die Regel, das Publics nicht in Forms kommen. Dazu ist ja das witzige, dass ich zwei CLS habe, das andere jedoch rein datenbanktechnische Funktionen verwaltet. Als ich es versuchsweise dort hinein getan habe, hat er geklappt.
Auch wenn ich ByRef fo As VB.Form als Wert rausnehme, funktioniert es. Am "f" kanns also auch nicht liegen, da ich f versuchsweise neu als fo deklariert habe. Das Einzige was bleibt, ist also das VB.form.


----------



## ronaldh (15. November 2007)

Ich meinte auch nicht, dass die Prozedur in eine Form gehört, da gehören Publics wirklich nicht hin. Ich habe von einem Modul geredet. Und da gehören derartige Prozeduren schon hin. 

Ronald


----------



## DrMueller (15. November 2007)

Das Projekt ist von der Logik her so aufgebaut:
1. Ne Menge Formulare
2. 2 Module: Konstantendeklraration und Spezialcode für Foldersearch
3. 2 Klassenmodule, ein Allgemeines (dort hätte ich eben die Sub gern drin) und eine, die für die Datenbankstruktur zuständig ist.

Wenn ich jetzt die Sub vom Allgemeinen in das Datenbankstruktur Klassenmodul verschiebe, funktioniert es mit dem Form.

Wenn ich in anderen Projekten die Funktion als Private direkt in ein Form stelle, funktioniert es auch.

Es funktioniert also genau in diesem Klassenmodul nicht, und der Grund ist diese Form Deklaration.
Deswegen kann ich mir gar keinen Reim darauf machen.


----------



## DrMueller (16. November 2007)

Zum vorherigen Problem: Ich habs einfach in die einzelnen Forms als private gepackt, ist zwar nicht gerade effizent, aber besser als Stunden über ein Problem nachzudenken.
Meine andere Frage:
So wie ichs unten mache, wird das Form ja einfach abgeschnitten. Dies ist als Test wegen der Breite etc. zwar zu gebrauchen, darf aber natürlich nicht drin bleiben.
Daher gibts eine einfache Möglichkeit, Forms und Controls zu skalieren? Am besten noch, dass, wenn der User das Form verändert, die Controls ebenfalls mitskalieren.


----------



## ronaldh (16. November 2007)

Ehrlich gesagt, verstehe ich immer noch nicht, warum Du Deine Prozedur nicht in ein MODUL packst. Da gibt es keine Probleme, und Du musst sie nicht in jede Form tun, was dem Programm nun wirklich nicht gut tut.

Zu Deiner zweiten Frage lies mal diesen Tipp. Der hilft Dir weiter.

Grüsse
ronaldh


----------



## DrMueller (16. November 2007)

Vielen dank für den Link, irgendwie bin ich noch net so geübt darin, solche Dinge im Internet zu finden.


----------



## DrMueller (22. November 2007)

Hey das hat mit leichteren Anpassungen toll funktioniert, ich danke.
Noch eine kleinere Frage.
Ich würde gerne die Grösse und Position des Fensters in die Registry speichern und diese dann beim nächsten Startup wieder auslesen.
Das Problem ist, wenn der Benutzer nur die Position ändert, zündet weder der Resize noch sonst irgend ein Event, den ich ausprobiert habe.
Das einzige, was mir einfällt, ist etwas mit den Mouseclickevents zu basteln, aber da gibts doch sicher eine elegantere Lösung?


----------



## ronaldh (22. November 2007)

Freut mich, wenn ich Dir helfen konnte.

Ein Form_Move Ereignis gibt es wirklich nicht. Und wenn man in die Titelleiste einer Form klickt, um diese zu bewegen, wird weder MouseDown, MouseUp noch sonst irgendetwas ausgelöst.

Das Speichern der Formposition und Größe würde ich an Deiner Stelle im Form_Unload-Ereignis machen. Das ist auch wesentlich besser, weil dieser Vorgang dann nur einmal ausgeführt wird, und nicht bei jeder Größenänderung. 

Viele Grüsse
ronaldh


----------



## DrMueller (22. November 2007)

Ah hat man mir auch empfohlen. Kann ich leider net machen, da das Form nur ein Modul zu einem Programm ist. Wenn also das Hauptprogramm geschlossen wird, löst sich der Event nicht aus und es wird gar nichts gespeichert.


----------



## ronaldh (22. November 2007)

Wieso? Ich habe in eine Form folgendes geschrieben:


```
Private Sub Form_Unload(Cancel As Integer)
   Call WriteFormSettings(Me)
End Sub
```

Und in ein Modul folgendes:


```
Public Sub WriteFormSettings(frm As Form)
   Debug.Print frm.Top, frm.Left, frm.Height, frm.Width
End Sub
```

Statt dem Debug.Print kannst Du natürlich auch in die Registry schreiben. Aber irgendwo musst Du das ja programmieren. Da ist es doch Banane, wie das Programm aufgebaut ist.

ronaldh


----------



## DrMueller (22. November 2007)

neinein mit Modul meinte ich, dass mein Teil nur an ein anderes Programm angehängt ist und mein Formular aufruft. Wenn ich jetzt das Hauptprogramm schliesse, werden die unteren Formulare, also auch meins, automatisch und ohne Unload geschlossen.


----------



## ronaldh (22. November 2007)

ok, verstehe. Wenn der Prozess einfach gekillt wird, wird leider tatsächlich das Form_Unload Ereignis auch nicht mehr ausgelöst.

In dem Fall hast Du nur folgende Möglichkeiten:

Entweder Du verzichtest darauf, die Position zu speichern, wenn nur verschoben wurde. 

Oder Du baust einen Timer ein, in dem Du regelmäßig die Position prüfst, und, falls sie sich geändert hat, speicherst. Zum Beispiel so:


```
Private Sub Timer1_Timer()
   Static Oben As Double
   Static Links As Double
   Static Hoehe As Double
   Static Breite As Double
   
   If Oben <> Me.Top Or Links <> Me.Left Or Hoehe <> Me.Height Or Breite <> Me.Width Then
      Oben = Me.Top
      Links = Me.Left
      Hoehe = Me.Height
      Breite = Me.Width
      Call WerteSpeichern
   End If
   
End Sub
```

Grüsse
ronaldh


----------



## DrMueller (22. November 2007)

hm danke erstmal, hätte echt gedacht, dass Forms verschieben noch etwas oft benutztes wäre, habe ich mich wohl geirrt.
Dumme Nebenfrage: Static habe ich noch gar nie gebraucht, was sind denn die Merkmale von diesem Typ?


----------



## ronaldh (22. November 2007)

Static bedeutet, dass die Werte nach Verlassen der Prozedur erhalten bleiben.

Würdest Du hier "Dim" verwenden, würde jedesmal die Speicherroutine aufgerufen werden, weil die Werte jedesmal auf 0 initialisiert werden.

Im übrigen wusste ich nicht, dass das Unload-Ereignis nicht aufgerufen wird, wenn man den Prozess von woanders abschießt. Habe ich ausprobiert, ist aber tatsächlich so. Ist auch eigentlich logisch, weil der Prozess davon ja überhaupt nichts mit bekommt. 

Viele Grüsse
ronaldh


----------



## DrMueller (22. November 2007)

Macht aber auch einige Probleme hier, da sich dann einiges gern mal aufhängt, wenns nicht sauber geschlossen wird. Ich empfehle lieber korrekt zu schliessen.
Hm Static hätte ich sooo oft brauchen können, hätte mir einiges an Arbeit und merkwürdige Gebilde erspart.


----------



## ronaldh (22. November 2007)

Ja logo, korrekt schliessen ist immer besser. Nur Du hast doch geschrieben, dass Dein Programm durch ein anderes geschlossen wird. Dann hast Du ja keinen Einfluss mehr darauf, dass es korrekt geschlossen wird.


----------

