Скопировать строку в StringGrid?

Я хотел бы скопировать содержимое Заметки в TStringGrid.

Если между строками есть пробел или пробел, то это слово должно быть добавлено в свою собственную ячейку в StringGrid.

Итак, предположим, что моя заметка, которая Wordwrapped содержит некоторую информацию, например:

enter image description here

Как я могу скопировать эту информацию в StringGrid?

для целей этого примера я сделал образец изображения, чтобы проиллюстрировать, как результат должно быть:

enter image description here

важно знать, что я не всегда буду знать количество столбцов для использования, если, например, заметка загружается из текстового файла.

возможно, предопределенное количество столбцов было бы лучше, например, 5 или 6 столбцов. Количество строк также будет неизвестно.

Как я могу это сделать?

3 ответов


Если я правильно понял, то это должно сделать это:

procedure TForm1.FormClick(Sender: TObject);
type
  TWordPos = record
    Start, &End: integer;
  end;
const
  ALLOC_BY = 1024;
var
  Words: array of TWordPos;
  ActualLength, i: integer;
  txt: string;
  ThisWhite, PrevWhite: boolean;
begin

  ActualLength := 0;
  txt := Memo1.Text;
  PrevWhite := true;
  for i := 1 to Length(txt) do
  begin
    ThisWhite := Character.IsWhiteSpace(txt[i]);
    if PrevWhite and not ThisWhite then
    begin
      if ActualLength = Length(Words) then
        SetLength(Words, Length(Words) + ALLOC_BY);
      Words[ActualLength].Start := i;
      inc(ActualLength);
      PrevWhite := false;
    end else if (ActualLength>0) and ThisWhite then
      Words[ActualLength - 1].&End := i;
    PrevWhite := ThisWhite;
  end;

  SetLength(Words, ActualLength);

  StringGrid1.RowCount := Ceil(Length(Words) / StringGrid1.ColCount);

  for i := 0 to Length(Words) - 1 do
  begin
    StringGrid1.Cells[i mod StringGrid1.ColCount, i div StringGrid1.ColCount] :=
      Copy(Memo1.Text, Words[i].Start, Words[i].&End - Words[i].Start);
  end;

end;

скриншот http://privat.rejbrand.se/stringgridwordsfrommemo.png


есть Tokenizer (Как прокомментировал Дэвид) в RTL. Он разделит текст на слова, используя разделитель по вашему выбору.

этот пример из комментария Олафа Мойнена в статье Зарко Гайича:how-to-split-a-delphi-string-to-words-tokens.НТМ.

uses HTTPUtil;

procedure TForm1.Button1Click(Sender: TObject);
var
  LTokenizer: IStringTokenizer;
begin
  Memo1.Clear;
  LTokenizer := StringTokenizer(Edit1.Text, ' ');
  while LTokenizer.hasMoreTokens do
  Memo1.Lines.Add(LTokenizer.nextToken);
end;

Он возьмет текст из элемента управления редактирования и поместит его в заметку. Я оставлю это как упражнение, чтобы сделать то же самое из заметки в stringgrid.


TStringGrid имеет функцию для заполнения несуществующий клетки, клетки, которые находятся за пределами ColCount * RowCount. При этом нет необходимости считать слова перед заполнением Строковой сетки.

затем, простой подход приводит к:

procedure TForm1.Button1Click(Sender: TObject);
var
  WordCount: Integer;
  WordStart: Integer;
  S: String;
  I: Integer;
begin
  WordCount := 0;
  WordStart := 1;
  S := Memo.Text + ' ';
  for I := 1 to Length(S) do
    if S[I] = ' ' then
    begin
      if WordStart <> I then
      begin
        Grid.Cells[WordCount mod Grid.ColCount, WordCount div Grid.ColCount] :=
          Copy(S, WordStart, I - WordStart);
        Inc(WordCount);
      end;
      WordStart := I + 1;
    end;
  Grid.RowCount := ((WordCount - 1) div Grid.ColCount) + 1;
end;

Примечание: чтобы предотвратить дополнительное выделение памяти для текста (из-за добавления ' '), вместо этого добавьте последнее слово в сетку после цикла.

бонус особенность:

чтобы иметь возможность регулировать количество столбцов, подкласс сетки строк следующим образом, и все ячейки будут переставлены автоматически:

type
  TStringGrid = class(Grids.TStringGrid)
  protected
    procedure SizeChanged(OldColCount, OldRowCount: Integer); override;
  end;

  TForm1 = class(TForm)
  ...

procedure TStringGrid.SizeChanged(OldColCount, OldRowCount: Integer);
var
  I: Integer;
begin
  if OldColCount < ColCount then
  begin
    for I := 0 to OldColCount * OldRowCount - 1 do
      Cells[I mod ColCount, I div ColCount] :=
        Cells[I mod OldColCount, I div OldColCount];
  end
  else if OldColCount > ColCount then
  begin
    for I := OldColCount * OldRowCount - 1 downto 0 do
      Cells[I mod ColCount, I div ColCount] :=
        Cells[I mod OldColCount, I div OldColCount];
  end;
  if OldColCount <> OldRowCount then
    for I := OldColCount * OldRowCount to ColCount * RowCount - 1 do
      Cells[I mod ColCount, I div ColCount] := '';
end;