2011-11-22 98 views
2

好吧,我一直在试图找出我犯的每一个可能的错误,但我放弃了......我需要帮助!我正在写的是一个应用程序来管理我的工作的租金,当日期过去时,我的应用程序从2个文本文件中删除名称。我写了3个小函数(过程)来完成这个工作。这里:德尔福for循环和StringList错误

这一个从dates.dat文件加载并删除包含该雇员的名称的行。

procedure remDate(emp: String);/// Removes employee from date file 
var 
    pos1, i: integer; 
    dateList: TStringList; 
begin 
    dateList:=TStringList.Create; 
    dateList.LoadFromFile('Data\dates.dat'); 
    for i:=0 to dateList.Count-1 do begin 
    pos1:=AnsiPos(emp, dateList[i]); 
    if pos1<>0 then begin 
     dateList.Delete(i); 
     dateList.SaveToFile('Data\dates.dat'); 
    end; 
    end; 
    dateList.Free; 
end; //eo remDate 

这一行从perm.dat文件中删除包含员工姓名的行。

procedure remPerm(emp: String);/// Removes employee from perm file 
var 
    pos1, i: integer; 
    permList: TStringList; 
begin 
    permList:=TStringList.Create; 
    permList.LoadFromFile('Data\perm.dat'); 
    for i:=0 to permList.Count-1 do begin 
    pos1:=AnsiPos(emp, permList[i]); 
    if pos1<>0 then begin 
     permList.Delete(i); 
     permList.SaveToFile('Data\perm.dat'); 
    end; 
    end; 
    permList.Free; 
end; //eo remPerm 

这一个坚持在一起。 isDue是一个简单的函数,它比较两个日期,如果日期是今天或已过去,则返回TRUE。

procedure updatePerms; 
var 
    empList: TStringList; 
    i: integer; 
begin 
    empList:=TStringList.Create; 
    empList.LoadFromFile('Data\employes.dat'); 
    for i:=0 to empList.Count-1 do begin 
    if isDue(empList[i]) then begin 
     remDate(empList[i]); 
     remPerm(empList[i]); (*) Here is where the error points. 
    end; 
    end; 
    empList.Free; 
end; 

时,它得到的updatePerms过程remPerm我得到的错误是。(*) 我得到一个错误EStringList,越界(#)。通过很多尝试发现,只有当员工的截止日期是今天才会发生。请评论,如果你需要更多的信息! 在此先感谢,任何帮助真的很感激!

+0

哦,顺便说一句,员工只能在一个文件中一次。 – Gab

回答

18

问题是您正在使用for循环。 for循环的终点仅在进入循环时评估一次。那时你可能有100个项目,但是一旦你开始删除,就会少一些。这将导致列表索引出界出错。

简单的解决方法是扭转for循环:

procedure remDate(emp: String); 
/// Removes employee from date file 
var 
    pos1, i: integer; 
    dateList: TStringList; 
begin 
    dateList := TStringList.Create; 
    dateList.LoadFromFile('Data\dates.dat'); 
    for i := dateList.Count - 1 downto 0 do 
    begin 
    pos1 := AnsiPos(emp, dateList[i]); 
    if pos1 <> 0 then 
    begin 
     dateList.Delete(i); 
     dateList.SaveToFile('Data\dates.dat'); 
    end; 
    end; 
    dateList.Free; 
end; // eo remDate 

如果发生一次以上的员工这将工作。

然而,如果员工确实只发生一次,就可以使用break从环路早退出:

procedure remDate(emp: String); 
/// Removes employee from date file 
var 
    pos1, i: integer; 
    dateList: TStringList; 
begin 
    dateList := TStringList.Create; 
    dateList.LoadFromFile('Data\dates.dat'); 
    for i := 0 to dateList.Count - 1 do 
    begin 
    pos1 := AnsiPos(emp, dateList[i]); 
    if pos1 <> 0 then 
    begin 
     dateList.Delete(i); 
     dateList.SaveToFile('Data\dates.dat'); 
     Break; // <-- early exit 
    end; 
    end; 
    dateList.Free; 
end; // eo remDate 

另一种解决方案是使用while循环。

+0

非常感谢!不仅你纠正了我,而且让我明白了我的错误!认为这可能是,但没有看到这么远。我改变了我为:= 0到...“downto”,它完全工作。我还注意到“休息”;备查!再次感谢! – Gab

+0

当我不得不从列表中删除东西时(stringlist,tlist),我总是使用'while'循环。从未想过为此使用'for..downto 0'。 +1好 –