Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - Multiple Fenster nutzen....Geht das?


fbkreon - Do 14.11.02 18:47
Titel: Multiple Fenster nutzen....Geht das?
Hallo,

ich bastle gerade an ner Chat-Variante mit nem Chatfenster für jeden User. So a là na Ihr wißt schon.

Wie kann ich denn nun bei verschiedenen Chatfenstern feststellen, zu welchem die Empfangsdaten sollen?? Ich sitze da irgendwie fest.

Vielleicht hat da jemand ne zündende Idee? :idea:

Irgendwie muß ich dem Hauptprogramm klarmachen können, wenn Message für User X, dann packe es auch in Fenster X.....

Vielen Dank schon mal für Eure Hilfe. :smile:


tommie-lie - Do 14.11.02 19:38

wie wär'S mit 'nem Array? Er speichert die User-ID in der einen "Spalte" und die Fenster-ID in der anderen. Wenn ein neues Fenster geöffnet wird, wird das array um eins erweitert (richtig, dynamisches Array) und die entsprechenden IDs eingefügt.
Dann muss man nur noch nach der User-ID suchen und findet daraufhin eine Spalte weiter die Fenster-ID und schon hat man das Fenster, auf das man zugreifen will.

P.S.: ID ist durch alle entsprechenden Äquivalente, also Labels, Captions, Handles, ..., zu ersetzen!


fbkreon - Do 14.11.02 21:28

Das klingt sehr machbar, nur ein Problem hätt' ich da noch....
Wie vergebe ich denn an ein Fenster in Delphi ne ID???


Delete - Do 14.11.02 21:49

Hat tommie-lee doch gesagt:
Zitat:
ID ist durch alle entsprechenden Äquivalente, ..., Handles, ..., zu ersetzen!

Du brauchst gar nichts vergeben. Jedes Fenster besitzt ein Handle, und dies ist in den meisten Fällen sogar einzigartig.


fbkreon - Do 14.11.02 22:43

also wie ich von einem Fenster das Handle herausbekomme, das weiß ich, aber wie rufe ich dann das jeweilige Objekt dann aufrufen?

Wenn ich jetzt beispielsweise zwei Fenster habe:

Form1 und Form1
11111 111112 als Handles

Wie rufe ich dann z.B. einen Button in 1111112 auf?

Denn bisher habe ich nur den Befehl
Showwindow(); gefunden....


Tino - Fr 15.11.02 10:56

Du könntest Dem Array statt dem Handel doch direkt einen Verweis auf das tForm-Objekt angeben. Dadurch kannst Du es direkt ansprechen!

Gruß
TINO


fbkreon - Fr 15.11.02 18:00

Zitat:
Du könntest Dem Array statt dem Handel doch direkt einen Verweis auf das tForm-Objekt angeben. Dadurch kannst Du es direkt ansprechen!


:smile: Sagen wir mal, die TForm heißt TMsgRecv,
und ich habe 5 Forms mit Namen MsgRecv offen, dann ist das ein Problem, oder????

Oder kann ich sagen,

Quelltext
1:
2:
123123:= TMsgRecv.Create(self); 123123.show;
124124:= TMsgRecv.Create(self); 124124.show;

und habe dann zwei Fenster?[/quote]


CenBells - Fr 15.11.02 20:03

genau so sieht es aus.

Dann hast du zwei fenster


fbkreon - Sa 16.11.02 19:13

also ich habe den Tipp mal ausprobiert mit dem direkt öffnen:

Zitat:
123123:= TMsgRecv.Create(self); 123123.show;
124124:= TMsgRecv.Create(self); 124124.show;


Also bei mir sagt Delphi, daß das nicht ginge......

123123 sei nicht definiert.....ist ja auch klar. wird ja erst auf knopfdruck erfunden.

Seid ihr sicher, daß das so geht??


Tino - So 17.11.02 18:09

fbkreon hat folgendes geschrieben:
Sagen wir mal, die TForm heißt TMsgRecv

Gut. Dann musst Du halt ein Array habe welches nicht ein tForm- sonder tMsgRecv-Element erwartet.

fbkreon hat folgendes geschrieben:
ich habe 5 Forms mit Namen MsgRecv offen, dann ist das ein Problem, oder????

Vergiss die Eingeschaft Name von Deinem Forms. Die brachst Du nicht!

Wenn Du nun ein neues Fenster öffnen willst dann musst Du erstmal das (dynamisches) Array um ein weiteres Element erweitern.

Quelltext
1:
SetLength (FensterListe, Length (FensterListe) +1);                    

Dann kannst Du Dein neues Fenster erstellen:

Quelltext
1:
2:
3:
4:
Var
  NewWindow: tMsgRecv;
Begin
  NewWindow := tMsgRecv.Create (Self);

Anschließend "fügst" Du das neue Fenster in die Liste ein:

Quelltext
1:
FensterListe [Length (FensterListe)] := NewWindow;                    

Ich hoffe das hat Dir ein wenig geholfen!

Gruß
TINO


fbkreon - So 17.11.02 21:52

Vielen Dank Tino für den Tipp,

Und in dem Array rufe ich dann das jew. Fenster über den Index auf und Unterobjekte dan in Abhängigkeit davon, ja?

Ich habe inzwischen noch ne Variante mit Handles und CommonControls bzw. WindowControls gefunden, die ist auch ganz interessant....


fbkreon - So 17.11.02 22:48

Also das mit dem dynamischen Array funktioniert ganz gut.....*grins*...jedenfalls bis zu dem Augenblick, wo ich das Fenster schließe und ein neues öffnen will oder das Programm beenden will da bekomme ich dann ne dicke Fehlermeldung: Adressenverletzung!!


