I've been trying to use a tvaluelisteditor as part of a form designer
project I've finally gotten time to work on.
Tvaluelisteditor has a list of Key/Value pairs stored in the strings
field in the format key=value.
I seem to be crashing whenever I access the strings list after having
emptied it first.
Example try running these three lines in sequence:
valuelist.strings.add('hello=world'); // runs fine
valuelist.strings.clear(); // no problem with this line, BUT
valuelist.strings.add('hello=world'); // instant GPF
Has anyone else found this issue? If so is there a known workaround or
patch? I'd really hate to have to write my own valuelist editor if I could
just use this one.
Thanks,
--- Pat
----------------------------------------------------------------------
Hi, All!
I'm a bit disappointed in TValueListEditor component.
Today I started to use it and found that:
when I want to add new row in run-time I get:
1. Everything is OK, when row count > 0
2. Access violation when row count = 0
I spent a lot of time debugging my single code line :-) :
{code}
vleDeviceProps.Strings.Add('test=1');
{end of code}
... and found that there is an incorrect behavior of
TValueListStrings.InsertItem method:
Let's see what's happening when my code line is being executed
(I decided to provid it under MPL 1.1 ;-)):
1. TStringList.Add
2. TStringList.AddObject
3. TStringList.Find; {this one is called only when Sorted = True}
4. TValueListStrings.InsertItem; {The beautifull example of
polymorphism :-)}
So, lets examine TValueListStrings.InsertItem:
{ code by Borland}
procedure TValueListStrings.InsertItem(Index: Integer; const S: string;
AObject: TObject);
var
OldCount: Integer;
begin
KeyIsValid(ExtractName(S));
Changing; {Point A1. Remember It}
OldCount := Count;
inherited;
SetLength(FItemProps, Count);
if Index < OldCount then
System.Move(FItemProps[Index], FItemProps[Index + 1], (OldCount -
Index) * SizeOf(TItemProp));
FItemProps[Index] := nil;
Changed; {Point B1. Remember It}
end;
{end of code}
From the first sight everything is clear:
[1]. "Begin update": Changing method
[2]. Call inherited method - TStringList.InsertItem.
[3]. Change the size of array of TItemProp
[4]. Set current ItemProp to nil(BTW, what's about AObject parameter? ;-))
[5]. "End update": Change method;
(Concerning Item [4] - I'll return to it later.)
But lets "expand" those 'inherited' TStringList.InsertItem method:
{ code by Borland}
procedure TStringList.InsertItem(Index: Integer; const S: string; AObject:
TObject);
begin
Changing;{Point A2. Remember It}
if FCount = FCapacity then Grow;
if Index < FCount then
System.Move(FList^[Index], FList^[Index + 1], (FCount - Index) *
SizeOf(TStringItem));
with FList^[Index] do
begin
Pointer(FString) := nil;
FObject := AObject;
FString := S;
end;
Inc(FCount);
Changed; {Point B2. Remember It} {"Mama, it's a rock'n'roll!!!" (c) DDT
;-)}
end;
{end of code}
Did you get that? No? OK, I'll try to explain.
Let's "include" inherited method into a overriden version:
{code}
procedure TValueListStrings.InsertItem(Index: Integer; const S: string;
AObject: TObject);
var
OldCount: Integer;
begin
KeyIsValid(ExtractName(S));
Changing; {Point A1. Remember It}
OldCount := Count;
{inherited begin}
Changing;{Point A2. Remember It}
if FCount = FCapacity then Grow;
if Index < FCount then
System.Move(FList^[Index], FList^[Index + 1], (FCount - Index)
* SizeOf(TStringItem));
with FList^[Index] do
begin
Pointer(FString) := nil;
FObject := AObject;
FString := S;
end;
Inc(FCount);
*****Changed; {Point B2. Remember It}
{inherited end}
SetLength(FItemProps, Count);
if Index < OldCount then
System.Move(FItemProps[Index], FItemProps[Index + 1], (OldCount -
Index) * SizeOf(TItemProp));
FItemProps[Index] := nil;
Changed; {Point B1. Remember It}
end;
{end of code}
Ok, I give up:
in the line of Point B2 (those with '*****') due to polymorphism
THE TVALUESTRINGS.CHANGED METHOD IS CALLED!
That means that updates (grid updates) comese BEFORE these lines
{code}
SetLength(FItemProps, Count);
if Index < OldCount then
System.Move(FItemProps[Index], FItemProps[Index + 1], (OldCount -
Index) * SizeOf(TItemProp));
FItemProps[Index] := nil;
{code}
are executed.
So the memory for TItemProp reference is not got.
in some of TValueListEditor methods (GetEditStyle) the
TValueListStrings.FindItemProp method is called.
This method tries to get a reference to TItemProp instance:
{line: 1037} Result := FItemProps[Index];
and, of course, here comes an access violation exception:
length of FItemProps array is 0.
SOLVING:
It seems that the most easy way for solving this problem is to rewrite
TValueListStrings.InsertItem method this way:
{code}
procedure TValueListStrings.InsertItem(Index: Integer; const S: string;
AObject: TObject);
var
OldCount: Integer;
begin
KeyIsValid(ExtractName(S));
Changing; {Point A1. Remember It}
OldCount := Count;
{ do not call inherited method but paste some of its code here }
{ WITHOUT Point A2 and Point B2 lines}
SetLength(FItemProps, Count);
if Index < OldCount then
System.Move(FItemProps[Index], FItemProps[Index + 1], (OldCount -
Index) * SizeOf(TItemProp));
FItemProps[Index] := nil;
Changed; {Point B1. Remember It}
end;
{end of code}
----------------------------
Though this message is about Point B2, but there is a need to
say some "good" words about Point A2 line:
TValueListStrings.Changing method is called twice in three(!!!) lines of
code:
{code}
Changing; {Point A1, line: 1054}
OldCount := Count;{this line does not influence grid behavior}
inherited;{ inherited method starts with Changing - Point A2}
{end of code}
That could probably be OK(though I don't think so), but
TValueListStrings.Changing method calls:
* inherited Changing method
* TValueListEditor.StringsChanging
* TCustomGrid.HideEdit
* TInplaceEdit.Hide
* TCustomGrid.UpdateText
* TCustomMaskEdit.GetText
* TValueListEditor.SetEditText
* Some more methods
* TInplaceEdit.Invalidate;
* SetFocus(Grid.Handle);
Well, the same actions being executed twice without any changed of a grid.
It must be to save cpu time and resources usage ;-)
---------------------
I have Delphi 6, Ent, Update Pack 1 installed.
Maybe some of Delphi developers can comment this message?
(Maybe I get wrong in some of my code lines ;-)?)
Regards,
Michael Skachkov
Author of Property Editors Project
http://delphiplus.spils.lv/downloads/tips/mspropedit_d6.zip
--- Pat
"Michael Skachkov" <ze...@dagobah.mk.ua> wrote in message
news:3c453b18_2@dnews...