"Edit"-Window Kann man den Inhalt UPDATEN anstatt ihn zu überschreiben ?



  • Hey Leuts,

    arbeite gerade ein bisl an einem Chat-Programmm und bin nun an diesem Problem angelangt. Ich habe ein main-Fenster mit 2 Edit-Fenster. Eins zur Eingabe und eins zur Ausgabe. Nun, wenn ein Client was schickt soll das ein anderer Client auch bekommen und das Ganze soll in dem Output-edit video ausgegeben werden. Das Problem : es gibt soweit ich gesehen habe nur das Makro Eedit_SetText() was den gesamtem Text eines Edit-Fensters auf einem bestimmten ändert. Das ist aber für ein Chat schlecht. Dann müsste ich jedes mal den aktuellen Text zwischenspeicher, den buffer um den neuen Text erweitern und dann das Edit-Feld auf diesen neuen Text setzen. Aber das wird nicht lange gut gehen, wenn man länger chatet werden ja iwann vielzuviele Zeichen in dem Edit-Fenster sein.

    Weiss jemand eine Lösung ? Vllt was ganz anderes als ein Edit-Window verwenden ?

    Bei dem CreateDialog bin ich gescheitert, da ich keine Ahnung hatte was für welche Ressourcen-Datein man da angeben soll bzw. woher man die beziehen soll.





  • Danke erstmal dafür !

    Aber ich bin damit gerade überfordert.

    SendDlgItemMessage() nutzt man wohl, um eine Msg an die callback function dieser Listbox zu verwenden.
    Nur ...
    Sagen wir mal ich erstelle ein Child window mit CreateWindowEx() und halt "editbox" als 2. Parameter um eine EditBox zu erhalten ... welches ist dann die Callbackfunction die die messages, die man per SendDlgItemMessage() schickt, erhält ? Und wo man sie dann schliesslich auch bearbeitet ?





  • Sorry, aber ich habe keine Ahnung was ich mit dieser Liste von Konstanten soll 😮 Ist wohl eine Alternative zur angabe von "editbox" als 2. Parameter, hilft mir aber nicht bei meinem Problem.



  • Was du suchst ist:
    SetWindowText() und GetWindowText()

    Im Prinzip löst dieser Pseudocode dein Problem...

    string = GetwindowText() + der Text der hinten dran soll
    SetWindoText(string)
    

    Eventuell hilfreich sind tutorials...



  • Danke schonmal 😛

    Aber das kann doch nicht die Lösung sein ? Wenn da jemand chattet werden am Ende 500.000+ zeichen einfach immer wieder ein ein string gespeichert + wieder ausgegeben ? Das ist wohl alles andere als elegant ?

    Nochwas, bzgl. der String class : Wie benutzt man string-objekte mit Funktionen, die ein char* als argument erwarten ? Bin auch da auf keine Lösung gestossen.



  • Was ich vergessen hatte : ... funktionen, die ein char* argument erwarten, um darin zu SCHREIBEN.



  • char* ist prinzipiell ein String. Von welcher Sprache reden wir denn?



  • es ist auch nicht besonderst elegant eine bearbeitungsfeld als anzeigefeld für den chatverlauf zu verwenden.
    augenzudrücker gab dir schon den richtigen wink. der chatverlauf wir dir egal bei welchem chattool (zumindest die ich kenne) immer in einer listbox ausgegeben.



  • @ HighLiger

    Nunja, ergibt man einer Funktion, die char* als Argument erwartet, ein String-Objekt, dann wird man ein Fehler ausgespuckt bekommen.

    @ LowFly Okay, das wusste ich nicht. Aber ich komme nicht mit der ListBox klar 😕 Man benutzt wohl, wie oben erwähnt, eine spezielle Funktion um Messages an die Callback funktion einer ListBox zu schicken. Nur, wo lege ich fest, welche CallBack Funktion meine ListBox verwendet ? Muss ich das überhaupt ?



  • wenn ein steuerelement (listbox, button, editfeld...) nachrichten zu versenden haben, werden die an die hauptnachrichtenschleife des jeweiligen dialogfeldes gesendet. um das wie must du dich nicht kümmern. sondern nur darum wo du sie abfängst. und das ist im jeweiligen steuerelement MSDN beschrieben.

    es sei denn du subclass'd das ganze, dann können die steuerelemente einen teil der nachrichten selbst verarbeiten.



  • String ist ein Synonüm für eine Anreihung von Zeichen mit einer Nullterminierung. Dies können z.B. ein C-String auch char* sein (C/C++/CLI), ein std::string (C++), ein String (C#) oder ein System::String (C++/CLI). Wenn du also von String redest dann kann das alles mögliche sein, und alle sind verschieden.

    Ich vermute du arbeitest mit C++, also std::string.

    char* parameter = "Hallo Welt";
    std::string str(parameter); //char* to std::string
    
    /////////////////////////////////////////////////
    
    std::string str("Hallo Welt");
    str.c_str(); //std::string to char*
    


  • meinst du wie bei einer textdatei seektoend?
    meines wissens nach nicht.

    ABER mit einer Listbox geht das.
    warum glaubst du das dich augenzudrücker darauf verwiesen hat 🙄


  • Mod

    WinApi-Noob schrieb:

    Aber das kann doch nicht die Lösung sein ? Wenn da jemand chattet werden am Ende 500.000+ zeichen einfach immer wieder ein ein string gespeichert + wieder ausgegeben ? Das ist wohl alles andere als elegant ?

    Ich würde auch ncith dazu raten SetWindowText zu verwenden. Weitaus schneller und effektiver ist eine Kombination aus EM_SETSEL und EM_REPLACESEL
    http://msdn.microsoft.com/en-us/library/bb761633(v=vs.85).aspx



  • Oh so viele Antworten 🙂

    Sorry, dass ich nicht mehr reingeschaut habe, hatte leider Internetprobleme.

    So...

    @LowFly : D.h wenn ich ein Fenster A habe und ein Child-Window B von Fenster A, dann werden alle messages, die an Fenster B geschickt wurden, auch an Fenster A's Callbackfunction "weitergeleitet" ?

    So und eine Frage : Ich habe Probleme mit dieser Funktion : SendDlgItemMessage(). Eig. sind alle Parameter logisch, nur mit der ID komm ich nicht klar. Welche ID ? Kann man da einfach 0 eingeben für die erste "Zeile" ( oder wie auch immer eine List-Box aufgebaut ist ), dann 1 für die 2. etc ? Oder woher soll man diese ID beziehen ?
    Meine diesen Parameter :

    int nIDDlgItem [in]

    The identifier of the control that receives the message.

    @HighLigerBiMBam
    Ja ich sprach von der C++ String Klasse 😛 Deswegen meinte ich ja auch immer "ein String-OBJEKT", hätte vllt einfach kurz ein Bsp. schreiben sollen.
    Die Beispiele die du gepostest hast waren mir klar, nur wie macht man nun folgendes :
    Nehmen wir mal die recv Funktion aus der WinSock library. Die will als 2. Parameter ein char* um darin zu schreiben. Nun StringObject.c_str() wird nicht funktionieren, da es ja ein konstanten Wert zurück gibt. Muss man da ein Umweg über einen C-String nehmen, nehm ich mal an ?

    @ Martin Richter :o die beiden Messages hatte ich garnicht gefunden. Kommt dem was ich will schon sehr nahe 😛 Nur wie soll ich Anfangs und End-Char angeben ? Dazu müsste ich ja wieder den gesammtem Text in einem C-Array speichern und dann wohl sowohl als start und ende das letzte Element angeben ( da ich ja am Ende der Box einfügen will ). Wie ich gesehen habe gibt es mit 0 und -1 eine möglichkeit den gesammten Text auszuwählen, aber anscheinend keine um keinen Text auszuwählen und einfach hinten einzufügen.


  • Mod

    Du musst gar nichts speichern... es gibt doch GetWindowTextLength. Damit die aktuelle Länge bestimmen. EM_SETSEL und danach EM_REPLACESEL.
    Fertig.



  • Wenn du in einem Fenster ein Control erstellst, werden keine Nachrichten des Controls weitergeleitet, sondern es werden vom Control Nachrichten an das Elternfenster geschickt.
    Typischerweise werden WM_COMMAND- und WM_NOTIFY-Nachrichten in der Dialog-Proc abgefangen.
    Bei WM_COMMAND:
    LOWORD(WPARAM) : die ID des Controls
    HIWORD(LPARAM) : Nachricht, bei Listboxes bspw. LBN_SELCHANGE, wenn der Benutzer einen Eintrag ausgewählt hat
    Bei WM_NOTIFY:
    WPARAM : die ID des Controls
    LPARAM : Immer ein Zeiger auf eine NMHDR-Struktur, abhängig vom Control kann diese Struktur aber weitaus größer sein (der erste Member der Struktur ist dann aber immer ein NMHDR).

    Die ID des Controls vergibt man normalerweise bei CreateWindow als HMENU-Parameter oder im Resourceneditor (nicht bei MSVS-Express) direkt beim Einfügen eines Elements.

    Zur Frage mit dem String: c_str() gibt immer einen konstanten Zeiger auf sein erstes Element zurück, er kann deshalb in dem Fall nicht verwendet werden.
    Stattdessen kann man einen std::vector verwenden:

    void f(TCHAR* p); // Funktionsdeklaration
    ...
    std::vector<TCHAR> v(1000); // 1000 TCHARS im vector anlegen
    f(&v[0]); // f aufrufen, &v[0] zeigt auf das erste Element im vector
    

    Im neuen C++-Standard ist garantiert, dass der Speicherbereich des std::strings wie beim std::vector nicht in Teilbereiche gesplittet ist, man kann dann obiges auch mit einem string durchführen.

    Du brauchst den Text für das Editfenster nicht separat speichern:

    void AddToEditCtrl(HWND EditWnd, const TCHAR * Text)
    {
    	SendMessage (EditWnd, EM_SETSEL, -1, -1);
    	SendMessage (EditWnd, EM_REPLACESEL, FALSE, reinterpret_cast<LPARAM>(Text));
    	SendMessage (EditWnd, EM_SCROLLCARET, 0, 0);
    }
    void AddToEditCtrl(HWND EditWnd, const std::basic_string<TCHAR>& s) // Überladung für strings
    {
        AddToEditCtrl(EditWnd, s.c_str());
    }
    

    Noch besser (aber mit mehr Aufwand verbunden) scheint mir die Lösung mit einer Listbox. Da die Texte aber eine unterschiedliche Länge haben können und daher ohne horizontale Scrollbar mehrere Zeilen einnehmen können, müsstest du die Textausgabe selber übernehmen (Stil LBS_OWNERDRAWVARIABLE bei der Listbox angeben) und WM_MEASUREITEM und WM_DRAWITEM-Nachrichten behandeln.


  • Mod

    SendMessage (EditWnd, EM_SETSEL, -1, -1);
    

    Ist IMHO falsch. Nach der Doku, wird dadurch nur die aktuelle Selektion aufgehoben und nicht das Caret an das Ende des Textes gesetzt.



  • Dies ist eine gekürzte Version aus dem Petzold:

    void EditPrintf (HWND hwndEdit, TCHAR* szFormat, ...)
    {
         TCHAR   szBuffer [1024] ;
         va_list pArgList ;
    
         va_start (pArgList, szFormat) ;
         wvsprintf (szBuffer, szFormat, pArgList) ;
         va_end (pArgList) ;
    
         SendMessage (hwndEdit, EM_SETSEL, (WPARAM) -1, (LPARAM) -1) ;
         SendMessage (hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) szBuffer) ;
         SendMessage (hwndEdit, EM_SCROLLCARET, 0, 0) ;
    }
    

    Ich nutze das Windows-Editfeld eher selten, ein kurzer Test vor dem Posten brachte aber das gewünschte Ergebnis.

    In einer älteren Version der MSDN (ausgeliefert mit VC 6) ist Folgendes zu finden:

    MSDN schrieb:

    If the nStart parameter is 0 and the nEnd parameter is –1, all the text in the edit control is selected. If nStart is –1, any current selection is removed. The caret is placed at the end of the selection indicated by the greater of the two values nEnd and nStart.

    Der letzte Satz wurde aber irgendwann entfernt.
    Ich werde es morgen noch einmal testen.


Log in to reply