Spalte in StringGrid aus Zwischenablage füllen



  • Ich möchte Daten, die sich in der Zwischenablage befinden, in ein StringGrid ablegen. Der Anwender wählt die Daten in einer Spalte in Exel aus und speichert diese in die Zwischenablage. Diese sollen über copy&paste in eine StringGrid kopiert werden (ab der markierten Zeile). Wie macht man das?



  • Excel kopiert die Daten auch im tab-separierten Textformat.



  • hab es mal versucht und es funktioniert auch soweit ganz gut. Hier mal das Ergebnis. Vielleicht habt Ihr ja Verbesserungsvorschläge. Was haltet Ihr davon?

    // Button kopiert Inhalt der Zwischenablage in die Grid in die Spalte der markierten Zelle
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       if (Clipboard()->HasFormat(CF_TEXT)){
          int size = Clipboard()->AsText.Length();
          size++;
          char* buffer = new char[size];
          Clipboard()->GetTextBuf(buffer, size);
          TStringList* stl = new TStringList();
          AnsiString s = "";
          for (int i=0; i<size; i++) {
             if (buffer[i] == '\r') {
                stl->Add(s);
                s = "";
             }
             else
                if (buffer[i] != '\n')
                   s = s + buffer[i];
          }
          for (int i=0; i<stl->Count; i++) {
             grid->Cells[iCol][i+iRow] = stl->Strings[i]; //iCol und iRow sind integer-Variablen die als private der Form deklariert sind
          }
    
          delete stl;
          delete [] buffer;
       }
       else
          Application->MessageBox("Die Zwischenablage enthält keinen Text!", NULL, MB_OK);
    }
    //---------------------------------------------------------------------------
    //markiert die Zelle im Grid und übergibt Spalte und Zeile
    void __fastcall TForm1::gridMouseDown(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
    {
       TStringGrid* pGrid = dynamic_cast<TStringGrid*>(Sender);
       pGrid->MouseToCell(X, Y, iCol, iRow);
    }
    


  • rudpower schrieb:

    Vielleicht habt Ihr ja Verbesserungsvorschläge.

    Smart-Pointer verwenden.

    Übrigens brauchst du das Zerlegen in Zeilen nicht von Hand zu machen; mit stl->Text = buffer; macht die String-Liste das ganz von selbst.



  • ok. Welchen Smart-pointer nehm ich da? Ich vermute mal der auto_ptr. Hier mal die korrigierte Version:

    void __fastcall TfraSubstrat::AusZischenablageSpalteeinfgen1Click(
          TObject *Sender)
    {
       if (Clipboard()->HasFormat(CF_TEXT)) {
          int size = Clipboard()->AsText.Length();
          size++;
          char* buffer = new char[size];
          Clipboard()->GetTextBuf(buffer, size);
          std::auto_ptr<TStringList> stlData(new TStringList); //hier die Fehlermarke
          stlData->Text = buffer;
    
          for (int i=0; i<stlData->Count; i++) {
             gridSubstrates->Cells[taggedCol][i+taggedRow] = stlData->Strings[i];
          }
    
          delete [] buffer;
       }
       else
          Application->MessageBox("Die Zwischenablage enthält keinen Text!", NULL, MB_OK);
    }
    

    Leider erhalte ich aus mir unbekannten Gründen folgenden Fehler:

    [C++ Fehler] frameSubtrat.cpp(75): E2316 'auto_ptr' ist kein Element von 'std'
    [C++ Fehler] frameSubtrat.cpp(75): E2108 Ungültige Verwendung von typedef 'TStringList'
    [C++ Fehler] frameSubtrat.cpp(75): E2268 Aufruf der undefinierten Funktion 'stlData'
    [C++ Fehler] frameSubtrat.cpp(76): E2288 Zeiger auf Struktur auf linker Seite von -> oder von ->* erforderlich
    [C++ Fehler] frameSubtrat.cpp(78): E2288 Zeiger auf Struktur auf linker Seite von -> oder von ->* erforderlich
    [C++ Fehler] frameSubtrat.cpp(79): E2288 Zeiger auf Struktur auf linker Seite von -> oder von ->* erforderlich
    

    Edit:

    Fehler gefunden. Habe memory nicht per include eingebunden.
    Kann ich den auto_ptr auch bei dem chararray buffer nehmen? also:

    std::auto_ptr<char> buffer(new char[]);
    


  • Hallo

    rudpower schrieb:

    Kann ich den auto_ptr auch bei dem chararray buffer nehmen? also:

    std::auto_ptr<char> buffer(new char[]);
    

    Nein, auto_ptr benutzt im Destruktor delete und nicht delete[], wie es bei C-Arrays nötig wäre.
    Aber dafür kannst du std::vector<char> nehmen.

    bis bald
    akari



  • ok. Wie geb ich die Adresse des Vektors in der Methode int __fastcall GetTextBuf(char * Buffer, int BufSize); als Parameter an?
    So funktioniert es natürlich nicht:

    int size = Clipboard()->AsText.Length();
    size++;
    std::vector<char> vbuffer;
    vbuffer.resize(size);
    Clipboard()->GetTextBuf(vbuffer, size); //???
    std::auto_ptr<TStringList> stlData(new TStringList);
    stlData->Text = vbuffer; //???
    

    Die Zeile stlData->Text = vbuffer; funktioniert ja mit Vektor so auch nicht mehr.

    Sollte ich zukünftig prinzipiell char arrays durch vector ersetzen? Ich fände es bequemer, da ich mich ja um das deleten nicht mehr kümmern müsste.

    Brauch ich das size++ überhaupt bzw warum muss ich das machen? Ich denk mal das war in dem Beispiel wo ich das her hatte für einen String der ja die '/0' am Ende braucht. Aber das benötige ich ja in meinem Fall nicht oder?

    --> Edit: grad nochmal ein bissl im grünen Buch geblättert und mal die Vektormethode begin() ausprobiert. Scheinbar ist das die Lösung:

    int size = Clipboard()->AsText.Length();
    size++;
    std::vector<char> vbuffer;
    vbuffer.resize(size);
    Clipboard()->GetTextBuf(vbuffer.begin(), size);
    std::auto_ptr<TStringList> stlData(new TStringList);
    stlData->Text = vbuffer.begin();
    


  • Die Angangsadresse eines vectors bekommt man mit

    &(vbuffer[0])
    

    begin liefert einen Iterator auf den Anfang deines vectors, ist also nicht direkt das was du hier brauchst. Insbesondere das hier

    stlData->Text = vbuffer.begin();
    

    kommt mir sehr merkwürdig vor. Dein vector<char> hat nämlich keine Nullterminierung weswegen diese Zuweisung nicht korrekt ist.
    Ich würde das eher so machen.

    stlData->Text = AnsiString(&(vbuffer[0]), vbuffer.size());
    


  • ok. Funktioniert. Das size++ brauch ich nicht oder?



  • Ich muss mich gerade nochmal revidieren.
    GetTextBuf erzeugt einen Nullterminierten String. Das heißt es liest size - 1 Daten aus dem Clipboard und hängt dann noch eine 0 an.
    Das bedeutet du brauchst das size++.
    Warum nimmst du denn nicht gleich AsText und ersparst dir den vector?

    std::auto_ptr<TStringList> stlData(new TStringList);
    stlData->Text = Clipboard()->AsText;
    

    PS:
    Das funktioniert natürlich nur wenn da wirklich Text drin ist. Das solltest du vielleicht vorher noch testen.



  • ok, das stimmt. Nun der fertige Code:

    void __fastcall TfraSubstrat::AusZischenablageSpalteeinfgen1Click(
          TObject *Sender)
    {
       if (Clipboard()->HasFormat(CF_TEXT)) {
          std::auto_ptr<TStringList> stlData(new TStringList);
          stlData->Text = Clipboard()->AsText;
          for (int i=0; i<stlData->Count; i++)
             gridSubstrates->Cells[taggedCol][i+taggedRow] = stlData->Strings[i];
       }
       else
          Application->MessageBox("Die Zwischenablage enthält keinen Text!", NULL, MB_OK);
    }
    

Anmelden zum Antworten