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



  • 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.



  • Ahaa, erst mal danke für die ganzen ANtworten wieder 🙂

    Wie ich sehe ist das mit dem Edit-Control also durchaus möglich, jedoch tendiere ich dann doch eher zur Listbox. Schließlich scheint das die gängige und auch saubere Methode zu sein und wird von euch auch empfohlen.

    So, nun habe ich mein Listbox-Control so erstellt :

    hOutput = CreateWindowEx( WS_EX_CLIENTEDGE  | LBS_OWNERDRAWVARIABLE | LBS_NOTIFY, 
    "listbox", 
    "",
    WS_CHILD | WS_VSCROLL, 
    10, 
    90, 
    510, 
    280,
    hwnd, 
    NULL, 
    hThisInstance, 
    NULL);
    ShowWindow(hOutput, nFunsterStil);
    

    Guut, hwnd ist dabei mein Handle für das Main-Window. In deren WndProc habe ich dann folgendes gemacht, erstmal nur aus Debugging gründen :

    switch (message)                  /* handle the messages */
        {   
            case WM_COMMAND : 
    
            // ... Paar Sachen hier
    
            else if ( HIWORD(lParam) == WM_MEASUREITEM ) {
                 MessageBox(NULL,"Succ","Got the WM_MEASUREITEM message", MB_OK);
                 }
    

    Leider erscheint diese Message-Box zu Beginn des Programmes nicht, was sie ja eigentlich sollte ? Laut MSDN wird sie beim Erzeugen einer Listbox/etc. gesendet.
    Wozu ist es eigentlich nötig, dass ich sie abfrage ? Habe da nichts von wegen Text-formatierung o.ä gelesen ? Auch nicht bei WM_DRAWITEM 😞



  • WM_MEASUREITEM ist ja auch kein lParam-Wert, der einer anderen Nachricht angehängt wird, sondern eine vollwertige Window-Nachricht, d.h. du kannst ihn auf der selben Ebene verarbeiten wie WM_COMMAND:

    switch (message)                  /* handle the messages */
    {   
        case WM_COMMAND : 
            // ... Paar Sachen hier
            break;
        case WM_MEASUREITEM :
            MessageBox(NULL,"Succ","Got the WM_MEASUREITEM message", MB_OK);
            break;
    
        // ... weitere Nachrichten
    }
    


  • Achso, gilt das für alle Nachrichten mit WM_ als präfix ?

    Funktioniert aber leider trotzdem nicht 😕 Irgendwas mache ich falsch



  • WinApi-Noob schrieb:

    Achso, gilt das für alle Nachrichten mit WM_ als präfix ?

    Soweit ich weiß ja - und für deine selbstdefinierten Nachrichten (WM_USER+x)

    Funktioniert aber leider trotzdem nicht 😕 Irgendwas mache ich falsch

    Was sagt denn dein Debugger, wenn du dort einen Breakpoint reinsetzt?


  • Mod

    Warum machst Du es überhaupt Ownerdraw? Dan musst Du auch alles selber Zeichnen.

    Was willst Du nun? Das das Listcontrol für Dich die Anzeige regelt oder machst Du es selber?

    BTW: Die Suche nach Onerdraw Listbox liefert einiges an Samplecode.



  • Hmm, benutze ATM Dev C++ und da scheint debugging gerade nicht zulaufen. Müsste den Code eben umschreiben, damit er unter MVSC++ compiled ( der macht die konstanten Strings als Parameter gar nicht .... ).

    @ Martin Richter
    Nunja, das habe ich auf Vorschlag von einem der Member hier gemacht ( _Falke ) weil die Strings ja unterschiedlich lang sind. Das Hautpproblem ist ja wohl, dass es keine Zeilenumbrüche gibt -> Alles wird in eine Zeile geklatscht und den Rest kann man nicht mehr lesen.


  • Mod

    Dann wirst Du um Ownerdraw-Variable nicht drum herum kommen.


Anmelden zum Antworten