TPanelEx = Class(TPanel)
在TPandelEx中我又增加了一个属性叫
property Items: TStringList read GetItems write SetItems;
作用是在TPanelEx上把Items中的字符显示出来
在设计和程序运行中都已经可以动态添加并显示Items中的内容了,
现在的问题是,我在设计时在Items中添加了的字串,在程序执行时无法显示,只能在程序运行时动态添加.查了一下类似的TListBox,也没有得到答案.
在TPandelEx中我又增加了一个属性叫
property Items: TStringList read GetItems write SetItems;
作用是在TPanelEx上把Items中的字符显示出来
在设计和程序运行中都已经可以动态添加并显示Items中的内容了,
现在的问题是,我在设计时在Items中添加了的字串,在程序执行时无法显示,只能在程序运行时动态添加.查了一下类似的TListBox,也没有得到答案.
或者继承绘制过程,先调用Caption := FItems.Text;再inherited试试
'123'
'456'
可程序运行时,FItems中什么都有没有,也就是说TPanelEx在Create的时候没有载入我设计时写的内容.我想这应该是要我手动完成的,可是如何实现呢?
如果有,那么可能是你创建的时候没有载入你的属性;
如果是前者,在D7的源码中有好多例子,如TMemo,TComBox,TTabSet...等.
当时我挑了一个TMemo,粗看了它的代码,没有找到问题的根源.
然后细看了TCustomMemo.Create()
constructor TCustomMemo.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 185;
Height := 89;
AutoSize := False;
FWordWrap := True;
FWantReturns := True;
FLines := TMemoStrings.Create;
TMemoStrings(FLines).Memo := Self;
ParentBackground := False;
end;
涉及FLines的只有两句
FLines := TMemoStrings.Create;
TMemoStrings(FLines).Memo := Self;
事实上也看不出有什么玄妙的.甚至找不到TMemoStrings或TStrings的Create函数,还请高手指点.手把手的教一下.呵呵
TPanelEx = Class(TPanel)
private
FLines: TStrings;
function GetLines(): TStrings;
procedure SetLines(const Value: TStrings);
protected
procedure Paint;override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Items: TStrings read GetLines write SetLines;
end;
constructor TPanelEx.Create(AOwner: TComponent); override;
begin
FLines := TStringList.Create;//这里比较偷懒,没有从TStrings中派生出一个而是直接用了一个现成的
end;
procedure Paint;override
begin
在PanelEx上把Flines中的字符显示出来
end;
function GetLines():TStrings;
begin
{Result := TStringList.Create
Result.assign(FLines)}
end;
事实上,我在设计时,在Object Inspect中的Items中写入
'123'
'1234'
在PanelEx1上是可以显示出来的
同样,如果我在程序中
ss := TStringList.Create;
ss.add('123');
ss.add('1234');
PanelEx1.Items := ss;
也是可以显示出来的,但是我在设计时写入的
'123'
'1234'
在程序运行时就无法显示了,FLines里面是空的。
可能正如 aiirii(ari-爱的眼睛) 所说的没有实现流话,请问如何实现呢?
查看 StdCtrls.Pas中TMemoStrings的声明和实现:
TMemoStrings = class(TStrings)
private
Memo: TCustomMemo;
protected
function Get(Index: Integer): string; override;
function GetCount: Integer; override;
function GetTextStr: string; override;
procedure Put(Index: Integer; const S: string); override;
procedure SetTextStr(const Value: string); override;
procedure SetUpdateState(Updating: Boolean); override;
public
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: string); override;
end;
{ TMemoStrings }function TMemoStrings.GetCount: Integer;
begin
Result := 0;
if Memo.HandleAllocated or (Memo.WindowText <> nil) then
begin
Result := SendMessage(Memo.Handle, EM_GETLINECOUNT, 0, 0);
if SendMessage(Memo.Handle, EM_LINELENGTH, SendMessage(Memo.Handle,
EM_LINEINDEX, Result - 1, 0), 0) = 0 then Dec(Result);
end;
end;function TMemoStrings.Get(Index: Integer): string;
var
Text: array[0..4095] of Char;
begin
Word((@Text)^) := SizeOf(Text);
SetString(Result, Text, SendMessage(Memo.Handle, EM_GETLINE, Index,
Longint(@Text)));
end;procedure TMemoStrings.Put(Index: Integer; const S: string);
var
SelStart: Integer;
begin
SelStart := SendMessage(Memo.Handle, EM_LINEINDEX, Index, 0);
if SelStart >= 0 then
begin
SendMessage(Memo.Handle, EM_SETSEL, SelStart, SelStart +
SendMessage(Memo.Handle, EM_LINELENGTH, SelStart, 0));
SendMessage(Memo.Handle, EM_REPLACESEL, 0, Longint(PChar(S)));
end;
end;procedure TMemoStrings.Insert(Index: Integer; const S: string);
var
SelStart, LineLen: Integer;
Line: string;
begin
if Index >= 0 then
begin
SelStart := SendMessage(Memo.Handle, EM_LINEINDEX, Index, 0);
if SelStart >= 0 then Line := S + #13#10 else
begin
SelStart := SendMessage(Memo.Handle, EM_LINEINDEX, Index - 1, 0);
if SelStart < 0 then Exit;
LineLen := SendMessage(Memo.Handle, EM_LINELENGTH, SelStart, 0);
if LineLen = 0 then Exit;
Inc(SelStart, LineLen);
Line := #13#10 + s;
end;
SendMessage(Memo.Handle, EM_SETSEL, SelStart, SelStart);
SendMessage(Memo.Handle, EM_REPLACESEL, 0, Longint(PChar(Line)));
end;
end;procedure TMemoStrings.Delete(Index: Integer);
const
Empty: PChar = '';
var
SelStart, SelEnd: Integer;
begin
SelStart := SendMessage(Memo.Handle, EM_LINEINDEX, Index, 0);
if SelStart >= 0 then
begin
SelEnd := SendMessage(Memo.Handle, EM_LINEINDEX, Index + 1, 0);
if SelEnd < 0 then SelEnd := SelStart +
SendMessage(Memo.Handle, EM_LINELENGTH, SelStart, 0);
SendMessage(Memo.Handle, EM_SETSEL, SelStart, SelEnd);
SendMessage(Memo.Handle, EM_REPLACESEL, 0, Longint(Empty));
end;
end;procedure TMemoStrings.Clear;
begin
Memo.Clear;
end;procedure TMemoStrings.SetUpdateState(Updating: Boolean);
begin
if Memo.HandleAllocated then
begin
SendMessage(Memo.Handle, WM_SETREDRAW, Ord(not Updating), 0);
if not Updating then
begin // WM_SETREDRAW causes visibility side effects in memo controls
Memo.Perform(CM_SHOWINGCHANGED,0,0); // This reasserts the visibility we want
Memo.Refresh;
end;
end;
end;function TMemoStrings.GetTextStr: string;
begin
Result := Memo.Text;
end;procedure TMemoStrings.SetTextStr(const Value: string);
var
NewText: string;
begin
NewText := AdjustLineBreaks(Value);
if (Length(NewText) <> Memo.GetTextLen) or (NewText <> Memo.Text) then
begin
if SendMessage(Memo.Handle, WM_SETTEXT, 0, Longint(NewText)) = 0 then
raise EInvalidOperation.Create(SInvalidMemoSize);
Memo.Perform(CM_TEXTCHANGED, 0, 0);
end;
另TComboBox,TTabSet等也有类似的实现,这是关键!
Memo间接继承自CustermEdit,它的Lines直接是来自CustermEdit的Text.这样是每个Edit天生就有的,而我的PanelEx是增加了一个全新的,Items的属性,没法子从其它属性中取值.
还有,我拿原生类型试试,Integer,String,设计和运行时都是没有问题的,请高手们继续.
unit PanelEx;interfaceuses
SysUtils, Classes, Controls, ExtCtrls;type
TPanelEx = class;
TItemList = class(TStringList)
private
Panel: TPanelEx;
public
procedure Insert(Index: Integer; const S: string); override;
procedure Delete(Index: Integer); override;
function Add(const S: string): Integer; override;
end; TPanelEx = class(TPanel)
private
{ Private declarations }
FItems : TStrings;
procedure SetItemList(Value: TStrings);
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
{ Published declarations }
property items: TStrings read FItems write SetItemList;
end;procedure Register;implementationprocedure Register;
begin
RegisterComponents('Samples', [TPanelEx]);
end;{ TOWNTabList }function TItemList.Add(const S: string): Integer;
begin
Result := inherited Add(S);end;procedure TItemList.Insert(Index: Integer; const S: string);
begin
inherited Insert(Index, S);
end;procedure TItemList.Delete(Index: Integer);
begin
inherited Delete(Index);
end;{TPanelEx}
constructor TPanelEx.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FItems := TItemList.Create;
TItemList(FItems).Panel := Self;
end;
destructor TPanelEx.Destroy;
begin
FItems.Free;
end;
procedure TPanelEx.SetItemList(Value: TStrings);
begin
FItems.Assign(Value);
end;
end.
原因,我也说不清楚。感觉好像设计时字符串是由TItemList 来维护的,要不,
你在运行赋给的字符串岂不在设计时也看见了?直接调用TStringList应该不能(或
是编译器不允许)完成保存字符串的功能。
destructor TPanelEx.Destroy;
begin
FItems.Free;
这里应该加一句inherited,否则会报错,不过无伤大
end;问题刚刚找到了,如果是这样
property Items: TStrings read GetItems write SetItems;
GetItems反回的是一个FItems的副本.
不行
property Items: TStrings read FItems write SetItems;
就行了.