AVE:模块中的访问冲突@adress:DELPHI7

时间:2012-10-15 10:03:36

标签: delphi delphi-7 access-violation

这是81个TEdit-s(MyEdit [bx,by,x,y])处理的onchange过程,动态创建并以4维海量分组。现在我正在尝试编辑Edits只接受1位数。 “仅数字”部分正常工作,但“仅1位”部分提供访问冲突错误(AVE)。代码:

procedure TForm1.OnHandleChange(Sender: TObject);
var
bx,by,x,y,len : Integer;
begin
bx:=(sender as TEdit).tag div 1000;
by:=(sender as TEdit).tag div 100-10*bx;
x:=(sender as TEdit).tag div 10-100*bx-10*by;
y:=(sender as TEdit).tag-bx*1000-by*100-x*10;
{*The line below gives the error*} 
if not (MyEdit[bx,by,x,y].text[1] in ['1'..'9']) then MyEdit[bx,by,x,y].text:='';
MyEdit[bx,by,x,y].SelStart:=length(MyEdit[bx, by, x,y].text);
if length(MyEdit[bx, by, x,y].text) >1
              then MyEdit[bx,by,x,y].text:=MyEdit[bx,by,x,y].text[2];
end;

虽然有AVE,程序仍会执行并运行。每次我输入一个字母而不是一个数字 - 错误来了,我点击确定,程序完成工作。但有必要删除该错误。有什么办法吗?

2 个答案:

答案 0 :(得分:3)

MyEdit[bx,by,x,y].text[1]假设编辑框文本非空,即至少有1个单个字符。当编辑框文本为空时,Text属性为空字符串,访问第一个字符会导致访问冲突。

我注意到你明确地将编辑框文本设置为空字符串,当然用户可以这样做。所以你当然必须警惕这种可能性。

通过检查编辑框是否为空来解决问题。

var
  Text: string;
....
Text := MyEdit[bx,by,x,y].Text;
if (Length(Text)=1) and (Text[1] in ['1'..'9']) then
  ....

访问冲突的另一个可能的候选者是MyEdit[bx,by,x,y]是否导致对阵列的越界访问。也许你的Tag字段的数学都搞砸了。这看起来很奇怪。

正如我在下面所述,Sender as TEdit似乎在这里更有意义。


更多一般性评论:

  • 您确实需要将演示文稿(即GUIm)与基础数据分开。你真的不想用4D视觉控件数组作为输入数据来解决。
  • 不要继续重复(Sender as TEdit).tag。将该值读入局部变量一次。或者可能将(Sender as TEdit)存储到本地变量中。
  • 为什么要计算bxbyxy?当然Sender as TEdit就是你所需要的。
  • 即使你必须计算这些,也不要多次写MyEdit[bx,by,x,y]来重复自己。将该引用存储到本地变量中,并在随后的任何引用中使用它。
  • 如果您需要从bx计算byxyTag,请不要在事件处理程序中对其进行内联。将该计算放在专用的辅助方法中。同样是一个专门的辅助方法,它朝着相反的方向发展。并测试这些功能确实是相互反转的。

举个例子,这些助手可能如下所示:

procedure PackCoordinates(const bx, by, x, y: Byte; out Tag: Integer);
begin
  LongRec(Tag).Bytes[0] := bx;
  LongRec(Tag).Bytes[1] := by;
  LongRec(Tag).Bytes[2] := x;
  LongRec(Tag).Bytes[3] := y;
end;

procedure UnpackCoordinates(const Tag: Integer; out bx, by, x, y: Byte);
begin
  bx := LongRec(Tag).Bytes[0];
  by := LongRec(Tag).Bytes[1];
  x := LongRec(Tag).Bytes[2];
  y := LongRec(Tag).Bytes[3];
end;

答案 1 :(得分:0)

为什么需要那个处理程序?只需设置TMaskEdit的掩码即可。 '9'似乎是你需要的。


AV原因是David发现的。但在TLama建议中,我将我的意见带回答。


还有DRY principle。不要一次又一次地做计算。做一次并记住结果。

  • 因为速度更快,有时速度更快(要求TEdit.text询问Windows GDI服务,这不只是阅读常规变量)。
  • 因为那更可靠 - 在这里和那里复制相同的论坛,你可能会输入错误并结束你[使用不同的公式。
  • 因为这更具有前瞻性。你有一天会改变这个公式 - 你必须只在一个地方制作它,而不是搜索它的所有出现。
  • 大卫指出,Sender已经是你的编辑了。没有必要再次搜索它了!

不要繁殖和删除 - 这些操作很昂贵。特别是当您删除10而不是2,4,8,16,...

并且不管怎么说 - 你可以在这里使用类型转换自然地分割值。


使用4D阵列非常奇怪。非常。你真的需要吗?


总而言之,归结为

type TTagSplit = packed record 
                        case byte of
                             0: (Tag: integer);   
                             1: (bx, by, x, y: byte);  end; 

procedure CreatingEdits...
var tt: TTagSplit; e: TEdit;
begin
    for ... do begin
        e := TEdit.Create(MainForm);
        ....
        tt.bx := ...; tt. by := ....
        e.Tag := tt.Tag;
    end;
end;

procedure TForm1.OnHandleChange(Sender: TObject);
var
    bx,by,x,y,len : Integer;
    e : TEdit; txt: string;
    tt: TTagSplit;
begin
    e := Sender as TEdit;
    tt.Tag := e.Tag;
    bx := tt.bx; by := ....
    // Here you do not need those bx and rest - just demo how to get them

    txt := e.Text;

    if length(txt) > 1 
       then e.Text := txt[2] 
       else
         if txt > '' then 
            if not (txt[1]  in ['1'..'9'])
               then e.Text := '';
end;

但是带来简历 - 只需使用TMaskEdit就可以使所有代码都不需要。 TMaskedit本身会检查内容是一位数还是空位。唯一要检查的是数字不为零。


樱桃到那个馅饼 - 你根本不需要81个编辑盒!您应该将一个TStringGrid设置为9x9大小。