2012-10-15 91 views
-2

這是81個TEdit-s(MyEdit [bx,by,x,y])處理的onchange過程,動態創建並分組爲4維海量。現在我試圖編輯編輯接受只有1位數字。 「只有數字」部分正常工作,但「僅1位數」部分給出訪問衝突錯誤(AVE)。代碼:AVE:訪問衝突模塊中的@adress:DELPHI7

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,程序仍然執行並工作。每次我輸入一個字母而不是一個數字 - 出現錯誤,我點擊確定,程序完成這項工作。但有必要刪除該錯誤。有什麼辦法嗎?

+0

哎呀,抱歉有一點小錯誤。 「僅1位數」部分正常工作,但「只有數字」部分給出錯誤。請參閱以IF NOT開頭的行。謝謝 –

+0

最好在編輯框的OnKey事件中測試數字。 –

+0

@Keith - 他根本不應該使用任何關鍵事件! TMaskEdit只是開箱即用。 –

回答

3

MyEdit[bx,by,x,y].text[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]導致一個出的陣列的邊界的訪問。也許你的數學與標籤領域都搞砸了。我看起來很奇怪。

正如我在下面所述,Sender as TEdit似乎在這裏更有意義。


更多一般性評論:

  • 你真的需要演示,即GUIm從底層數據分開。你真的不想用四維視覺控制陣列作爲你的輸入數據。
  • 不要繼續重複(Sender as TEdit).tag。將該值讀入局部變量。或者,也可以將(Sender as TEdit)存儲到局部變量中。
  • 爲什麼要計算bx,by,xy呢?當然Sender as TEdit是你所需要的。
  • 即使你必須計算這些,不要再多次寫MyEdit[bx,by,x,y]來重複自己。將該引用存儲到局部變量中,並在後續引用中使用該引用。
  • 如果你需要計算bxby,從Tagxy,不要在一個事件處理程序做內聯。把這個計算放在一個專門的輔助方法中。同樣也是一種專門的幫手方法,它的方向相反。並測試這些函數確實是相互顛倒的。

給你舉個例子,那些助手看起來是這樣的:

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; 
+0

@ Arioch'The我不聽你的評論。請詳細說明。 –

+0

好的,我糾正了你在這裏所說的事情,謝謝。但主要問題仍然存在,我嘗試了David的代碼,錯誤仍然存​​在。 –

+0

調用.text在這裏和那裏而不是緩存是比'as'和數組引用'MyEdit [bx,by,x,y]'更昂貴的操作。作爲第一優化步驟,與OS的交互作用將被最小化。本地TEXT變量是必需的。 –

0

爲什麼需要一個處理程序呢?只需設置TMaskEdit的掩碼即可。 '9'似乎是你需要的。


AV的理由是大衛的地方。但是在TLama的建議中,我將我的評論帶給了答案。


還有DRY principle。不要一次又一次地進行計算。做一次並記住結果。

  • 因爲速度更快,所以有時要快得多(要求TEdit.text詢問Windows GDI服務,這不僅僅是讀取常規變量)。
  • 因爲這是更可靠的 - 複製相同的論壇在這裏和那裏你可能會打字錯誤和結束你[用不同的公式。
  • 因爲這是更具前瞻性的。你有一天會改變公式 - 你只能在一個地方完成,而不是搜索它的所有事件。
  • 正如David指出的那樣,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大小。

+0

好Arioch我需要4個維度,因爲在檢查數獨時,我們需要檢查行,行和3x3塊。這就是爲什麼我把它們分組在4dim中。可以說我想檢查位於該區域最中間的第五個3x3區塊。沒有辦法解釋程序將它們按9 3x3分組並檢查解決方案。 –

+0

然後,你需要特殊的一維數組爲這些行,行和塊(也有對角線AFAIR)。可能是Integer而不是TEdit的數組。你在那個巨型陣列中究竟搜索什麼,以及如何搜索? –

+0

'TTagSplit'是一個好主意,但它已經存在。它是SysUtils.LongRec。 –