線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:4226
推到 Plurk!
推到 Facebook!

onCalcFields的事件可以只觸發一次嗎?

答題得分者是:pedro
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#1 引用回覆 回覆 發表時間:2007-07-26 11:08:51 IP:122.123.xxx.xxx 訂閱
請教各位我有一個表如下列:
SELECTED A B C D
----------------------------------------------------------------
SELECTED,A,B的資料是下SQL語法得來
C,D是我設定增加的虛擬的計算欄(New Field->Calculated)我把計算的公式都寫在onCalcFields的事件
onCalcFields事件中,C,D欄位都是又下SQL搜尋一些表做計算
第一次觸發onCalcFields事件的時候資料顯示很快...
但是我只要有加下列程式碼
while no ADOQuery1.eof do
ADOQuery1.Edit<-----這個就會觸發onCalcFields
ADOQuery1.FieldByName('SELECTED').AsInteger:=1;
ADOQuery1.Post
ADOQuery1.next
end;
每次C,D的資料又重新算過一次
這樣導致DBGrid1的資料SHOW的時候delay的很嚴重,很像當機一樣
有方法不要一直觸發onCalcFields嗎?
還是可以寫在別的事件去計算.....不過還有另外一個問題是新增的計算欄好像只能在onCalcFields使用才會出現值....
寫在其他地方...它的值都是空白...請教各位有什麼好方法嗎??
如果方便的話寫個小範例讓我可以參考一下...感謝大家^^;
編輯記錄
taishyang 重新編輯於 2007-07-26 13:29:12, 註解 將文章分類成[問題]‧
pedro
尊榮會員


發表:152
回覆:1187
積分:892
註冊:2002-06-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-07-26 11:15:34 IP:60.248.xxx.xxx 未訂閱
賦值給欄位,會觸發OnCalcFields是合理的,因為需重新計算虛擬欄位

建議可用一個旗標變數

if not EventFromProg then
做計算欄位計算
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#3 引用回覆 回覆 發表時間:2007-07-26 13:37:20 IP:210.202.xxx.xxx 訂閱
您好:
我之前有試過你說的方法
我設一個變數flag:integer
程式碼大略如下:
flag=0;
ADOQuery1.close;
ADOQuery1.sql.text:='xxxxxxx';
ADOQuery1.open;
.........
flag=1;
while not adoquery1.eof do
adoquery1.edit;
adoquery1.fieldbyname('selected').asinteger:=1;
adoquery1.post;
adoquery1.next;
end;

在adoquery1的OnCalcFields事件中

if flag=0 then
begin
做計算欄位計算
end;

但是執行出來的結果變成那些計算欄位的值都變成空白
是我哪裡寫錯...
我用的flag應該就算是你說旗標吧!!
還是你指的旗標變數是另外的變數種類



===================引 用 pedro756901 文 章===================
賦值給欄位,會觸發OnCalcFields是合理的,因為需重新計算虛擬欄位

建議可用一個旗標變數

if not EventFromProg then
做計算欄位計算
編輯記錄
lkkplayer 重新編輯於 2007-07-26 13:40:02, 註解 無‧
pedro
尊榮會員


發表:152
回覆:1187
積分:892
註冊:2002-06-12

發送簡訊給我
#4 引用回覆 回覆 發表時間:2007-07-26 14:13:17 IP:60.248.xxx.xxx 未訂閱
在while loop 之後
需把flag清為0吧?
dyming
初階會員


發表:0
回覆:11
積分:32
註冊:2003-04-21

發送簡訊給我
#5 引用回覆 回覆 發表時間:2007-07-26 17:28:27 IP:61.218.xxx.xxx 未訂閱
可將程序複雜的結果另開欄位記錄 (為加速反正規化), 寫相關的 TField.OnChange 將計算結果寫入此欄位,
因為是正式欄位, 以後取用時也方便.

