-2

这是 81 个 TEdit-s (MyEdit[bx,by,x,y]) 的处理 onchange 过程,动态创建并分组在一个 4 维块中。现在我正在尝试对编辑进行编程以仅接受 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,但该程序执行并运行。每次我输入一个字母而不是一个数字 - 错误来了,我点击确定,程序完成了这项工作。但有必要消除该错误。有什么办法吗?

4

2 回答 2

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)到局部变量中。
  • 你为什么要计算bx,by和?当然是你所需要的。xySender as TEdit
  • 即使您确实必须计算这些,也不要通过MyEdit[bx,by,x,y]多次编写来重复自己。将该引用存储到局部变量中,并在任何后续引用中使用它。
  • 如果您需要计算bxby和from x,请不要在事件处理程序中内联。将该计算放入专用的辅助方法中。同样,还有一个专门的辅助方法,它朝相反的方向发展。并测试这些函数确实是彼此的倒数。yTag

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

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;
于 2012-10-15T10:10:46.407 回答
0

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


AV 原因是大卫发现的。但是在 TLama 的建议下,我将我的评论带到了答案中。


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

  • 因为这更快,有时更快(询问 TEdit.text 是询问 Windows GDI 服务,而不仅仅是读取常规变量)。
  • 因为那更可靠-在这里和那里复制相同的论坛,您可能会打错字并以不同的公式结束 u[。
  • 因为这更具前瞻性。你有一天会改变公式吗 - 你只需要在一个地方制作它,而不是搜索它的所有出现。
  • 正如大卫指出的那样,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 尺寸。

于 2012-10-15T10:40:32.603 回答