 |
VFP 愛用者社區 本討論區為 Visual Foxpro 愛用者經驗交流的地方, 請多多利用"搜尋"的功能, 先查看看有無前例可循, 如果還有不懂的再發問. 部份主題有附加檔案, 須先註冊成為社區居民才可以下載.
|
上一篇主題 :: 下一篇主題 |
發表人 |
內容 |
小賴
註冊時間: 2004-12-27 文章: 476
第 16 樓
|
發表於: 星期四 九月 05, 2013 2:53 am 文章主題: |
|
|
直接使用Jerryclt原程式碼(一樓) 與CKP6250資料庫(6樓)實現每200筆顯示進度:
Select * From 傳票檔 ;
WHERE ((MOD(RECNO(), 200) = 1 OR RECNO() >= RECCOUNT() - 60) AND progress_bar(RECNO()*100/RECCOUNT(),'處理進度.... '+TRANSFORM(INT(RECNO()*100/RECCOUNT()))+'%') AND .F.);
OR (! DELETED() AND BETWEEN(Date ,'0901','0930')) INTO Cursor AA
簡化條件 (A AND B AND C) OR D
說明如下
A. (MOD(RECNO(), 200) = 1 OR RECNO() >= RECCOUNT() - 60) //每200筆或最後60筆才顯示
B. progress_bar(RECNO()* .... //顯示進度
C. .F.
D. WHERE 條件
X. (A AND B AND C) // 每200筆或最後60筆顯示進度並傳回.F. ; 只有當A = .F. 電腦才會判讀B
Y. X OR D //因為 X = .F. 所以 X OR D之結果為D 也就是WHERE 條件之結果 |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 17 樓
|
發表於: 星期四 九月 05, 2013 7:31 am 文章主題: |
|
|
小賴 寫到: | ~43 ~
A. (MOD(RECNO(), 200) = 1 OR RECNO() >= RECCOUNT() - 60) //每200筆或最後60筆才顯示
B. progress_bar(RECNO()* .... //顯示進度
C. .F.
D. WHERE 條件
X. (A AND B AND C) // 每200筆或最後60筆顯示進度並傳回.F. ; 只有當A = .F. 電腦才會判讀B
Y. X OR D //因為 X = .F. 所以 X OR D之結果為D 也就是WHERE 條件之結果 |
紅色部份是不是寫錯?
乍看之下好像真的會減少 progress_bar 執行的次數,
只不知 WHERE 子句的複雜化,會不會拖慢 SELECT-SQL,
小弟來試試先,
謝謝小賴兄的指點! |
|
回頂端 |
|
 |
ckp6250
註冊時間: 2004-07-30 文章: 1645
第 18 樓
|
發表於: 星期四 九月 05, 2013 7:56 am 文章主題: |
|
|
不用測試,光用看的就看得出來
肯定拖慢 SELECT-SQL
因為,單是判斷第一個條件
MOD(RECNO(), 200) = 1
就必需掃描整個資料庫了,VFP的OPTIMIZE完全用不上 |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 19 樓
|
發表於: 星期四 九月 05, 2013 8:45 am 文章主題: |
|
|
大功告成 !!
原始碼已修正如下:
* 進度條函數
PROCEDURE progress_bar
LPARAMETERS val1
IF val1>0 AND val1<=100
IF TYPE('ctln')#'O'
PUBLIC ctln
ctln=CREATEOBJECT('my_progress')
ctln.show()
ENDIF
ctln.show_progress(INT(val1))
IF val1>=100
RELEASE ctln
ENDIF
ENDIF
RETURN .F.
ENDPROC
* 自訂進度條視窗
DEFINE CLASS my_progress AS FORM
AlwaysOnTop=.T.
AutoCenter=.T.
BorderStyle=2
Caption=''
Closable=.F.
ControlBox=.F.
Height=70
MaxButton=.F.
MinButton=.F.
Movable=.F.
Name='my_progress'
ShowTips=.T.
ShowWindow=1
Width=350
WindowType=0
ADD OBJECT __OutUpLine AS line WITH;
BorderWidth=1,;
Height=0,;
Left=4,;
Top=4,;
Width=342,;
BorderColor=RGB(0,0,0),;
ZOrderSet=3,;
Name='__OutUpLine'
ADD OBJECT __OutDownLine AS line WITH;
BorderWidth=1,;
Height=0,;
Left=4,;
Top=66,;
Width=342,;
BorderColor=RGB(255,255,255),;
ZOrderSet=6,;
Name='__OutDownLine'
ADD OBJECT __OutLeftLine AS line WITH;
BorderWidth=1,;
Height=62,;
Left=4,;
Top=4,;
Width=0,;
BorderColor=RGB(0,0,0),;
ZOrderSet=4,;
Name='__OutLeftLine'
ADD OBJECT __OutRightLine AS line WITH;
BorderWidth=1,;
Height=62,;
Left=346,;
Top=4,;
Width=0,;
BorderColor=RGB(255,255,255),;
ZOrderSet=5,;
Name='__OutRightLine'
ADD OBJECT __InUpLine AS line WITH;
Height=0,;
Left=21,;
Top=31,;
Width=309,;
BorderColor=RGB(0,0,0),;
ZOrderSet=7,;
Name='__InUpLine'
ADD OBJECT __InDownLine AS line WITH;
Height=0,;
Left=21,;
Top=59,;
Width=309,;
BorderColor=RGB(255,255,255),;
ZOrderSet=10,;
Name='__InDownLine'
ADD OBJECT __InLeftLine AS line WITH;
Height=28,;
Left=21,;
Top=31,;
Width=0,;
BorderColor=RGB(0,0,0),;
ZOrderSet=8,;
Name='__InLeftLine'
ADD OBJECT __InRightLine AS line WITH;
Height=29,;
Left=330,;
Top=31,;
Width=0,;
BorderColor=RGB(255,255,255),;
ZOrderSet=9,;
Name='__InRightLine'
ADD OBJECT progress_title AS label WITH;
Alignment=2,;
AutoSize=.T.,;
BackStyle=0,;
Caption='處理進度... ',;
FontName='細明體',;
FontSize=14,;
Height=25,;
Left=114,;
Top=9,;
Width=122,;
ZOrderSet=0,;
Name='progress_title'
ADD OBJECT progress_per AS Shape WITH;
Top=35,;
Left=25,;
Height=20,;
Width=0,;
FillColor=RGB(0,0,255),;
BorderStyle=0,;
FillStyle=0,;
SpecialEffect=0,;
ZOrderSet=1,;
Name='progress_per'
* 顯示進度格與百分比
PROCEDURE show_progress
LPARAMETERS pt_per1
WITH thisform
.LockScreen=.T.
.progress_title.caption='處理進度... '+TRANSFORM(pt_per1)+'%'
.progress_per.width=pt_per1*3
.LockScreen=.F.
ENDWITH
* WAIT WINDOW '' TIMEOUT 0.001 * 想看到完整1-100%就把 最左邊 * 拿掉
ENDPROC
ENDDEFINE
* ---------- 實例 -----------
SELECT * FROM 傳票檔;
WHERE (MOD(RECNO(),CEILING(RECCOUNT()/100))=0 OR RECNO()=RECCOUNT()) AND progress_bar(IIF(RECCOUNT()=0,100,RECNO()*100/RECCOUNT())) OR;
(!DELETED() AND BETWEEN(Date,'0101','1231'));
ORDER BY Date INTO CURSOR _tmpf
progress_bar(100)
本例在 199954 筆記錄中提取了 196470 筆, 耗時 0~1 秒,
進度條跑得很快,
想要完美呈現 1~100% 的過程又不怕拖慢速度的話,
就把上頭紅色那行的 * 拿掉!
多虧大家的提示,
尤其是最後小賴兄的MOD(),
真是天外一筆哪!
不過小弟不明白小賴兄那個 C (就是 AND .F.這句)的作用,
套上去會被濾掉一推記錄.
jerryclt 在 星期五 九月 06, 2013 1:07 pm 作了第 5 次修改 |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 20 樓
|
發表於: 星期四 九月 05, 2013 9:05 am 文章主題: |
|
|
ckp6250 寫到: | 不用測試,光用看的就看得出來
肯定拖慢 SELECT-SQL
因為,單是判斷第一個條件
MOD(RECNO(), 200) = 1
就必需掃描整個資料庫了,VFP的OPTIMIZE完全用不上 |
話雖是這樣說,
但是判斷RECCOUNT()次 MOD(RECNO(), 200) = 1,
肯定比呼叫RECCOUNT()次 progress_bar() 來得便宜,
而且不管怎樣下WHERE條件式,
SELECT-SQL一樣要掃瞄整個資料表格, 不是嗎!?
Garfield兄的 mint / mcount,
目的是要減少執行 show_progress 的次數(最多顯示100次,但是呼叫了progress_bar*RECCOUNT()次),
小賴兄把MOD()放進SELECT內,
更是省去呼叫 progress_bar 的次數(最多呼叫100次)...
如果還有更精簡的運算式,
請大家不吝提供...感恩啊! |
|
回頂端 |
|
 |
小賴
註冊時間: 2004-12-27 文章: 476
第 21 樓
|
發表於: 星期四 九月 05, 2013 10:09 am 文章主題: |
|
|
TO jerryclt 兄
1. 請 Check 有(AND .F.) 和無 (AND .F.) 提取資料筆數差異
2. 如果有差異;表示你的資料少了或多了... 讓進度條動作的那些筆
即 MOD(RECNO(),CEILING(RECCOUNT()/100))=0 OR RECNO()=RECCOUNT()) = .T. 的時候
此時條件式為 (.T. AND progress_bar()) OR (!DELETED() AND BETWEEN(Date,'0101','1231'))
偏偏你的 progress_bar() 都傳回 .T.
所以條件式變為 (.T.) OR (!DELETED() AND BETWEEN(Date,'0101','1231'))
二條件作 OR ; 第一個條件已是 .T.
所以不論 (!DELETED() AND BETWEEN(Date,'0101','1231')) 的結果為何都會是 .T.
// 其實此情形電腦直接傳回 .T. 根本沒有判定 (!DELETED() AND BETWEEN(Date,'0101','1231'))
3. 結論:讓進度條動作的那些筆;不一定符合 (!DELETED() AND BETWEEN(Date,'0101','1231'))
4. 修正方式有二
A. 使用 (AND .F.)
B. progress_bar() 固定傳回 .F.
因為我沒改你的程式碼; 所以只能用 (AND .F.)
之所以用RECCOUNT() - ? 是想讓最後 98 % ; 99%在畫面停留久一點 |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 22 樓
|
發表於: 星期四 九月 05, 2013 12:50 pm 文章主題: |
|
|
小弟最後POST的修正程式碼,
已經不用 C 條件式了,
只要該運算式計算出的值是 1-100 的整數,
就會呼叫 progress_bar !
至於 progress_bar 傳回 .T. 或 .F. 已經無關緊要,
因為小賴兄不是用了個 OR 嗎?
(.T. OR (.T.))=(.F. OR (.T.))
如果真的放上 AND .F.
對於條件 between(Date,'0101','1231') 是沒差,
因為該條件是全部資料檢索,
但是如果下的是:
between(Date,'0901','0930')
就會少了 89 筆... |
|
回頂端 |
|
 |
小賴
註冊時間: 2004-12-27 文章: 476
第 23 樓
|
發表於: 星期四 九月 05, 2013 5:34 pm 文章主題: |
|
|
jerryclt 寫到: |
至於 progress_bar 傳回 .T. 或 .F. 已經無關緊要,
因為小賴兄不是用了個 OR 嗎?
(.T. OR (.T.))=(.F. OR (.T.))
|
(.T. OR (.T.))=(.F. OR (.T.)) = (.T. OR (.F.)) = .T.
第三種情形也會取出資料 ;
會是你要的嗎 ? |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 24 樓
|
發表於: 星期四 九月 05, 2013 5:54 pm 文章主題: |
|
|
您說得對,
總是會有小三介入... @@"
還是固定讓 progress_bar 傳回 .F. |
|
回頂端 |
|
 |
ckp6250
註冊時間: 2004-07-30 文章: 1645
第 25 樓
|
發表於: 星期五 九月 06, 2013 9:57 am 文章主題: |
|
|
若 Reccount()=0 時,就出槌啦,請修正一下
又,在某些情況下,若下完 select 指令,若不再加上 progress_bar(100) 的話,這個進度條不能自動關閉,這可能要考慮修正一下 |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 26 樓
|
發表於: 星期五 九月 06, 2013 3:13 pm 文章主題: |
|
|
已修正,
加上紅色部份應該就沒問題了! |
|
回頂端 |
|
 |
ckp6250
註冊時間: 2004-07-30 文章: 1645
第 27 樓
|
發表於: 星期五 九月 06, 2013 3:56 pm 文章主題: |
|
|
我的意思是,下完 Select ...... into cursor _tmp 後
progress_bar(100) , 這一行應該要省略才對
跑完 select 應該要自動關閉進度條,而不需再多下一道指令去關它 |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 28 樓
|
發表於: 星期六 九月 07, 2013 4:25 pm 文章主題: |
|
|
ckp6250 寫到: | 我的意思是,下完 Select ...... into cursor _tmp 後
progress_bar(100) , 這一行應該要省略才對
跑完 select 應該要自動關閉進度條,而不需再多下一道指令去關它 |
照理應該會執行到 RECNO()=RECCOUNT() 這個結果,
所以也就應該會如期關閉 progress_bar,
什麼情況下 RECNO()=RECCOUNT() 這段會被忽略了呢? |
|
回頂端 |
|
 |
ckp6250
註冊時間: 2004-07-30 文章: 1645
第 29 樓
|
發表於: 星期六 九月 07, 2013 5:34 pm 文章主題: |
|
|
有 join 的情況
程式碼如下
Select Acc4.invent, Acc13.Date, Acc13.mount;
FROM Acc4 INNER Join Acc13 ;
ON Acc4.invent = Acc13.invent;
ORDER By Acc4.invent, Acc13.Date ;
WHERE (Mod(Recno(),Ceiling(Reccount()/100))=0 Or Recno()=Reccount()) And progress_bar(Recno()*100/Reccount()) ;
OR (!Deleted() And Between(Acc13.Date,'01/01','12/31'));
Into Cursor _tmpf |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 30 樓
|
發表於: 星期一 九月 09, 2013 8:06 am 文章主題: |
|
|
ckp6250 寫到: | 有 join 的情況
程式碼如下
Select Acc4.invent, Acc13.Date, Acc13.mount;
FROM Acc4 INNER Join Acc13 ;
ON Acc4.invent = Acc13.invent;
ORDER By Acc4.invent, Acc13.Date ;
WHERE (Mod(Recno(),Ceiling(Reccount()/100))=0 Or Recno()=Reccount()) And progress_bar(Recno()*100/Reccount()) ;
OR (!Deleted() And Between(Acc13.Date,'01/01','12/31'));
Into Cursor _tmpf |
將 SELECT 改成
Select Acc4.invent, Acc13.Date, Acc13.mount;
FROM Acc4 LEFT Join Acc13 ;
ON Acc4.invent = Acc13.invent;
ORDER By Acc4.invent, Acc13.Date ;
WHERE (Mod(Recno(),Ceiling(Reccount()/100))=0 Or Recno()=Reccount()) And progress_bar(Recno()*100/Reccount()) ;
OR (!Deleted() And Between(Acc13.Date,'01/01','12/31'));
Into Cursor _tmpf
試試 |
|
回頂端 |
|
 |
|
|
您 無法 在這個版面發表文章 您 無法 在這個版面回覆文章 您 無法 在這個版面編輯文章 您 無法 在這個版面刪除文章 您 無法 在這個版面進行投票 您 無法 在這個版面附加檔案 您 無法 在這個版面下載檔案
|
|