Tino - So 17.11.02 23:03

fbkreon hat folgendes geschrieben:
jedenfalls bis zu dem Augenblick, wo ich das Fenster schließe

Hast Du auch den entsprechende Eintrag aus dem Array entfernt?


fbkreon - Mo 18.11.02 20:33

Ja, dachte ich eigentlich, ungefähr so....


Quelltext
1:
procedure DelWindowArray(Index: Integer);                    

Zitat:
X entspricht FensterListe.....


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
begin
 if Index > High(X) then Exit; 
  if Index < Low(X) then Exit; 
  if Index = High(X) then 
  begin 
    SetLength(X, Length(X) - 1); 
    Exit; 
  end; 
  Finalize(X[Index]); 
  System.Move(X[Index +1], X[Index], 
  (Length(X) - Index -1) * SizeOf(string) + 1); 
  SetLength(X, Length(X) - 1); 
end;

aber irgendwie funzt es trotzdem nicht....


Tino - Di 19.11.02 11:07

Hallo,

ich schreib jetzt einfach mal wie ich das machen würde!

Als erstes definiere ich das Record welches dann in dem Array gespeichert wird. Dieses Record beinhaltet dann zwei Variablen: 1. den Usernamen und 2. das entsprechende Form.

Quelltext
1:
2:
3:
4:
5:
6:
Type
  pChatSession = ^tChatSession;
  tChatSession = Record
      User: String;
      Form: tMsgRecv;
    End;

Die Definition von dem Array musste wie folgt sein:

Quelltext
1:
fChatSessions: Array of pChatSession;                    

Wenn jetzt eine Nachricht von einem User ankommt rufst Du folgende Funktion auf die als Ergebnis das ensprechende Fenster liefert. Die Funktion arbeitet so das sie zu erst die schon geöffneten Chat-Session durchläuft und prüft ob schon eine Chat-Session mit dem User existiert. Ist das der Fall wird das schon vorhandene Fenster zurück gegeben ansonsten wird ein neues Fenster erstellt:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
Function GetChatForm (aUsername: String): tMsgRecv;
Var
  NewForm: tMsgRecv;
  NewSession: pChatSession;

  Idx: Integer;
Begin
  Result := nil;

  // Prüfen ob schon eine Chat-Session mit dem User gibt.
  For Idx := Low (fChatSessions) To High (fChatSessions) Do
    If fChatSessions [Idx]^.User = aUsername Then
      Begin
        Result := fChatSessions [Idx]^.Form;
        Exit;
      End;

  // Eine Chat-Session mit dem User existiert noch nicht
  // Neues Fenster erstellen
  NewForm := tMsgRecv.Create (Self);

  // Neue ChatSession erstellen
  New (NewSession);

  NewSession^.User := aUsername
  NewSession^.Form := NewForm;

  // Das Array erweitern
  SetLength (fChatSessions, Length (fChatSessions) +1);

  // Dem Array das NewSession Record zuweisen
  fChatSessions [Length (fChatSessions)] := NewSession;

  Result := NewForm;
End;

Wenn nun der Anwender eine Chat-Session schließt (also das Form schließt) musst Du noch die Einträge in dem Array entfernen:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
Procedure DeleteSession (aForm: tMsgRecv);
Var
  Idx, Idx2: Integer;
  ChatSession: pChatSession;
Begin
  For Idx := Low (fChatSessions) To High (fChatSessions) Do
    If fChatSessions [Idx].Form = aForm Then
      Begin
        // Chat-Session Record aus dem Speicher entfernen
        Dispose (fChatSessions [Idx]);
  
        // Die anderen nachfolgenden Chat-Session nach oben verschieben
        For Idx2 := Idx +1 To High (fChatSessions) Do
          fChatSessions [Idx2 -1] := fChatSessions [Idx2];

        // Das Array um ein Element verkleinern
        SetLength (fChatSessions, Length (fChatSessions) -1);

        Break;
      End;
End;


Ich hoffe das ist verständlich. Die Code-Beispiele habe ich nicht gestestet und sollen auch nur als Beispiel dienen. Es ist also sinnvoll das Du diese noch mal selbst Zeile für Zeile durchgehst und prüfst ob alles ok ist und eventl. Änderungen / Erweiterungen vornimmst!

Gruß
TINO


fbkreon - Di 19.11.02 23:18

also ich lösche dann das Fenster wie folgt.


Quelltext
1:
2:
3:
4:
procedure TMsgRecv.FormClose(......);
begin
   DeleteSession(self); 
end;


oder?

Wenn ja, ich bekomme immer noch nen dicken Adressfehler....

Zusätzlich habe ich die function und procedure sowie den array in den "public" part geschrieben. Das muß man ja, wenn man von anderen Units darauf zugreifen will. Oder? Ist es eigentlich egal, weil das nicht die Hauptunit des Programms ist, wo ich die hinschreibe, solange alle darauf zugreifen können über die uses-Liste?

Ich schließe das Fenster mit Action:=caFree;


Tino - Mi 20.11.02 10:12

Einen kleinen Fehler habe ich in der Funktion GetChatForm gemacht. Folgende Zeile musst Du ändern:

Quelltext
1:
2:
 // Dem Array das NewSession Record zuweisen 
 fChatSessions [Length (fChatSessions)-1] := NewSession;

Habe die Funktionen jetzt selbst getestet und es läuft!

Gruß
TINO


fbkreon - Mi 20.11.02 12:52

Es funktioniert nun wunderbar!! Vielen, vielen Dank für Deine Mühe. Ich hoffe, ich kann mich mal revangieren. Ich bin eigentlich im Bereich Grafik, Audio, HTML und PHP zu Haus.