ورود

View Full Version : سوال: خواندن و نوشتن در مشخصه tag هر Node در treeView



tabaprg
یک شنبه 22 خرداد 1390, 18:22 عصر
با سلام خدمت اساتید دلفی
من یه کدی نوشتم و میخوام مثل سی شارپ توی هر node یک treeView مقدار پراپرتی tag رو پر کنم.
لطفا راهنماییم کنید.ممنون میشم.
MyTreeNode2 := TreeView1.Items.AddChild(MyTreeNode1, dstOrder.FieldByName('OrderId').AsString);
MyTreeNode2.TreeView.Tag := dstOrder.FieldByName('OrderId').AsInteger;

اگر کدی که من نوشتم درست باشه یعنی درست به tag مقدار داده باشم با این حساب فقط خواندن این پراپرتی (tag) میمونه که من نتونستم بخونمش.

vcldeveloper
دوشنبه 23 خرداد 1390, 00:05 صبح
Node ها در TreeView خصوصیت Tag ندارند. اون خصوصیت Tag ایی که شما دارید بهش مقدار میدید، Tag مربوط به کنترل TreeView1 هست.

Node ها در TreeView خصوصیت Data دارند که یک اشاره گر هست، می تونید در آن اشاره گری به هر ساختار داده ایی در حافظه را نگهداری کنید، و بعدا به آن داده رجوع کنید. مثلا می تونید یک شی داشته باشید و آدرسش را در این خصوصیت ذخیره کنید تا بعدا بتونید بهش دسترسی داشته باشید.

برای اینکه بتونید یک مقدار Integer را در این خصوصیت Data نگهداری کنید، دو راه دارید؛

راه اول این هست که برای اون integer در فضای حافظه heap حافظه ایی رزرو کنید، و آدرس اون رو در خصوصیت Data نگهداری کنید. در این حالت، باید بعد از پایان کار تان حافظه رزرو شده را آزاد کنید، وگرنه با نشست حافظه مواجه میشید. مثالش میشه کدی شبیه به این:


var
MyNode : TTreeNode;
MyNodeData : Integer;
MyNodeName : string;
PMyNodeData : PInteger;

ایجاد Node:


New(PMyNodeData);
PMyNodeData^ := 1234;
MyNodeName := 'My Node';
MyNode := TreeView1.Items.AddChild(nil,MyNodeName);
MyNode.Data := PMyNodeData;

دسترسی به خصوصیت Data یک Node:


MyNode := TreeView1.Selected;
if Assigned(MyNode) then
begin
MyNodeName := MyNode.Text;
PMyNodeData := MyNode.Data;
MyNodeData := PMyNodeData^;
end;

آزاد کردن حافظه رزرو شده در پایان کار:


for MyNode in TreeView1.Items do
begin
PMyNodeData := MyNode.Data;
if Assigned(PMyNodeData) then
Dispose(PMyNodeData);
end;

به این طریق می تونید آدرس هر داده ایی رو نگهداری کنید، و محدود به نوع Integer نیستید.


راه دوم این هست که فرض کنید یک Pointer در واقع یک Integer هست که به جای یک عدد عادی، آدرس یک خانه از حافظه را نگهداری میکنه؛ پس میشه با type-cast کردن Integer به Pointer و بالعکس، یک مقدار Integer را در خصوصیت Data از Node مربوطه نگهداری کرد. البته به شرطی که همیشه یادتون باشه که در اون خصوصیت یک عدد معمولی را نگهداری می کنید، و جایی اشتباها ازش به عنوان Pointer استفاده نکنید. اون وقت کد شما اینطوری میشه:


var
MyNode : TTreeNode;
MyNodeData : Integer;
MyNodeName : string;


ایجاد یک Node:


MyNodeData := 1234;
MyNodeName := 'My Node';
MyNode := TreeView1.Items.AddChild(nil,MyNodeName);
MyNode.Data := Pointer(MyNodeData);

دسترسی به خصوصیت Data یک Node:


MyNode := TreeView1.Selected;
if Assigned(MyNode) then
begin
MyNodeName := MyNode.Text;
MyNodeData := Integer(MyNode.Data);
end;

این روش دردسر کمتری از روش قبلی داره، ولی مبتنی بر یک پیش فرض دارای ریسک هست. در واقع شما دارید به کامپایلر میگید، من خودم میدونم دارم چیکار میکنم و به همه زوایای موضوع اشراف دارم، تو کاریت نباشه. خب اگر یک وقتی دقیقا ندونید دارید چیکار می کنید، براتون مشکل پیش میاد.

tabaprg
سه شنبه 24 خرداد 1390, 16:44 عصر
با تشکر از پاسخ شما استاد عزیز
حالا اگه من بخوام یک treeView داشته باشم که به هر نود اون یک tag اختصاص بدم باید چه عملیاتی رو انجام بدم؟ یعنی یک پراپرتی براش تعریف کنم. فکر کنم اگه بشه یک لیست داشته باشم که دو مقدار بگیره یکی value و دیگری Key که value هر مقداری می تونه باشه و key ذخیره خاصیت absolutIndex هر نود باشه ولی اینکه چه طور این دو کامپوننت(treeView, ValueListEditor) رو با هم تلفیق کنم نمی دونم چه کار کنم.

vcldeveloper
چهارشنبه 25 خرداد 1390, 02:40 صبح
حالا اگه من بخوام یک treeView داشته باشم که به هر نود اون یک tag اختصاص بدم باید چه عملیاتی رو انجام بدم؟ یعنی یک پراپرتی براش تعریف کنم.
چرا از همون خصوصیت Data که در بالا اشاره کردم استفاده نمی کنید؟ اگر بخواید خودتون یک خصوصیت tag اضافه کنید، باید اولا یک کلاس جدید از کلاس TTreeNode مشتق کنید، و خصوصیت Tag رو بهش اضافه کنید، و ثانیا، برای رویداد OnCreateNodeClass اون TreeView خاص کد بنویسید که کلاس جدید شما رو برگشت بده، و ثالثا، هر جا که به خصوصیت Tag یک نود نیاز دارید، مقدار Item برگشتی از TreeView را به کلاس جدید خودتان Type-cast کنید:

یک کلاس جدید از TTreeView:


type
TMyTreeNode = class (TTreeNode)
private
FTag : NativeInt;
public
property Tag : NativeInt read FTag write FTag;
end;

ایجاد کد برای رویداد OnCreateNodeClass :


procedure TForm1.TreeView1CreateNodeClass(Sender: TCustomTreeView;
var NodeClass: TTreeNodeClass);
begin
NodeClass := TMyTreeNode;
end;

ایجاد نود جدید با قابلیت استفاده از Tag :


var
MyNode : TMyTreeNode;
begin
MyNode := TreeView1.Items.Add(nil,'My node name') as TMyTreeNode;
MyNode.Tag := 1234;
end;


دسترسی به خصوصیت Tag یک نود خاص:


var
MyTagValue : Integer;
begin
if Assigned(TreeView1.Selected) then
MyTagValue := TMyTreeNode(TreeView1.Selected).Tag;
end;



دقت کنید که هم در ساخت نود جدید و هم در زمان دسترسی به یکی از نودهای موجود، برای دسترسی به خصوصیت Tag، باید مقدار برگشتی از TTreeView به کلاس مورد نظر ما (TMyTreeNode) تبدیل نوع (Type-cast) بشه، وگرنه به خصوصیت Tag دسترسی نخواهید داشت.

tabaprg
شنبه 28 خرداد 1390, 21:42 عصر
با تشکر فراون از شما استاد عزیز من برنامه رو تست کردم و لینکش رو برای عموم میذارم