Скопировать строку в StringGrid? - PullRequest
6 голосов
/ 11 марта 2012

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

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

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

enter image description here

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

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

enter image description here

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

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

Как мне это сделать?

Ответы [ 3 ]

5 голосов
/ 11 марта 2012

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

Этот пример взят из комментария Олафа Мойнена к статье Зарко Гайича: как разделить дельфиstring-to-words-tokens.htm .

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;

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

5 голосов
/ 11 марта 2012

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

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

2 голосов
/ 12 марта 2012

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