要避免無謂的 OnCalcFields 事件, 您可以判斷 TField.Value 與 TField.OldValue 不同才處理, 另外,
在大量的資料移動前, DataSet 設定 AutoCalcFields = False (最好也 DisableControls), 等處理完後再將
AutoCalcFields = True 並執行一次 Edit Cancel (觸動 OnCalcFields), 若有 DisableControls 記得要
EnableControls 回來.
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#6 引用回覆 回覆 發表時間:2007-07-26 17:30:40 IP:210.202.xxx.xxx 訂閱
我依照您的意思加了
flag:=1;
while xxx do
........
end;
flag:=0; <-加這一個不夠
adoquery1.first <- 還要觸發一次 onCalcFields事件原本被清為空白的值,才會在恢復耶!!

整體的速度快多了...基本上是要減少觸發onCalcFields事件
只是還有一個也是一樣很慢
我在DBGrid1DblClick事件中所加的程式碼
flag:=1;
case ADOQuery1.FieldByName('SELECTED').AsInteger of
0 : begin
//flag:=1;
ADOQuery1.Edit;
//flag:=1;
ADOQuery1.FieldByName('SELECTED').AsInteger := 1;
flag:=0;
ADOQuery1.Post;
end;

1 : begin
//flag:=1;
ADOQuery1.Edit;
//flag:=1;
ADOQuery1.FieldByName('SELECTED').AsInteger := 0;
flag:=0;
ADOQuery1.Post;
end;
end;

點一次過很久才會變更狀態.....因為一樣會觸發onCalcFields事件這個也沒法在改了@@;
不過還是謝謝您的指導^^"

===================引 用 pedro756901 文 章===================
在while loop 之後
需把flag清為0吧?
pedro
尊榮會員


發表:152
回覆:1187
積分:892
註冊:2002-06-12

發送簡訊給我
#7 引用回覆 回覆 發表時間:2007-07-26 17:34:45 IP:60.248.xxx.xxx 未訂閱
如dyming所講的,資料結構可加開這些計算結果的欄位,以加速上下一筆調資料的速度

像訂單總計之類的
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#8 引用回覆 回覆 發表時間:2007-07-26 17:42:10 IP:210.202.xxx.xxx 訂閱
dyming,您好
我看了您的回答.....我並不是很懂您要我做的事情
如果方便的話可以寫個小程式讓我參考嗎??
===================引 用 dyming 文 章===================
可將程序複雜的結果另開欄位記錄 (為加速反正規化), 寫相關的 TField.OnChange 將計算結果寫入此欄位,
因為是正式欄位, 以後取用時也方便.

要避免無謂的 OnCalcFields 事件, 您可以判斷 TField.Value 與 TField.OldValue 不同才處理, 另外,
在大量的資料移動前, DataSet 設定 AutoCalcFields = False (最好也 DisableControls), 等處理完後再將
AutoCalcFields = True 並執行一次 Edit Cancel (觸動 OnCalcFields), 若有 DisableControls 記得要
EnableControls 回來.
VICSYS
初階會員


發表:21
回覆:64
積分:32
註冊:2002-10-10

發送簡訊給我
#9 引用回覆 回覆 發表時間:2007-07-28 00:32:25 IP:219.68.xxx.xxx 訂閱
1:以 Dataset.State 來看, 會有下列態, 會觸發 onCalcFields
dsCalcFields dsInternalCalc dsEdit dsInsert
但是您不能不去計算出該值用來顯示, 因為 CalcFields 實際上只有一筆的 Buffer
就算 dsEdit 不需要計算, 不過如果不這樣做, 您會發覺, 進入 dsEdit 時
顯示孌成空白! 只好自行把計算值保留, 再取出. 但這樣工程有點大!

2.把 ADO DatSet 改為 ClientDataSet, 利用 ClientDataSet 的 InternalCalc 的類型來解決.
InternalCalc 好像記憶體欄位一樣. 用 ClientDataSet 的彈性很大,
只不過要再加上 DataSetProvider

ClientDataSet -> DataSetProvider -> ADO DataSet
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#10 引用回覆 回覆 發表時間:2007-07-30 23:38:14 IP:218.169.xxx.xxx 訂閱
感謝大家的幫忙,我最後使用實體欄位的方法
用select A1.*,A2.A AS C,A2.B AS D FROM XXX A1,XXX A2
這樣我就會多出C,D的欄位
我就把原本寫在oncalcfield的計算都搬出來
計算一次就可以啦!!
系統時間:2024-04-26 7:24:18
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!