JSONTreeView.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. unit JSONTreeView;
  2. interface
  3. uses
  4. System.JSON, System.Generics.Collections, System.Math, System.SysUtils,
  5. System.Types, System.Classes, System.UITypes,
  6. FMX.Types, FMX.Graphics, FMX.Controls, FMX.StdCtrls, FMX.TreeView, FMX.Objects,
  7. FMX.Forms, FMX.Menus;
  8. type
  9. // 自定义的树视图项类,用于处理JSON数据
  10. TJSONTreeViewItem = class(TTreeViewItem)
  11. private
  12. FJsonData: TJSONAncestor; // 存储JSON数据
  13. FMouseDowned: Boolean; // 鼠标是否按下
  14. FMouseDownPos: TPointF; // 鼠标按下位置
  15. private
  16. // 设置JSON数据
  17. procedure SetJsonData(const AValue: TJSONAncestor);
  18. // 获取JSON值
  19. function GetJsonValue: TJSONValue;
  20. // 设置JSON值
  21. procedure SetJsonValue(const AValue: TJSONValue);
  22. // 获取键名
  23. function GetKey: string;
  24. // 获取值
  25. function GetValue: string;
  26. // 获取最后一个路径
  27. function GetLastPath: string;
  28. // 获取完整路径
  29. function GetPath: string;
  30. protected
  31. // 重载绘制函数
  32. procedure Paint; override;
  33. public
  34. property JsonData: TJSONAncestor read FJsonData write SetJsonData; // JSON数据属性
  35. property JsonValue: TJSONValue read GetJsonValue write SetJsonValue; // JSON值属性
  36. property Key: string read GetKey; // 键名属性
  37. property LastPath: string read GetLastPath; // 最后一个路径属性
  38. property Path: string read GetPath; // 完整路径属性
  39. property Value: string read GetValue; // 值属性
  40. public
  41. // 鼠标按下事件处理
  42. procedure TreeViewItemMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  43. // 鼠标移动事件处理
  44. procedure TreeViewItemMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
  45. // 鼠标释放事件处理
  46. procedure TreeViewItemMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  47. public
  48. // 构造函数
  49. constructor Create(AOwner: TComponent); override;
  50. // 获取第一个子项
  51. function First: TJSONTreeViewItem;
  52. // 获取最后一个子项
  53. function Last: TJSONTreeViewItem;
  54. // 获取层级
  55. function Level: integer;
  56. // 是否有子项
  57. function HasSubItem: Boolean;
  58. // 是否有选中的子项
  59. function HasSUbItemIsSelected: Boolean;
  60. // 获取父项
  61. function MyParentItem: TJSONTreeViewItem;
  62. // 移除子项
  63. procedure RemoveItem(const AItem: TJSONTreeViewItem; AReTextSubItem: Boolean = False);
  64. // 从父项中提取
  65. function ExtractFromParent(AParentReTextSubItem: Boolean = False): TJSONTreeViewItem;
  66. // 添加子项
  67. procedure AddItem(const AItem: TJSONTreeViewItem; AItemReText: Boolean = False);
  68. // 插入子项
  69. procedure InsertItem(const AIndex: integer; const AItem: TJSONTreeViewItem;
  70. AReTextSubItem: Boolean = False);
  71. // 移动子项
  72. procedure MoveItem(const ACurIndex, ANewIndex: integer; AReTextSubItem: Boolean = False);
  73. // 清除子条目
  74. procedure ClearItem;
  75. // 重新设置文本
  76. procedure ReText;
  77. // 重新设置所有子项的文本
  78. procedure ReTextSubItem;
  79. end;
  80. // 设置树视图项,递归地将JSON数据添加到树视图中
  81. procedure SetTreeItem(const AParentItem: TStyledControl; const AJData: TJSONAncestor; APopupMenu: TPopupMenu = nil);
  82. procedure SetTreeItems(const AParentItem: TStyledControl; const AJData: TJSONAncestor; APopupMenu: TPopupMenu = nil);
  83. implementation
  84. uses pub, jsonhelper, Logger;
  85. ////////////////////////////////////////////////////////////////////////////////
  86. // 为树形控件的项目设置JSON数据和PopupMenu
  87. ////////////////////////////////////////////////////////////////////////////////
  88. procedure SetTreeItem(const AParentItem: TStyledControl; const AJData: TJSONAncestor; APopupMenu: TPopupMenu);
  89. var
  90. tvItem: TJSONTreeViewItem;
  91. begin
  92. tvItem := TJSONTreeViewItem.Create(nil);
  93. AParentItem.AddObject(tvItem);
  94. tvItem.PopupMenu := APopupMenu;
  95. tvItem.JsonData := AJData;
  96. for var i := 0 to tvItem.JsonValue.ItemCount - 1 do
  97. begin
  98. SetTreeItem(tvItem, tvItem.JsonValue.Items[i]);
  99. end;
  100. end;
  101. procedure SetTreeItems(const AParentItem: TStyledControl; const AJData: TJSONAncestor; APopupMenu: TPopupMenu = nil);
  102. begin
  103. if AJData is TJSONObject then
  104. begin
  105. for var i := 0 to TJSONObject(AJData).Count - 1 do
  106. begin
  107. SetTreeItem(AParentItem, TJSONObject(AJData).Pairs[i]);
  108. end;
  109. end
  110. else if AJData is TJSONArray then
  111. begin
  112. for var i := 0 to TJSONArray(AJData).Count - 1 do
  113. begin
  114. SetTreeItem(AParentItem, TJSONArray(AJData)[i]);
  115. end;
  116. end;
  117. end;
  118. ////////////////////////////////////////////////////////////////////////////////
  119. // TJSONTreeViewItem类的构造函数
  120. ////////////////////////////////////////////////////////////////////////////////
  121. constructor TJSONTreeViewItem.Create(AOwner: TComponent);
  122. begin
  123. inherited;
  124. FJsonData := nil;
  125. OnMouseDown := TreeViewItemMouseDown;
  126. OnMouseMove := TreeViewItemMouseMove;
  127. OnMouseUp := TreeViewItemMouseUp;
  128. end;
  129. ////////////////////////////////////////////////////////////////////////////////
  130. // 获取JSONTreeViewItem的第一个子项
  131. ////////////////////////////////////////////////////////////////////////////////
  132. function TJSONTreeViewItem.First: TJSONTreeViewItem;
  133. begin
  134. if Count > 0 then
  135. Result := TJSONTreeViewItem(Items[0])
  136. else
  137. Result := nil;
  138. end;
  139. ////////////////////////////////////////////////////////////////////////////////
  140. // 获取JSONTreeViewItem的最后一个子项
  141. ////////////////////////////////////////////////////////////////////////////////
  142. function TJSONTreeViewItem.Last: TJSONTreeViewItem;
  143. begin
  144. if Count > 0 then
  145. Result := TJSONTreeViewItem(Items[Count - 1])
  146. else
  147. Result := nil;
  148. end;
  149. ////////////////////////////////////////////////////////////////////////////////
  150. // 获取JSONTreeViewItem的层级深度
  151. ////////////////////////////////////////////////////////////////////////////////
  152. function TJSONTreeViewItem.Level: integer;
  153. var
  154. LCurItem: TJSONTreeViewItem;
  155. begin
  156. Result := 0;
  157. LCurItem := self;
  158. while LCurItem.ParentItem <> nil do
  159. begin
  160. Inc(Result);
  161. LCurItem := LCurItem.MyParentItem;
  162. end;
  163. end;
  164. ////////////////////////////////////////////////////////////////////////////////
  165. // 判断JSONTreeViewItem是否有子项
  166. ////////////////////////////////////////////////////////////////////////////////
  167. function TJSONTreeViewItem.HasSubItem: Boolean;
  168. begin
  169. Result := Count > 0;
  170. end;
  171. ////////////////////////////////////////////////////////////////////////////////
  172. // 判断JSONTreeViewItem是否有被选中的子项
  173. ////////////////////////////////////////////////////////////////////////////////
  174. function TJSONTreeViewItem.HasSUbItemIsSelected: Boolean;
  175. begin
  176. Result := False;
  177. for var i := 0 to Count - 1 do
  178. begin
  179. if Items[i].IsSelected then
  180. Exit(True);
  181. end;
  182. end;
  183. ////////////////////////////////////////////////////////////////////////////////
  184. // 获取当前项的父项
  185. ////////////////////////////////////////////////////////////////////////////////
  186. function TJSONTreeViewItem.MyParentItem: TJSONTreeViewItem;
  187. begin
  188. Result := TJSONTreeViewItem(ParentItem);
  189. end;
  190. ////////////////////////////////////////////////////////////////////////////////
  191. // 从当前项中移除子项
  192. ////////////////////////////////////////////////////////////////////////////////
  193. procedure TJSONTreeViewItem.RemoveItem(const AItem: TJSONTreeViewItem; AReTextSubItem: Boolean = False);
  194. begin
  195. if JsonValue is TJSONObject then
  196. begin
  197. TJSONObject(JsonValue).DeletePair(TJSONPair(AItem.FJsonData));
  198. RemoveObject(AItem);
  199. end
  200. else if JsonValue is TJSONArray then
  201. begin
  202. TJSONArray(JsonValue).Delete(AItem.JsonValue);
  203. RemoveObject(AItem);
  204. if AReTextSubItem then
  205. begin
  206. ReTextSubItem;
  207. end;
  208. end
  209. else
  210. begin
  211. raise Exception.Create('TJSONTreeViewItem.RemoveItem: must be TJSONObject or TJSONArray');
  212. end;
  213. end;
  214. ////////////////////////////////////////////////////////////////////////////////
  215. // 从父项中提取当前项
  216. ////////////////////////////////////////////////////////////////////////////////
  217. function TJSONTreeViewItem.ExtractFromParent(AParentReTextSubItem: Boolean = False): TJSONTreeViewItem;
  218. begin
  219. Result := TJSONTreeViewItem(ParentItem);
  220. if Result <> nil then
  221. Result.RemoveItem(self, AParentReTextSubItem);
  222. end;
  223. ////////////////////////////////////////////////////////////////////////////////
  224. // 向当前项中添加子项
  225. ////////////////////////////////////////////////////////////////////////////////
  226. procedure TJSONTreeViewItem.AddItem(const AItem: TJSONTreeViewItem; AItemReText: Boolean = False);
  227. var
  228. LValue: TJSONValue;
  229. begin
  230. if JsonValue is TJSONObject then
  231. begin
  232. if not(AItem.JsonData is TJSONPair) then
  233. begin
  234. AItem.JsonData := TJSONPair.Create('untitled', AItem.JsonValue);
  235. end;
  236. TJSONObject(JsonValue).AddPair(TJSONPair(AItem.JsonData));
  237. end
  238. else if JsonValue is TJSONArray then
  239. begin
  240. if AItem.JsonData is TJSONPair then
  241. begin
  242. LValue := AItem.JsonValue;
  243. LValue.Owned := False;
  244. FreeAndNil(AItem.JsonData);
  245. LValue.Owned := True;
  246. AItem.JsonData := LValue;
  247. end;
  248. TJSONArray(JsonValue).AddElement(AItem.JsonValue);
  249. end;
  250. AddObject(AItem);
  251. if AItemReText then
  252. begin
  253. AItem.ReText;
  254. end;
  255. end;
  256. ////////////////////////////////////////////////////////////////////////////////
  257. // 在当前JSON树视图项中插入一个新项
  258. ////////////////////////////////////////////////////////////////////////////////
  259. procedure TJSONTreeViewItem.InsertItem(const AIndex: integer; const AItem: TJSONTreeViewItem; AReTextSubItem: Boolean = False);
  260. var
  261. LValue: TJSONValue;
  262. begin
  263. if JsonValue is TJSONObject then
  264. begin
  265. if not(AItem.JsonData is TJSONPair) then
  266. begin
  267. AItem.JsonData := TJSONPair.Create('untitled', AItem.JsonValue);
  268. end;
  269. TJSONObject(JsonValue).InsertPair(AIndex, TJSONPair(AItem.JsonData));
  270. InsertObject(AIndex, AItem);
  271. AItem.ReText;
  272. end
  273. else if JsonValue is TJSONArray then
  274. begin
  275. if AItem.JsonData is TJSONPair then
  276. begin
  277. LValue := AItem.JsonValue;
  278. LValue.Owned := False;
  279. FreeAndNil(AItem.JsonData);
  280. LValue.Owned := True;
  281. AItem.JsonData := LValue;
  282. end;
  283. TJSONArray(JsonValue).InsertElement(AIndex, AItem.JsonValue);
  284. InsertObject(AIndex, AItem);
  285. if AReTextSubItem then
  286. begin
  287. ReTextSubItem;
  288. end;
  289. end;
  290. end;
  291. ////////////////////////////////////////////////////////////////////////////////
  292. // 移动JSON树视图项的位置
  293. ////////////////////////////////////////////////////////////////////////////////
  294. procedure TJSONTreeViewItem.MoveItem(const ACurIndex, ANewIndex: integer; AReTextSubItem: Boolean = False);
  295. var
  296. LItem: TJSONTreeViewItem;
  297. begin
  298. if JsonValue is TJSONObject then
  299. begin
  300. TJSONObject(JsonValue).Move(ACurIndex, ANewIndex);
  301. LItem := TJSONTreeViewItem(Items[ACurIndex]);
  302. RemoveObject(LItem);
  303. InsertObject(ANewIndex, LItem);
  304. end
  305. else
  306. begin
  307. TJSONArray(JsonValue).Move(ACurIndex, ANewIndex);
  308. LItem := TJSONTreeViewItem(Items[ACurIndex]);
  309. RemoveObject(LItem);
  310. InsertObject(ANewIndex, LItem);
  311. if AReTextSubItem then
  312. begin
  313. ReTextSubItem;
  314. end;
  315. end;
  316. end;
  317. ////////////////////////////////////////////////////////////////////////////////
  318. // 清除子条目
  319. ////////////////////////////////////////////////////////////////////////////////
  320. procedure TJSONTreeViewItem.ClearItem;
  321. begin
  322. for var i := Count - 1 downto 0 do
  323. begin
  324. Items[i].Free;
  325. end;
  326. end;
  327. ////////////////////////////////////////////////////////////////////////////////
  328. // 处理JSON树视图项的鼠标按下事件
  329. ////////////////////////////////////////////////////////////////////////////////
  330. procedure TJSONTreeViewItem.TreeViewItemMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  331. begin
  332. if (Button = TMouseButton.mbLeft) and (ParentItem <> nil) then
  333. begin
  334. FMouseDownPos := Screen.MousePos;
  335. FMouseDowned := True;
  336. end
  337. else
  338. begin
  339. FMouseDowned := False;
  340. end;
  341. end;
  342. ////////////////////////////////////////////////////////////////////////////////
  343. // 处理JSON树视图项的鼠标移动事件
  344. ////////////////////////////////////////////////////////////////////////////////
  345. procedure TJSONTreeViewItem.TreeViewItemMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
  346. begin
  347. if FMouseDowned then
  348. begin
  349. if not(ssLeft in Shift) then
  350. begin
  351. FMouseDowned := False;
  352. end
  353. else if FMouseDowned and ((Abs(FMouseDownPos.X - Screen.MousePos.X) > 4) or (Abs(FMouseDownPos.Y - Screen.MousePos.Y) > 2)) then
  354. begin
  355. BeginAutoDrag;
  356. end;
  357. end;
  358. end;
  359. ////////////////////////////////////////////////////////////////////////////////
  360. // 处理鼠标抬起事件
  361. ////////////////////////////////////////////////////////////////////////////////
  362. procedure TJSONTreeViewItem.TreeViewItemMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  363. begin
  364. FMouseDowned := False;
  365. end;
  366. ////////////////////////////////////////////////////////////////////////////////
  367. // 绘制树视图项
  368. ////////////////////////////////////////////////////////////////////////////////
  369. procedure TJSONTreeViewItem.Paint;
  370. const
  371. c_add_line = {$IFDEF MACOS}0{$ELSE}1{$ENDIF};
  372. c_color_default = $FF808080;
  373. c_color_brother = $FFFF8080;
  374. c_color_sub = $FF00AA00;
  375. var
  376. LParentItem, LCurItem: TJSONTreeViewItem;
  377. LLeft: Single;
  378. begin
  379. inherited;
  380. if ParentItem <> nil then
  381. begin
  382. LParentItem := MyParentItem;
  383. Canvas.Stroke.Kind := TBrushKind.Solid;
  384. Canvas.Stroke.Thickness := 1.0;
  385. // 根据父项的状态设置绘制颜色
  386. if LParentItem.IsSelected then
  387. Canvas.Stroke.Color := c_color_sub
  388. else if LParentItem.HasSUbItemIsSelected then
  389. Canvas.Stroke.Color := c_color_brother
  390. else
  391. Canvas.Stroke.Color := c_color_default;
  392. // 绘制连接线
  393. Canvas.DrawLine(PointF(0, c_add_line), PointF(0, LocalRect.Height / IfThen(self = LParentItem.Last, 2, 1)), 1.0);
  394. Canvas.DrawLine(PointF(c_add_line, LocalRect.Height / 2), PointF(IfThen(HasSubItem, 7.5, 15), LocalRect.Height / 2), 1.0);
  395. LLeft := 0;
  396. LCurItem := LParentItem;
  397. // 绘制父项及其所有子项的连接线
  398. while LCurItem.ParentItem <> nil do
  399. begin
  400. LLeft := LLeft - 20;
  401. LParentItem := LCurItem.MyParentItem;
  402. if (LCurItem <> LParentItem.Last) and LParentItem.IsExpanded then
  403. begin
  404. if LParentItem.IsSelected then
  405. Canvas.Stroke.Color := c_color_sub
  406. else if LParentItem.HasSUbItemIsSelected then
  407. Canvas.Stroke.Color := c_color_brother
  408. else
  409. Canvas.Stroke.Color := c_color_default;
  410. Canvas.DrawLine(PointF(LLeft, c_add_line), PointF(LLeft, LocalRect.Bottom), 1.0);
  411. end;
  412. LCurItem := LParentItem;
  413. end;
  414. end;
  415. end;
  416. ////////////////////////////////////////////////////////////////////////////////
  417. // 获取JSON值
  418. ////////////////////////////////////////////////////////////////////////////////
  419. function TJSONTreeViewItem.GetJsonValue: TJSONValue;
  420. begin
  421. if FJsonData is TJSONPair then
  422. Result := TJSONPair(FJsonData).JsonValue
  423. else
  424. Result := TJSONValue(FJsonData);
  425. end;
  426. ////////////////////////////////////////////////////////////////////////////////
  427. // 设置JSON值
  428. ////////////////////////////////////////////////////////////////////////////////
  429. procedure TJSONTreeViewItem.SetJsonValue(const AValue: TJSONValue);
  430. var
  431. LArr: TJSONArray;
  432. LIndex: integer;
  433. begin
  434. if FJsonData is TJSONPair then
  435. begin
  436. TJSONPair(FJsonData).JsonValue := AValue;
  437. end
  438. else
  439. begin
  440. if ParentItem <> nil then
  441. begin
  442. LArr := TJSONArray(TJSONTreeViewItem(ParentItem).JsonValue);
  443. LIndex := LArr.IndexOf(JsonValue);
  444. LArr.SetValue(LIndex, AValue);
  445. end;
  446. FJsonData := AValue;
  447. end;
  448. ImageIndex := Ord(AValue.JsonKind);
  449. end;
  450. ////////////////////////////////////////////////////////////////////////////////
  451. // 获取JSON键
  452. ////////////////////////////////////////////////////////////////////////////////
  453. function TJSONTreeViewItem.GetKey: string;
  454. begin
  455. if FJsonData is TJSONPair then
  456. begin
  457. Result := TJSONPair(FJsonData).JsonString.Value;
  458. end
  459. else
  460. begin
  461. Result := '';
  462. end;
  463. end;
  464. ////////////////////////////////////////////////////////////////////////////////
  465. // 获取JSON值的字符串表示
  466. ////////////////////////////////////////////////////////////////////////////////
  467. function TJSONTreeViewItem.GetValue: string;
  468. begin
  469. Result := GetJsonValue.Value;
  470. end;
  471. ////////////////////////////////////////////////////////////////////////////////
  472. // 获取当前项的最后路径
  473. ////////////////////////////////////////////////////////////////////////////////
  474. function TJSONTreeViewItem.GetLastPath: string;
  475. begin
  476. if ParentItem = nil then
  477. begin
  478. Exit('');
  479. end;
  480. if FJsonData is TJSONPair then
  481. begin
  482. Result := TJSONPair(FJsonData).JsonString.Value;
  483. end
  484. else
  485. begin
  486. Result := '[' + Index.ToString + ']';
  487. end;
  488. end;
  489. ////////////////////////////////////////////////////////////////////////////////
  490. // 获取当前项的完整路径
  491. ////////////////////////////////////////////////////////////////////////////////
  492. function TJSONTreeViewItem.GetPath: string;
  493. var
  494. tmpStr: string;
  495. ptItem: TJSONTreeViewItem;
  496. begin
  497. ptItem := TJSONTreeViewItem(ParentItem);
  498. if ptItem = nil then
  499. Exit('');
  500. tmpStr := GetLastPath;
  501. while ptItem.ParentItem <> nil do
  502. begin
  503. if ptItem.JsonValue is TJSONObject then
  504. begin
  505. tmpStr := ptItem.GetLastPath + '.' + tmpStr;
  506. end
  507. else
  508. begin
  509. tmpStr := ptItem.GetLastPath + tmpStr;
  510. end;
  511. ptItem := TJSONTreeViewItem(ptItem.ParentItem);
  512. end;
  513. Result := tmpStr;
  514. end;
  515. ////////////////////////////////////////////////////////////////////////////////
  516. // 设置JSON数据
  517. ////////////////////////////////////////////////////////////////////////////////
  518. procedure TJSONTreeViewItem.SetJsonData(const AValue: TJSONAncestor);
  519. begin
  520. if FJsonData = AValue then
  521. Exit;
  522. FJsonData := AValue;
  523. ReText;
  524. end;
  525. ////////////////////////////////////////////////////////////////////////////////
  526. // 重新设置文本
  527. ////////////////////////////////////////////////////////////////////////////////
  528. procedure TJSONTreeViewItem.ReText;
  529. begin
  530. Text := GetLastPath + ': ' + JsonValue.Value;
  531. ImageIndex := Ord(JsonValue.JsonKind);
  532. if JsonValue.ClassType = TJSONString then
  533. begin
  534. Text := Text.Replace(#13, '\r').Replace(#10, '\n');
  535. if Text.Length > 100 then
  536. begin
  537. Text := Text.Substring(0, 100) + ' ...';
  538. end;
  539. end;
  540. end;
  541. ////////////////////////////////////////////////////////////////////////////////
  542. // 重新设置所有子项的文本
  543. ////////////////////////////////////////////////////////////////////////////////
  544. procedure TJSONTreeViewItem.ReTextSubItem;
  545. begin
  546. for var i := 0 to Count - 1 do
  547. begin
  548. TJSONTreeViewItem(Items[i]).ReText;
  549. end;
  550. end;
  551. end.