Formular zur laufzeit erstellen mit vielen fragen
-
hey du...
ich schreibe gerade an einem msn messenger clone.
das klappt soweit auch gut, jedoch habe ich mit dem erstellen einer form zur laufzeit so meine probleme. viele aspekte sind ja zu beachten. ich versuche meine probleme so gut wie möglich in kategorien zu unterteilen und beschreiben.
let's rock.....Das erstellen einer Form zur laufzeit.
Da fangen meine probleme eigentlich schon an, da ich noch nie sowas von gebrauch machte. ich fange das ganze wie folgt an:TForm *Msg = new TForm(this); Msg->Caption = "Unterhaltung mit " + Online->Items->Strings[Online->ItemIndex]; Msg->Height = 400; Msg->Width = 400; Msg->Show();
wäre das soweit richtig? so als basis?
Jedenfalls wird bei klicken in der listbox, ein formular erstellt mit den gesetzten eigenschaften. ich bitte euch in diesem kapitel um hilfeDas einmalige erstellen wenn bereits erstellt wurde.
Jetzt stellt sich mir die frage, wie erstelle ich pro user jeweils nur ein fenster? wenn ihr einen messenger habt (MSN, icq, etc.) dann wisst ihr ja das diese jeweils pro benutzer nur einmal erstellt werden, also wenn das fenster bereits offen ist. wie regle ich sowas?Die events
Gang speziell hier kratz ich mir am kopf.
Wie greiffe ich an die events des erstellten formular zu?
zur design zeit wäre das ja pipsi einfach über den objektinspektor.
stellt euch vor, ich habe an den zur laufzeit erstellten formularen ja z.B. ein memo, ein edit und einen button. ich muss ja dann z.B. beim button auf OnClick zugreifen, damit ich auch an den user eine message schicken kann
ausserdem müsste ich hier auch das schlüsselwort delete mal einsetzen, damits keine schmutzverletzung gibt.Weitere fragen
Fallen mir sicher noch ein...
-
Hallo
wäre das soweit richtig? so als basis?
Ja, genau so ist richtig. Natürlich sollte dann statt TForm eine von dir erstellte, von TForm abgeleitete Klasse aufgerufen werden, damit du bereits alle Steuerelemente integriert hast.
Erstell also in deinem Projekt ein Formular, das du so aufbaust, wie du es dir als Chat-Fenster vorstellst. Das nennst du dan z.B. TChatForm. Dann includest du die Header des Forms in deinem Hauptprogramm, wo du die Chatfenster erstellen willst. Dann ist der AufrufTCharForm *Msg = new TChatForm(this); Msg->Caption = "Unterhaltung mit " + Online->Items->Strings[Online->ItemIndex]; Msg->Height = 400; Msg->Width = 400; Msg->Show();
Natprlich sollte man nicht vergessen, jede dynamische Fenster-Instanz wieder per delete zu löschen.
Jetzt stellt sich mir die frage, wie erstelle ich pro user jeweils nur ein fenster? wenn ihr einen messenger habt (MSN, icq, etc.) dann wisst ihr ja das diese jeweils pro benutzer nur einmal erstellt werden, also wenn das fenster bereits offen ist. wie regle ich sowas?
Du hast ja sicher für jeden User ein Objekt/Struct, wo du Daten über den User speicherst (zB. Name oder IP-Adresse). Die erweiterst du einfach um eine Referenz auf ein TChatForm. Standardwert ist NULL. Wenn du für diesen User einen Chatfenster erstellt, speicherst du die Referenz der Instanz dadrin:
// Datenstruktur-Klasse eines Users class TUser { ... private : TChatForm *iChatForm; // Referenz des Chatfensters zu diesem User public : __property TChatForm *ChatForm = {read = iChatForm}; // Property auf ChatForm, um es von außen lesen zu können TUser() {... ChatForm = NULL}; // Konstruktor : Referenz auf NULL setzen int OpenWindow(); // Memberfunktion zum Öffnen des Fensters int CloseWindow(); // ... zum Schließen des Fensters } int TUser::OpenWindow() { if (iChatForm != NULL) return(-1); // Wenn Fenster vorhanden, abbrechen iChatForm = new TChatForm(NULL); // Für diesen User ein Chatfenster erstellen iChatForm->Tag = (int) this; // Adresse der Userdaten in Form speichern, um Usaerdaten vom Form aus zu finden ... // Weitere Werte des Fensters setzen } int TUser::CloseWindow() { iChatForm.Close(); // Fenster schließen delete iChatForm; // Fenster löschen iChatForm = NULL; // Referemz zurücksetzen } ... // Dann kannst du für einen User ein Fenster öffnen und schließen TUser *User; ... User->OpenWindow(); User->CloseWindow();
Gang speziell hier kratz ich mir am kopf.
Wie greiffe ich an die events des erstellten formular zu?Zuerst einmal kannst du durch dein bereits vorgefertigtes ChatForm bereits viele Events innerhalb des Forms bereits zur Entwurfszeit erstellen.
Zur Laufzeit machst du das so:// irgendwo im Hauptformular eine Eventfunktion vom Typ TNotifyEvent, // die das schließen eines ChatForms regelt void __fastcall TMainForm::OnChatFormClose(TObject *Sender) { TButton *CloseButton = dynamic_cast<TButton *> (Sender); // Sender als TButton TChatForm *ChatFormToClose; // Das Fenster, dessen Close-Button den Event ausgelöst hat TUser *User; // Der user, dessen CHatfenster geschlossen werden soll if (CloseButton == NULL) return; // Wenn kein Button, abbrechen ChatFormToClose = dynamic_cast<TChatForm *> (CloseButton->Owner); // Chatfenster von Button bestimmen if (ChatFormToClose == NULL) return; // Wenn kein Chatfenster, abbrechen User = (TUser *) ChatFormToClose->Tag; // User aus Tag bestimmen User->CloseWindow(); // User-Objekt schließt das Fenster } // dann mußt du jedem neu erschaffenen ChatForm nur den Event setzen TUser *UserToChat; ... UserToChat->OpenWindow; UserToChat->ChatForm->ButtonCloseClick = OnChatFormClose;
ich hoffe du kannst das nachvollziehen. ansonsten schreib.
bis bald
akari
-
Hallo
wen ich's mir von mal überlege, gehört die Eventfunktion OnChatFormClose (und jede andere Userspezifische Eventfunktion) natürlich nicht zum TMainForm, sondern lieber direkt zu TUser. Dann kann man sich es sparen, den User zu bestimmen.
Und in TUser->CloseWindow() sollte man zuerst über prüfen, ob ein ChatForm vorhanden ist.
Und natürlich Rückgabewerte...bis bald
akari
-
hey vielen dank für deine ausführliche hilfe!
da hast du mich doch gleich auf eine gute lösung gebracht. ich habe nähmlich wie du geschrieben hast ein formular erstellt, memo, edit, button drauf getan und dann im messenger projekt abgespeichert.nun habe ich dort ja drei dateien. die *.cpp, *.dfm (oder so:)), *.h
das macht das ganze nähmlich nun leicht für mich da ich alle benötigten kompenenten ebreits auf dem formular habe und sie nicht extra mit dem new operator anfordern muss. lediglich die form erstelle ich zur laufzeit neu.
also eben, habe nun diese drei dateien und in meinem messenger projekt inkludiert "chatwindow.h". dann im messenger code:TChat *ChatWindow = new TChat(this); ChatWindow->Show();
und fertig
ist das ganze gut und ok so wie ich das nun mache?
das erspaart mir einiges. auch muss ich die events nicht extra schreiben. ich kann nun ja einfach das formular entsprechend bearbeiten (events etc.) und dann wieder abspeichern.
-
Hallo
ist das ganze gut und ok so wie ich das nun mache?
naja, funktioniert es denn? Mein Ansatz finde ich natürlich gut
bis bald
akari
-
yepp es funktioniert
aber das mit dem nur einmal pro user erstellen leuchtet mir noch nciht ganz ein.verstehst du wie ich das meinte?
es gibt zwei möglichkeiten wie man das fenster neu erstellt:1. der benutzer macht es selber, indem er auf einen namen in der listbox doppelt klickt.
2. der benutzer kriegt eine nachricht geschickt, es popt sich also ein neues fenster auf.diese zwei möglichkeiten gibt es.
jetzt muss ich natürlich verhinern das mehrere fenster erstellt werden, wenn bereits eins des betroffenen user erstellt wurde.
-
Hallo
aber das mit dem nur einmal pro user erstellen leuchtet mir noch nciht ganz ein.
verstehst du wie ich das meinte?
es gibt zwei möglichkeiten wie man das fenster neu erstellt:Du verwechselst den User an sich und die Daten, die ein Client über einen User sammelt.
Der Client braucht über jeden User, mit dem er in Kontakt steht, Daten wie Name und IP-Adresse.
Dazu habe ich eine Klasse TUser (ab sofort TUserData) angedacht. Als Member bekommt die zB.AnsiString iName; AnsiString iIP; // und eben TChatForm *iChatForm; // und oben beschriebene Zugriffsfunktion
dann erstellst du ein Array oder besser noch ein std::vector über TUserData, um alle erreichbaren User zu erfassen. Dann Kannst du zu jedem User über die zugehörigen TUserDaten aus dem Array ein eigenes Fenster öffen :
include <vector> using namespace std; ... vector<TUserData> UserList; TUserData *UserData; int Pos = 1; ... UserData = *(UserList.at(Pos)); // Zugriff auf zweiten User, wenn vorhanden UserData->OpenWindow();
alle Klarheiten beseitigt?
-
danke für deine hilfe aber ich krieg das nicht hin..
habe keine ahnung von vector, und so kann dein beispiel nicht nachvollziehen
-
Hallo
danke für deine hilfe aber ich krieg das nicht hin..
habe keine ahnung von vector, und so kann dein beispiel nicht nachvollziehenVielleicht hilfts es ja ein bißchen, wenn du statt vector erstmal DynamicArray nimmst.
class TMainForm : public TForm { ... DynamicArray<TUserData> UserList; // Liste aller User, die von diesem Client aus zu erreichen sind int AddUser(AnsiString Name, AnsiString IDAddress); // Beispielfunktion zum Hinzufügen eines neuen Users int OpenChatWindow(int UserNumber); // Bepsielfunktion zum Öffnen eines CHatfensters zu einem bestimmten Users } ... int TMainForm::AddUser(AnsiString UserName, AnsiString UserIDAdress) { int Pos = -1; // Position der Userdaten UserList.Length++; // neuen Eintrag in der Liste machen Pos = UserList.Length -1; // Position bestimmen UserList[Pos] = TUserData(); // Eintrag initialisieren UserList[Pos].Name = UserName; // Namen zuweisen UserList[Pos].IPAdress = UserIPAddress; // Adresse zuweisen ... return(Pos); } int TMainForm::OpenChatWindow(unsinged int UserNumber) { // UserNumber überprüfen, ob in Bereich des Arrays if (UserNumber >= UserList.Length) { ShowMessage("User List - Out of Range"); return; } // Wenn Fenster für diesen User noch nicht vorhanden, Fenster öffen if (UserList[UserNumber].ChatForm == NULL) UserList[UserNumber].OpenWindow(); // Wenn Fenster für diesen User vorhanden, diesen in Vordergrund holen else UserList[UserNumber].ChatForm->SetFocus(); return(0); }
Noch weiter vereinfachen kann ich es nicht. Wenn du damit nicht klar kommst, solltest du dich erst mal an einfacheren Sachen probieren (Ist nicht böse oder überheblich, sondern ernst gemeint)
bis bald
akari