Delphi FMX.Treeview函数TTreeViewContent.GetLastVisibleObjectIndex中出错
我正在将VCL应用程序迁移到Firemonkey。它具有两个显示文件夹树的TTreeview控件。在主窗体的OnCreate事件处理程序中,从.Ini文件读取文件夹的路径,并设置TreeView。在主窗体出现在屏幕上之前的某个时刻,FMX.TreeView TTreeViewContent.GetLastVisibleObjectIndex函数中出现异常,即:Delphi FMX.Treeview函数TTreeViewContent.GetLastVisibleObjectIndex中出错,delphi,firemonkey,Delphi,Firemonkey,我正在将VCL应用程序迁移到Firemonkey。它具有两个显示文件夹树的TTreeview控件。在主窗体的OnCreate事件处理程序中,从.Ini文件读取文件夹的路径,并设置TreeView。在主窗体出现在屏幕上之前的某个时刻,FMX.TreeView TTreeViewContent.GetLastVisibleObjectIndex函数中出现异常,即: function TTreeViewContent.GetLastVisibleObjectIndex: Integer; var
function TTreeViewContent.GetLastVisibleObjectIndex: Integer;
var
Item: TTreeViewItem;
begin
if (FTreeView.FGlobalList.Count > 0) and (FTreeView.FLastVisibleItem < FTreeView.FGlobalList.Count) then
begin
Item := FTreeView.FGlobalList[FTreeView.FLastVisibleItem];
{etc.}
end
else
Result := ControlsCount;
end;
因为数组索引无效
此代码似乎与确定哪些treeview项目在treeview控件的滚动窗口中可见有关。由于错误发生在表单显示之前,因此我尝试在更新treview期间使treeview不可见,如下代码所示:
procedure TFormMain.UpdateTreeview(var Folder: TFolder; Treeview: TTreeview);
begin
if Folder= FInputFolder then
begin
if not FTreeviewInputFolderValid then
begin
Treeview.Visible:= False;
Treeview.BeginUpdate;
FolderToTreeView(Folder, Treeview);
//Treeview.InvalidateRect(Treeview.ContentRect);
Treeview.ExpandAll;
Treeview.EndUpdate;
Treeview.Visible:= True;
FTreeviewInputFolderValid:= True;
end;
end;
{Ditto for FOutputFolder}
end;
如果在显示表单之前未设置treeview控件而运行程序,即未从.ini文件读取文件夹路径且未更新treeview控件,则不会发生错误
关于如何避免函数TTreeViewContent.GetLastVisibleObjectIndex中出现编码错误的建议
对于Tom,FolderToTreeview的代码为:
procedure TFormMain.FolderToTreeview(Folder: TFolder; Treeview: TTreeview);
var
TreeviewOwner: TComponent;
RootNode: TTreeViewItemFolderCpt;
procedure AddFolderChildCpts(ParentTreeNode: TTreeViewItemFolderCpt; Folder: TFolder);
var
i: integer;
FolderCpt: TFolderCpt;
FileCpt: TFileCpt;
SubFolder: TFolder;
ChildTreeNode: TTreeViewItemFolderCpt;
Found: Boolean;
begin
{Add all cpts of folder to child nodes of ParentTreeNode}
for i:= 0 to Folder.CptCount-1 do
begin
FolderCpt:= Folder.Cpts[i];
ChildTreeNode:= TTreeViewItemFolderCpt.Create(ParentTreeNode);
ParentTreeNode.AddObject(ChildTreeNode);
ChildTreeNode.Parent:= ParentTreeNode;
ChildTreeNode.FolderCpt:= FolderCpt;
ChildTreeNode.OnPaint:= TreeViewItemPaint;
if FolderCpt is TFileCpt then
begin
FileCpt:= FolderCpt as TFileCpt;
ChildTreeNode.ImageIndex:= 1;
end
else if FolderCpt is TFolder then
begin
SubFolder:= FolderCpt as TFolder;
ChildTreeNode.ImageIndex:= 0;
{Recursively add subfolder:}
AddFolderChildCpts(ChildTreeNode, SubFolder);
end;
end;
end;
begin
if not Folder.IsSorted then
Folder.Sort(True);
{Delete all existing nodes in tree:}
Treeview.Clear;
{Create a new root node and add to tree:}
RootNode:= TTreeviewItemFolderCpt.Create(Treeview);
Treeview.AddObject(RootNode);
RootNode.Parent:= Treeview;
{Link folder object to root tree node:}
RootNode.FolderCpt:= Folder;
RootNode.ImageIndex:= 0;
RootNode.OnPaint:= TreeViewItemPaint;
{Now install child folder cpts:}
AddFolderChildCpts(RootNode, Folder);
end;
TFolder、tfolderpt、TFileCpt是单独类层次结构的元素,用于在内存树结构中存储根文件夹下所有文件和文件夹的名称和元数据。类TFolder的根对象有一个方法Read(Path:string),该方法通过使用FindFirst和FindNext过程访问根目录下的文件和目录来生成其所有节点。在调用FolderToTreeview之前调用Folder.Read。由于这种额外的复杂性,我认为您无法运行FolderToTreeview方法 我已经找到了我发布的问题的解决方案。FolderToTreeview方法修改如下:
procedure TFormMain.FolderToTreeview(Folder: TFolder; Treeview: TTreeview;
PaintEventHandler: TOnPaintEvent);
const
COptionA= True; {True if TreeviewItem.Clear used to destroy existing tree nodes}
COptionB= False; {True if PaintEventHandler assigned after tree nodes have been created}
var
RootNode: TTreeViewItemFolderCpt;
i: integer;
procedure AddFolderChildCpts(ParentTreeNode: TTreeViewItemFolderCpt;
Folder: TFolder; PaintEventHandler: TOnPaintEvent);
var
i: integer;
FolderCpt: TFolderCpt;
FileCpt: TFileCpt;
SubFolder: TFolder;
ChildTreeNode: TTreeViewItemFolderCpt;
begin
{Add all cpts of folder to child nodes of ParentTreeNode}
for i:= 0 to Folder.CptCount-1 do
begin
FolderCpt:= Folder.Cpts[i];
ChildTreeNode:= TTreeViewItemFolderCpt.Create(ParentTreeNode, FolderCpt);
ParentTreeNode.AddObject(ChildTreeNode);
ChildTreeNode.Parent:= ParentTreeNode;
ChildTreeNode.OnPaint:= PaintEventHandler;
if FolderCpt is TFileCpt then
begin
FileCpt:= FolderCpt as TFileCpt;
ChildTreeNode.ImageIndex:= 1;
end
else if FolderCpt is TFolder then
begin
SubFolder:= FolderCpt as TFolder;
ChildTreeNode.ImageIndex:= 0;
{Recursively add subfolder:}
AddFolderChildCpts(ChildTreeNode, SubFolder, PaintEventHandler);
end;
end;
end;
procedure SetSubNodesPaintEventHandler(ParentTreeNode: TTreeViewItem;
PaintEventHandler: TOnPaintEvent);
var
i, j: integer;
ChildTreeNodeI: TTreeViewItem;
begin
ParentTreeNode.OnPaint:= PaintEventHandler;
{Assign PaintEventHandler to all child nodes of TreeNode}
for i:= 0 to ParentTreeNode.Count-1 do
begin
ChildTreeNodeI:= ParentTreeNode.Items[i];
SetSubNodesPaintEventHandler(ChildTreeNodeI, PaintEventHandler);
end;
end;
begin
if not Folder.IsSorted then
Folder.Sort(True);
Treeview.BeginUpdate;
try
{Delete all existing nodes in tree:}
if COptionA then
Treeview.Clear
else
for i:= Treeview.Count-1 downto 0 do
Treeview.Items[i].Release;
{Create a new root node and add to tree:}
RootNode:= TTreeviewItemFolderCpt.Create(Treeview, Folder);
Treeview.AddObject(RootNode);
RootNode.Parent:= Treeview;
{Assign properties to root tree node:}
RootNode.ImageIndex:= 0;
{Now install child folder cpts:}
if COptionB then
{For testing purposes}
AddFolderChildCpts(RootNode, Folder, nil)
else
AddFolderChildCpts(RootNode, Folder, PaintEventHandler);
{Assign OnPaint event handler:}
RootNode.OnPaint:= PaintEventHandler;
if COptionB then
{For testing purposes}
SetSubNodesPaintEventHandler(RootNode, PaintEventHandler);
finally
Treeview.EndUpdate;
end;
end;
最重要的更改是将Treeview节点更新代码包含在BeginUpdate中。。。EndUpdate括号
链接到TreeviewItem的FolderCpt现在在TTreeviewItemFolderCpt构造函数中分配:
TTreeViewItemFolderCpt = class(TTreeViewItem)
protected
FFolderCpt: TFolderCpt;
procedure SetFolderCpt(const Value: TFolderCpt);
function GetName: string;
procedure SetName(Value: string);
public
constructor Create(Owner: TComponent; FolderCpt: TFolderCpt);
property FolderCpt: TFolderCpt read FFolderCpt write SetFolderCpt;
property Name: string read GetName write SetName;
end;
constructor TTreeViewItemFolderCpt.Create(Owner: TComponent;
FolderCpt: TFolderCpt);
begin
inherited Create(Owner);
FFolderCpt:= FolderCpt;
end;
您有哪个Delphi版本,以及如何将项目(在
FolderToTreeView()
中)添加到树状视图中?当我尝试在表单OnCreate
中将项目添加到树视图时,我没有问题。我有Delphi社区版。使用ChildTreeNode添加项:=TTreeViewItemFolderCpt.Create(ParentTreeNode);ParentTreeNode.AddObject(ChildTreeNode);ChildTreeNode.Parent:=ParentTreeNode;那么,Delphi 10.3.2社区版?请添加“FolderToTreeView”代码,以便我可以在调试器中跟踪它。啊,你已经编辑了你的评论。很好,但也许您可以将其添加到您的问题帖子中。您在FolderToTreeView()
中显示的几行代码不足以进行评估。太多的不确定性。GetLastVisibleObjectIndex
中没有错误,因此错误必须出现在您的代码中,而您的代码没有显示到足够的程度以便进行分析。编辑您的问题并添加FolderToTreeView()
语句中的完整代码“if(FTreeView.FGlobalList.Count>0)和(FTreeView.FLastVisibleItemTTreeViewItemFolderCpt = class(TTreeViewItem)
protected
FFolderCpt: TFolderCpt;
procedure SetFolderCpt(const Value: TFolderCpt);
function GetName: string;
procedure SetName(Value: string);
public
constructor Create(Owner: TComponent; FolderCpt: TFolderCpt);
property FolderCpt: TFolderCpt read FFolderCpt write SetFolderCpt;
property Name: string read GetName write SetName;
end;
constructor TTreeViewItemFolderCpt.Create(Owner: TComponent;
FolderCpt: TFolderCpt);
begin
inherited Create(Owner);
FFolderCpt:= FolderCpt;
end;