views:

194

answers:

2

I have an attribute called HistoryText in a object that is stored as a string. I want to show all rows in a grid. I should be able to delete and edit rows in the grid. The format is:

16.5.2003-$-12:09-$-anna-$-Organization created
2.6.2005-$-13:03-$-jimmy-$-Organization edited
19.12.2005-$-13:33-$-madeleine-$-Organization edited

So each row have 4 fields, date, time, user, and message with a delimiter string as '-$-'. As the delimiter a string and not a char it cannot be assigned to the stringlists delimiter property.

I have a routine to extract the string to a Stringlist:

procedure ParseDelimited(const aStringList: TStringList; const aOrgList, aDelimiter: string);
var
   vDelimiterPos : integer;
   vPartialStr : string;
   vRemaingTxt : string;
   vDelimiterLength : integer;
begin
   vDelimiterLength := Length(aDelimiter);

   if (AnsiRightStr(aOrgList, Length(aDelimiter)) = aDelimiter) then
     vRemaingTxt := aOrgList
   else
     vRemaingTxt := aOrgList + aDelimiter;

   aStringList.BeginUpdate;
   aStringList.Clear;
   try
     while Length(vRemaingTxt) > 0 do
     begin
       vDelimiterPos := Pos(aDelimiter, vRemaingTxt);
       vPartialStr := Copy(vRemaingTxt,0,vDelimiterPos-1);
       aStringList.Add(vPartialStr);
       vRemaingTxt := Copy(vRemaingTxt,vDelimiterPos+vDelimiterLength,MaxInt);
     end;
   finally
     aStringList.EndUpdate;
   end;
end;

and it seems to work fine. My problem is syncing the changes in the StringList back to the original String property ? There are so much historical data with this delimiter so I don't think change it to a TChar is a realistic option.

Update: A clarification. I think I can manage to convert the String to a StringList with the method above. Then display it in the grid should not be so hard. The problem come when I want to convert the TStringList back to the original String property wih '-$-' as delimiter. I cannot do HistoryText := myStringList.Delimitedtext for example.

Second update: I have solved it. You all got a +1 for fast answers and really trying to help. In summary how I did it.

Read from Historytext:

MyStringList.Text := Historytext;

Now each row have 3 delimiters of '-$-' and each line is separated by a linefeed as usual.

  • In a loop parse the Stringlist and show it in the grid. I don't bother about MyStringList anymore.
  • Let the user delete and edit rows in the grid.
  • When finished loop by row and columns in the grid and build a new string with the same format as original.
  • Assign that string to HistoryText.

So shift focus from StringList to the grid made it easier :)

+2  A: 

Wild stab in the dark (it isn't very clear what you are asking):

Work through the grid rows:

  • For each row:
    • assign an empty string to a temporary string var
    • For each column add row/column value plus your delimiter to temporary string var
    • remove last delimiter from temporary string var (if it is non-empty)
    • add temporary string var to stringlist
  • Write stringlist's text property back to your HistoryText

const
  Delimiter = '-$-';
var
  row: Integer;
  col: Integer;
  SL: TStringList;
  rowString: string;
begin
  SL := TStringList.Create;
  try
    for row := 0 to StringGrid1.RowCount - 1 do begin
      rowString := '';
      for col := 0 to StringGrid1.ColCount - 1 do begin
        rowString := StringGrid1.Cells[col, row] + Delimiter;
      end;
      if rowString <> '' then begin
        rowString := Copy(rowString, 1, Length(rowString) - Length(Delimiter));
      end;
      SL.Add(rowString);
    end;
    HistoryText := SL.Text;
  finally
    SL.Free;
  end;
end;

Using Uwe's solution of TStrings' LineBreak property:

var
  row: Integer;
  col: Integer;
  SLRows: TStringList;
  SLCols: TStringlist;
begin
  SLRows := TStringList.Create;
  try
    SLCols := TStringList.Create;
    try
      SLCols.LineBreak := '-$-';
      for row := 0 to StringGrid1.RowCount - 1 do begin
        SLCols.Clear;
        for col := 0 to StringGrid1.ColCount - 1 do begin
          SLCols.Add(StringGrid1.Cells[col, row]);
        end;
        SLRows.Add(SLCols.Text);
      end;
      HistoryText := SLRows.Text;
    finally
      SLCols.Free;
    end;
  finally
    SLRows.Free;
  end;
end;
Marjan Venema
+4  A: 

Instead of Delimiter (a char) and DelimitedText, you can also use LineBreak (a string) and Text:

lst := TStringList.Create;
try
  lst.LineBreak := '-$-';
  lst.Text := '16.5.2003-$-12:09-$-anna-$-Organization created';
  Memo1.Lines := lst;  // or whatever you do with it
finally
  lst.Free;
end;

Ans it works even the other way round.

Uwe Raabe
Hey that's a good one. Do you know when (Which Delphi version) that was introduced?
Marjan Venema
D7 < x <= D2007
Uwe Raabe
Sorry but I don't understand it.Each line in the string property as delimited with a Carriage return + linefeed. So The real string is:16.5.2003-$-12:09-$-anna-$-Organization created#D#A2.6.2005-$-13:03-$-jimmy-$-Organization edited#D#A19.12.2005-$-13:33-$-madeleine-$-Organization edited#D#Alst := TStringList.Create;try lst.LineBreak := '-$-'; lst.Text := myObject.HistoryText // Use the list in grid for example finally lst.Free;end;Is this what you mean?
Roland Bengtsson
@Uwe, @Marjan: the TStrings.LineBreak property got introduced in Delphi 2006.
Jeroen Pluimers
Yeah, so do it like in my answer, or use 2 stringlists. You start by assigning the HistoryText to the first and then work through all items in that stringlist. Assign each string from the first stringlist to the text of the second stringlist. This should have its linebreak property set to '-$-' to split each row in fields. Each field should then be an item in the second stringlist. To go back to your HistoryText you do the same in reverse: add each col value to the second stringlist, then add its entire text to the first, clear the second, rinse and repeat for each row.
Marjan Venema
Added an example using two stringlists to my answer.
Marjan Venema
@Roland: I assumed you meant to split only one line of text so the index inside the resulting stringlist resembles the column of the stringgrid. If you have only one big string, you must first separate it into indivdual rows using a stringlist with the #D#A linebreak and the each row into fields with second stringlist using my approach - just as Marjan shows in his example as I just realized.
Uwe Raabe