markierung (auch über mehrere zeilen einrücken)



  • Da stellt sich mir die Frage, was ist ein "Profiproblem" bzw. was sind sogenannte Profis 😃 ?
    Wenn Dir AnsiString ein "Klotz am Bein" ist, dann wandle das Teil doch um und schaff mit Pointer, wo ist das Problem 🙄
    Immer flexibel und kreativ sein, dazu braucht es keinen Profi 😉



  • Na ganz so is es wohl nicht. Immerhin blieb der Thread ungelöst offen. Die Frage, wie man die Cursor im Fließtext eine Zeile tiefer setzt, findet keine Antwort. Also wohl doch schwerer Stoff? :p

    Ich muß zB. aufgeben. In was umwandeln? Worauf den Pointer? Und dann? Nee, da sind ja nur Unbekannte ohne Weg. Also vielleicht später irgendwann flexibel und kreativ sein. 😉



  • Was heisst "ungelöst offen"? Der Lösungsansatz ist da, und da sich der ursprüngliche Poster (unhöflicherweise) nicht mehr gemeldet hat ist die Sache für ihn wohl erfolgreich abgeschlossen.

    Und auch deine Zusatzfrage lässt sich aus den ursprünglichen Informationen und meinem Hinweis auf SelStart beantworten.



  • Danke, @Jansan. Im ersten Moment hatte mich deine Torpedoantwort verblüfft. Denn entweder ich komm nun drauf, oder ich bin zu dumm für den Job und soll sofort aufgeben. Tatsächlich sind alle benötigten Infos im Thread vorhanden. Die Übung ist frischlingsgeeignet - wenn man drauf kommt. 😉

    @Peter, auch dir noch mal Dank für "kreativ" und "flexibel". Beides sollte man sein im Showgeschäft. :p

    PS: Ich weiß noch nicht, wie ich die ersten 40 Kamele der Frühjahrsernte aufteilen werde. Wahrscheinlich werde ich sie einfach losschicken, sie sollen selbst entscheiden. 😉



  • Sorry @Jansen, hatte gehofft, mit dem neuen Thread die Übersichtlichkeit zu erhöhen. Eine Lösung ist vorhanden, natürlich kann da noch einiges verbessert werden.

    Im wesentlichen geht es nun um das Problem, daß nach der Implementierung des StringReplace-Codes die Zeilen nicht mehr in voller Länge genutzt werden.

    Beschreibung: In der Form liegt ein RichEdit (Txt), alClient, PlainText, WordWrap.
    Darüber (genau gleich groß) ein Dummy, RichEdit (Druide), alClient, PlainText, WordWrap, Visible=false.

    Ich markier einen beliebigen Textblock, der Code rückt jede Zeile ein.

    Den Dummy nutz ich, weil der Textblock während der Aktionen schwer/gar nicht zu erhalten war. Wär für bessere Tips und Ideen dankbar.

    Da der Cursor-Vorschub zum nächsten Zeilenanfang in der while-Schleife an "\r\n" hängen blieb, ersetze ich im Druiden alle "\r\n" gegen "\n". Nun klappt - soweit getestet - jede Situation.

    Problem: Die Zeilen im eingerückten Block werden kürzer. Also der Text füllt nun nicht mehr die vollen möglichen Zeilenlängen auf. Das ist auch so, wenn im Block kein "\r\n" vorhanden ist. - Ich kann mir den Grund nicht erklären. Bringt ggf. StringReplace da was durcheinander?

    Kann jemand den Fehler erkennen? Der Ausrufezeichen-Kommentar markiert die Stelle:

    void __fastcall TChild::TextBlockClick(TObject *Sender)
    {
        // Txt = RE, Druide = DummyRE
        // Textblock ist markiert
        int Start = Txt->SelStart, Ziel = Txt->SelLength;
        // vor dem Textblock ein '\n' ?
        if (Txt->Text.SubString(Start,1) == "\n")
        {
            // Zeile einrücken, Cursor an den Zeilenanfang
            Txt->SelText = "\t" + Txt->SelText;
            Txt->SelStart = Start;
            CarPYold = Txt->CaretPos.y;
            // Cursor eine Zeile tiefer
            // Blockende beibehalten
            while (Txt->CaretPos.y <= CarPYold)
            {
                Txt->SelStart++;
                Ziel--;
            }
            // '\t' kam dazu, also
            Ziel++;
        }
        // kein '\n' vor dem Textblock
        else if (Txt->Text.SubString(Start,1) != "\n")
        {      
            // "\n" + Zeile einrücken, Cursor an den Zeilenanfang
            Txt->SelText = "\n\t" + Txt->SelText;
            Txt->SelStart = Start;
            CarPYold = Txt->CaretPos.y+1; 
            // Cursor eine Zeile tiefer
            // Blockende beibehalten
            while (Txt->CaretPos.y <= CarPYold)
            {
                Txt->SelStart++;
                Ziel--;
            }  
            // "\n\t" kam dazu, also
            Ziel+=2;
        }
        // Restlichen Textblock an Dummy übergeben
        Txt->SelLength = Ziel;
        Druide->Clear();
        Druide->Text = Txt->SelText;
        // alle "\r\n" in "\n" umwandeln
        /* !!!! hilft, aber die Blockzeilen werden kürzer !!!! */
        AnsiString Alles(Druide->Text);
        Druide->Text=StringReplace(Alles,
        "\r\n", "\n", TReplaceFlags()<<rfReplaceAll);
        Txt->ClearSelection();
        // Bei minimal 2 Zeilen kannst du fehlerfrei arbeiten, also
        while (Druide->Lines->Count>1)
        {
            // bau mal ein ENTER + Einrückung
            Druide->SelStart = 0;
            Druide->SelectAll();
            Druide->SelText = "\n\t" + Druide->SelText;
            Druide->SelStart = 0;
            CarPYold = Druide->CaretPos.y+1;
            // Cursor an den Zeilenanfang eine Zeile tiefer
            while (Druide->CaretPos.y <= CarPYold)
            {
                Druide->SelStart++;
                Druide->Refresh();
            }
            CarPYold = Druide->CaretPos.y;
            // markier die erste Zeile und schick sie ans Haupt-RE
            Ziel = Druide->SelStart;
            Druide->SelStart = 0;
            Druide->SelLength = Ziel;
            Txt->SelText = Druide->SelText;
            Druide->ClearSelection();
        }
        // Nun noch die letzte Leile zum Haupt-RE schicken
        Txt->SelText = "\n\t" + Druide->Text;
    }
    

    Dank an @AndreasW für Tips, wie sich die Aufgabe ggf. kompakter lösen ließe. Aus seinem Vorschlag

    RichEdit1->Lines->Strings[0]=RichEdit1->Lines->Strings[0].Insert("\t",1);
    

    Hatte ich dann die "Prototyp"Zeile gebaut:

    Txt->Lines->Strings[Txt->Perform(EM_EXLINEFROMCHAR,0,Txt->SelStart)] =
                Txt->Lines->Strings[Txt->Perform(EM_EXLINEFROMCHAR,0,
                Txt->SelStart)].Insert("\t",1);
    

    Geht vielleicht noch besser.? Muß probieren.

    Aber wie gesagt, das oben angesprochene Hauptprob bleibt, die nur etwa zu 3/4 genutzte Zeilenlänge. Hier die Lösung zu finden, wär mir besonders wichtig.



  • Bei meinem ersten Beitrag hatte ich eigentlich an sowas gedacht (ungetestet):

    int sstart = RichEdit1->Perform(EM_EXLINEFROMCHAR, 0, RichEdit1->SelStart);
    int ssende = RichEdit1->Perform(EM_EXLINEFROMCHAR, 0, RichEdit1->SelStart + RichEdit1->SelLength);
    
    for (int i = sstart; i <= ssende; i++)
      RichEdit1->Lines->Strings[i].Insert("\t", 1);
    


  • *Hilfe*, ich will hier raus :p . @Jansen, einen so schönen Stein, wie er in deinen Garten paßt, gibt es wahrscheinlich gar nicht. 😉 Absolut top und elegant! Der Trost, ich hab bei der aufwändigen Übung etwas Stringmanipulation gelernt.

    Aber jetzt kommt das ganz gemeine Osterei 😞 : Auge sagte sofort "jaaaa", Debugger sagt auch "ja", alles stimmt (logo!). Und doch, im Text rührt sich rein gar nix. Mit Sleep(200) und Refresh() konnte ich aber wenigstens was zum wackeln bringen.

    Also Projekt geschlossen, alle .obj usw. raus, dann sogar PC-Neustart. Es nützt nichts, der Text wird kein bischen verändert - auch ohne die laufende IDE nicht. An was kann sowas liegen? (Kein Wunder, daß ich Stringmanipulation für schwierig halte).

    -Wer hat noch dieses Prob bzw. + den BCB3? Ole, meine Finger sind unegal. Aber soooo sehr? 😞



  • War, wie gesagt, ungetestet. Aber mit ein wenig Kombinationsgabe hättest du da auch selbst drauf kommen können, oder? 😉

    RichEdit1->Lines->Strings[i] = RichEdit1->Lines->Strings[i].Insert("\t", 1);
    


  • Hatte ich getestet, aber als Insert("\n\t", 1). Das schafft erst mal entsprechende Leerzeilen und setzt dann einmal den Tab, nützt also nix. Insert("\t", 1) geht aber, eben getestet.

    Da muß was gehen. So ein schöner Algor, das geb ich so schnell nicht auf. Erst die Abfrage auf "\n" vor dem Block, dann je bearbeitete Zeile die Restmarkierung wieder aktivieren und mit SelText arbeiten. So in etwa...



  • Ich kann dir nicht folgen. Inzwischen konnte ich es testen, das o.g. Beipiel (mit der korrigierten Zuweisung) funktioniert einwandfrei.

    Was hast du nur immer mit dem \n, das ist doch völlig irrelevant!?



  • Hmmm, hast du mal in eine der eingerückten Zeilen (oder ggf. auch in der davor) weiteren Text geschrieben? Der Text kann sich auch über mehrere Zeilen hinweg verschieben, die Tabs sind nicht mehr am Zeilenanfang.

    Ich will voneinander unabhängige Zeilen schaffen. Wenn dann eine Zeile länger wird und eine Folgezeile bildet, kann man die gezielt behandeln. Aber die geschaffene Gesamtstruktur bleibt erhalten. Darauf kommt es mir an.



  • "Und sie bewegt sich doch!" 😃 "\v" ist nicht "\n", kann aber zu "\n" werden. :p Mit dem Trick klappt das Separieren der Zeilen.

    // Alle Zeilen im markierten Block einrücken und voeinander trennen
    void __fastcall TChild::TextBlockClick(TObject *Sender)
    {
    
        // Txt ist ein RichEdit
        int Start = Txt->SelStart, Ende = Txt->SelLength, ssPlus = 0;
        int bkStart = Txt->Perform(EM_EXLINEFROMCHAR,0,Txt->SelStart);
        int bkEnde = Txt->Perform(EM_EXLINEFROMCHAR,0,Txt->SelStart+Txt->SelLength);
        for (int i = bkStart; i <= bkEnde; i++)
            // wenn der Block an einem Absatz begint
            if (i == bkStart && Txt->Text.SubString(Start,1) == "\n")
            {
                Txt->Lines->Strings[i] = Txt->Lines->Strings[i].Insert("\t",1);
                // Blocklängenkorrektur
                ssPlus += 1;
            }
            // sonst bzw. alle weiteren Zeilen
            else
            {
                Txt->Lines->Strings[i] = Txt->Lines->Strings[i].Insert("\r\v\t",1);
                // Blocklängenkorrektur
                ssPlus += 3;
            }
        // nochmal den Block markieren
        Txt->SelStart = Start;
        Txt->SelLength = (Ende + ssPlus);
        // die "\v" in "\n" umwandeln
        Txt->SelText=StringReplace(Txt->SelText,
                    "\v", "\n", TReplaceFlags()<<rfReplaceAll);
    }
    

    Letzter Schönheitsfehler: Läuft der Block über Absätze hinweg, entstehen zusätzliche Leerzeilen. Hat jemand 'ne Idee, wie sich das vermeiden läßt? Ich find die richtige Abfrage nicht. Txt->Lines->Strings[i].Trim(); hilft nicht.



  • Niemand 'ne Idee? Hätte es gern in der Schleife geregelt, aber am Schluß der Routine geht auch:

    // Leerzeilen entfernen 
        Txt->SelStart = Start;
        Txt->SelLength = (Ende + ssPlus);
        Txt->SelText=StringReplace(Txt->SelText,
                    "\n\r\n", "\n", TReplaceFlags()<<rfReplaceAll);
    

    Vorhanden gewesene Leerzeilen bleiben dabei erhalten - wie es sein soll.

    -Insgesamt stehen also die beiden Wege mit und ohne Absatzseparierung zur Verfügung... falls es jemand interessiert... (ziemlich verdatenbankt, die wüste Jejend hier 😃 ).


Anmelden zum Antworten