markierung (auch über mehrere zeilen einrücken)



  • Das ist ein Profiproblem, würde ich mal sagen.

    Und zwar mache ich das mit dem Text einrücken über den Trick:
    RichEdit->SelText = "\t";

    Da wird im Grunde der Text nach der aktuellen Cursorposition um einen Tabulator nach rechts verschoben, also genau das was "Text Einrücken" machen soll. Jetzt hat mich aber ein Nutzer darauf hingewiesen, dass bei einer Markierung und dem Klicken auf "Text einrücken" der gelöscht wird.

    Logisch, denn der wird ja nun von einem tab ersetzt.

    Ich möchte aber, dass der komplette Text dann ganz am Anfang der Zeile um jeweils einen Tab nach rechts verschoben wird. Wie kriege ich das hin? (Ich denke, dass folgende zwei Dinge nötig sind: Erst mal irgendwie herausfinden, welche Zeilen alles von der markierung betroffen sind und am anfang der zeile immer ein tab einfügen! ersteres ist das schwere, ich brauche die betroffenen markierten zeilen als integer zurück)



  • ich hoffe ich hab das Problem richtig verstanden, denn dann währe hier die Lösung:

    RichEdit1->SelText = "\t" + RichEdit1->SelText;
    

    Das bewirkt nämlich, dass der markierte text durch einen Tabulator + markierten text ersetzt wird.

    J0



  • Original erstellt von <ascii>:
    irgendwie herausfinden, welche Zeilen alles von der markierung betroffen sind

    RichEdit1->Perform(EM_EXLINEFROMCHAR, 0, RichEdit1->SelStart)
    

    gibt die erste Zeile mit markiertem Text zurück, das Gleiche unter Berücksichtigung von SelLength dann die letzte Zeile.

    Alternativ (ohne WinAPI) könnte man die letzte Zeile aus CaretPos.y entnehmen und dann einfach die Zeilenumbrüche (\r\n) in SelText zählen, um alle betroffenen Zeilen zu ermitteln. Allerdings versagt die Methode bei aktiviertem WordWrap, da dort (noch) keine echten Zeilenumbrüche erzeugt werden, letzteres passiert erst beim Speichern in eine Datei.



  • was macht ihr denn für gemausche? für sowas gibts doch Paragraph um textformatierungen vorzunehmen!?! 😕



  • Naja, da ist doch wohl noch ein Unterschied zwischen dem Einrücken per Tabulator und dem "Indenting" per Paragraph. Oder an welche Paragraph-Methode/Property hast du gedacht?



  • Wie beweg ich den Cursor eine Zeile tiefer? RichEdit->Lines++; gibt eine Verletzung.

    Ole, die Pfeiltaste kennt keinen AnsiString und verschiebt einfach die Cursorposition. Wie kann ich auf die Pfeiltasten zugreifen?

    -Oder hat niemand mehr Interesse an dem Thema? Nur die erste Zeile einrücken können, ist doch unbefriedigend.



  • TRichEdit::SelStart



  • Aber wohin dirigier ich den?

    Im Grund interessiert mich in der '?'-Zeile nur, ob RE->SelStart kleiner als Ziel bleibt. Ist diese Bedingung nicht mehr erfüllt,

    RE->SelStar = Ziel; // feddisch :p

    void __fastcall TChild::TextBlockClick(TObject *Sender)
    {
        int Start=RE->SelStart, Ziel=RE->SelLength;
        RE->SelText = "\t" + RE->SelText;
        RE->SelStart = Start;
        //RE->SelStart = ?;
    }
    

    Ab der 2. Zeile würde ich dem Text "\n\t" voransetzen. Gelingt es, bis dahin zu kommen, ließe sich ab da alles in einer Schleife regeln.



  • Probier mal selbjenes:

    AnsiString Text(RichEdit1->SelText);
    
    Text.Insert("\t", 1);
    RichEdit1->SelText=StringReplace(Text, "\n", "\n\t", TReplaceFlags()<<rfReplaceAll);
    

    Mußt das evtl. noch ein wenig "verfeinern" ... 😉



  • Herrliche Idee, @Peter. Das gibt schon mal die Funktionen Absätze einrücken, Absätze trennen, trennen und einrücken. Wieder ein paar Features, die der "gemeine Notepad" nicht hat; das wollte einfach eingebaut werden. :p

    In der Überlegung war übrigens ein denkfehler. Die erste Zeile braucht auch ein "\n" vor dem "\t", wenn noch keins vorhanden ist. Sonst verschiebt sich ja der Blockanfang beim weiter bearbeiten.

    Die Funktion tut halt nur was bei vorhandenen "\n". Die Kunst wäre, die reinzubringen. RE dürfte beim WordWrap kein Steuerzeichen anlegen, also erkennt man die virtuellen umbrüche nicht. Kann man nicht doch irgendwie auf die VK_DOWN zugreifen? Oder wie kann man das anders regeln?



  • In der Überlegung war übrigens ein Denkfehler

    Ich sagte doch, "Mußt das evtl. noch ein wenig 'verfeinern'" ... 🕶
    Hatte die Idee so zwischendurch und dachte, gibst mal ne kleine "Anregung". Jetzt bist Du wieder gefordert, ich muß mich "leider" mit anderen Aufgabenstellungen beschäftigen 😉



  • Hähä, ich hatte ja meinen Denkansatz gemeint. :p Man kann ja auch innerhalb eines Absatzes eine Einrückung haben wollen.

    Jo, ich kann nur rumschnüffeln, ob ich was find. Die Werkzeuge, die ich kenne, dürften nicht reichen. "Das ist ein Profiproblem", hat @ascii gesagt, und da dürfte was dran sein. In Sachen Stringmanipulation verhält sich AnsiString wie ein kompakter Klotz. 😞



  • 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);
    

Anmelden zum Antworten