 |
VFP 愛用者社區 本討論區為 Visual Foxpro 愛用者經驗交流的地方, 請多多利用"搜尋"的功能, 先查看看有無前例可循, 如果還有不懂的再發問. 部份主題有附加檔案, 須先註冊成為社區居民才可以下載.
|
上一篇主題 :: 下一篇主題 |
發表人 |
內容 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 1 樓
|
發表於: 星期二 九月 03, 2013 10:39 am 文章主題: 不需要MSCOMCTL.OCX的自制Select-SQL進度條 |
|
|
轉自梅子論壇 http://www.mzvfp.com/read.php?tid=45337
原始碼:
引言回覆: | SET TALK OFF
cTable = GETFILE("dbf")
IF EMPTY(cTable)
RETURN .T.
ENDIF
SELECT * FROM (cTable) WHERE Progress_Bar( RECNO()*100/RECCOUNT(), "Processing ..."+STR(RECNO()*100/RECCOUNT())+"%" )
SET MESSAGE TO
CLOSE ALL
RELEASE ALL
* *************************************************************************
PROCEDURE progress_bar
LPARAMETERS tnUpdateValue, tcTitle
IF INT(tnUpdateValue) >= 1
IF TYPE( "oThre" ) <> "O"
PUBLIC oThre
oThre = CREATEOBJECT("frmProgress")
oThre.Show( )
ENDIF
oThre.ShowThre( tnUpdateValue, tcTitle )
IF INT( tnUpdateValue ) >= 100
= MESSAGEBOX( "Finished!", 64, "Info" )
RELEASE oThre
ENDIF
ENDIF
ENDPROC
* ***********************************************
DEFINE CLASS frmprogress AS FORM
DoCreate = .T.
ShowTips = .T.
AutoCenter = .T.
Caption = ""
ControlBox = .F.
Closable = .F.
MaxButton = .F.
MinButton = .F.
Movable = .F.
Height = 72
Width = 350
BorderStyle = 2
WindowType = 0
Name = "frmProgress"
ADD OBJECT line1 AS line WITH ;
BorderWidth = 2, ;
Height = 0, ;
Left = -1, ;
Top = 1, ;
Width = 348, ;
BorderColor = RGB(128,128,128), ;
ZOrderSet = 0, ;
Name = "Line1"
ADD OBJECT labthre AS label WITH ;
Alignment = 2, ;
Caption = "", ;
Height = 17, ;
Left = 48, ;
Top = 12, ;
Width = 288, ;
ZOrderSet = 1, ;
Name = "labThre"
ADD OBJECT line2 AS line WITH ;
BorderWidth = 2, ;
Height = 0, ;
Left = 2, ;
Top = 71, ;
Width = 346, ;
BorderColor = RGB(255,255,255), ;
ZOrderSet = 2, ;
Name = "Line2"
ADD OBJECT line3 AS line WITH ;
BorderWidth = 2, ;
Height = 68, ;
Left = 1, ;
Top = 1, ;
Width = 0, ;
BorderColor = RGB(128,128,128), ;
ZOrderSet = 3, ;
Name = "Line3"
ADD OBJECT line4 AS line WITH ;
BorderWidth = 2, ;
Height = 68, ;
Left = 349, ;
Top = 2, ;
Width = 0, ;
BorderColor = RGB(255,255,255), ;
ZOrderSet = 4, ;
Name = "Line4"
ADD OBJECT image1 AS image WITH ;
Picture = "progress.bmp", ;
BackStyle = 0, ;
Height = 32, ;
Left = 7, ;
Top = 7, ;
Width = 32, ;
ZOrderSet = 5, ;
Name = "Image1"
ADD OBJECT olethre AS OleControl WITH ;
OleClass = "MSComctlLib.ProgCtrl.2", ;
Top = 45, ;
Left = 14, ;
Height = 13, ;
Width = 326, ;
ZOrderSet = 6, ;
Name = "oleThre"
ADD OBJECT line5 AS line WITH ;
Height = 0, ;
Left = 9, ;
Top = 61, ;
Width = 333, ;
BorderColor = RGB(255,255,255), ;
ZOrderSet = 7, ;
Name = "Line5"
ADD OBJECT line7 AS line WITH ;
Height = 0, ;
Left = 9, ;
Top = 41, ;
Width = 333, ;
BorderColor = RGB(128,128,128), ;
ZOrderSet = 8, ;
Name = "Line7"
ADD OBJECT line8 AS line WITH ;
Height = 19, ;
Left = 9, ;
Top = 42, ;
Width = 0, ;
BorderColor = RGB(128,128,128), ;
ZOrderSet = 9, ;
Name = "Line8"
ADD OBJECT line6 AS line WITH ;
Height = 19, ;
Left = 341, ;
Top = 42, ;
Width = 0, ;
BorderColor = RGB(255,255,255), ;
ZOrderSet = 10, ;
Name = "Line6"
*-- Used to show the thremeter progress
PROCEDURE showthre
LPARAMETERS tnProgress, tcTitle
LOCAL lnProgress, lcTitle
lnProgress = INT(tnProgress)
IF PARAMETERS()=2
lcTitle = tcTitle
ELSE
lcTitle = ""
ENDIF
WITH thisform
.LockScreen = .T.
.labThre.Caption=lcTitle
.oleThre.Value=lnProgress
.LockScreen = .F.
ENDWITH
ENDPROC
ENDDEFINE |
原本在自己的電腦上套用是可行的,
就開始大改特改一堆程式碼,
結果送到客戶那兒,
出現了不預知的錯誤......就是客戶端沒那個該死的MSCOMCTL.OCX
小弟修改了一些程式段後已無MSCOMCTL.OCX的需求了,
以下將修改過的程式碼提供狐友們參考,
如有待改進的地方也請不吝指教...
PROCEDURE progress_bar
LPARAMETERS val1,pt_title1
IF val1>0 AND val1<=100
IF TYPE('ctln')#'O'
PUBLIC ctln
ctln=CREATEOBJECT('my_progress')
ctln.show()
ENDIF
ctln.show_progress(INT(val1),pt_title1)
IF val1=100
RELEASE ctln
ENDIF
ENDIF
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,pt_title1
LOCAL pt_per2,pt_title2
pt_per2=INT(pt_per1)
pt_title2=IIF(PARAMETERS()=2,pt_title1,'')
WITH thisform
.LockScreen=.T.
.progress_title.caption=pt_title2
.progress_per.width=pt_per2*3
.LockScreen=.F.
ENDWITH
ENDPROC
ENDDEFINE
實例:
* ---------- 在 Select-SQL 內的寫法
SELECT * FROM table;
WHERE field='' AND;
!DELETED() AND progress_bar(RECNO()*100/RECCOUNT(),'處理進度... '+RIGHT(STR(INT(RECNO()*100/RECCOUNT())),3)+'%');
INTO CURSOR _tmpf
progress_bar(100,'處理進度... '+'100%')
IF _TALLY>0
* ---------- 逐筆的寫法
SELECT _tmpf
_nCount=RECCOUNT()
GO TOP
DO WHILE !EOF()
progress_bar(RECNO()*100/_nCount,'處理進度... '+RIGHT(STR(INT(RECNO()*100/_nCount)),3)+'%')
SELECT _tmpf
SKIP
ENDDO
progress_bar(100,'處理進度... '+'100%')
SELECT _tmpf
USE IN _tmpf
ENDIF |
|
回頂端 |
|
 |
ckp6250
註冊時間: 2004-07-30 文章: 1645
第 2 樓
|
發表於: 星期二 九月 03, 2013 2:42 pm 文章主題: |
|
|
用 RecNo() 來做會不會有問題呀?
如果這個 Select 有加上 order by 或者 group by 或者是 join 的話
其次,若資料量很大,比如數十萬筆中要取出一千筆的話,
這個 where 語句會不會拖慢效率呢? |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 3 樓
|
發表於: 星期二 九月 03, 2013 4:04 pm 文章主題: |
|
|
事實上我自己的SORUCE裡是這樣:
SELECT * FROM oo01 RIGHT OUTER JOIN oo01a ON or01a_001=or01_001;
WHERE !EMPTY(or01_001) AND or01_016=.F. AND TRANSFORM(or01_006)>=TRANSFORM(&_bproc.10.value) AND;
TRANSFORM(or01_006)<=TRANSFORM(&_bproc.11.value) AND or01_003=ALLTRIM(&_bproc.12.value) AND;
EMPTY(or01a_009) AND or01a_002=ALLTRIM(&_bproc.13.value) AND !DELETED() AND;
progress_bar(RECNO()*100/RECCOUNT(),'處理進度... '+RIGHT(STR(INT(RECNO()*100/RECCOUNT())),3)+'%');
ORDER BY or01_001 DESC INTO CURSOR _tmpor
progress_bar(100,'處理進度... '+'100%')
既有JOIN又有ORDER BY還有DESC,
但是PROGRESS並不會變成由100到0的方式顯示,
因為RECNO() / RECCOUNT()是指向 CURSOR _tmpor 吧!
至於資料量大的話,
有哪一種 progress 不會拖慢 SELECT 呢?
用 timer 嗎? |
|
回頂端 |
|
 |
ckp6250
註冊時間: 2004-07-30 文章: 1645
第 4 樓
|
發表於: 星期二 九月 03, 2013 4:50 pm 文章主題: |
|
|
試了一下,給您按一個讚!
若大資料量時,我試了廿萬筆,實在很慢,但這不是您的問題 |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 5 樓
|
發表於: 星期二 九月 03, 2013 5:17 pm 文章主題: |
|
|
剛剛實測了一下,
從 72184(tt0) + 123724(tt1) 筆記錄內,
SELECT * FROM tt0 RIGHT OUTER JOIN tt1 ON st01a_001=st01_001;
WHERE (st01_001='KO' OR st01_001='CA' OR st01_001='BZ') AND st01_006<{^1980.01.01} AND st01a_002='9' AND;
st01a_007>={^2001.01.01} AND st01a_007<={^2012.06.30} AND !DELETED() AND;
progress_bar(RECNO()*100/RECCOUNT(),'處理進度... '+RIGHT(STR(INT(RECNO()*100/RECCOUNT())),3)+'%');
ORDER BY st01_006 DESC INTO CURSOR _tmpf
抽出594筆,只花了..... 2 秒 |
|
回頂端 |
|
 |
ckp6250
註冊時間: 2004-07-30 文章: 1645
第 6 樓
|
發表於: 星期二 九月 03, 2013 5:39 pm 文章主題: |
|
|
我傳一個檔,您試一下,指令如下
代碼: |
Select * From 傳票檔 ;
WHERE !Deleted() And ;
BETWEEN(Date ,'0901','0930') And ;
progress_bar(RECNO()*100/RECCOUNT(),'處理進度.... '+TRANSFORM(INT(RECNO()*100/RECCOUNT()))+'%');
INTO Cursor _tmpf
|
1.它不會由 1% 起跳,會從66%起跳
2.如果把日期範圍放大,比如設成BETWEEN(Date ,'0101','1231'),那麼,有加progress_bar和沒加progress_bar,速度差了幾百倍 |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 7 樓
|
發表於: 星期三 九月 04, 2013 7:18 am 文章主題: |
|
|
測試結果...確實是由 66% 起, 73% 結束,
由此可證明 progress_bar 不是針對 CURSOR 作反應(小弟上文說的是錯誤);
話又說回來,
如果資料表格只有一筆記錄,
把一筆記錄拆分為1~100%的進度條,
也是很詭異的一件事,不是嗎?
所以小弟暫且不去計較每次的進度條都得從1而終 ^^"
另外...實測計時如下:
BETWEEN(Date ,'0901','0930')---->1-2秒
BETWEEN(Date ,'0101','1231')---->10-11秒
沒差到幾百倍吧 @@"
還有一個重點,
就算改成 BETWEEN(Date ,'0101','1231')
如果拿掉 progress_bar 耗時不到1秒,
不到1秒的 query 可以考慮不使用 progress_bar
小弟目前大部份只應用在
* ---------- 逐筆的寫法
SELECT _tmpf
_nCount=RECCOUNT()
GO TOP
DO WHILE !EOF()
progress_bar(RECNO()*100/_nCount,'處理進度... '+RIGHT(STR(INT(RECNO()*100/_nCount)),3)+'%')
SELECT _tmpf
SKIP
ENDDO
progress_bar(100,'處理進度... '+'100%')
這種場合比較多
jerryclt 在 星期三 九月 04, 2013 11:41 am 作了第 2 次修改 |
|
回頂端 |
|
 |
garfield Site Admin

註冊時間: 2003-01-30 文章: 2160
第 8 樓
|
發表於: 星期三 九月 04, 2013 9:21 am 文章主題: |
|
|
如果改進成最多只顯示100次, 顯示速度會快很多,
Define Class my_progress As Form
......
WindowType=0
加上一行
mint = -1
****
Procedure show_progress
.........
pt_per2=Int(pt_per1)
加上這5行
IF pt_per2 =this.mint
RETURN
ELSE
this.mint = pt_per2
endif _________________ 利用>>搜尋<<的功能會比問的還要快得到答案. |
|
回頂端 |
|
 |
ckp6250
註冊時間: 2004-07-30 文章: 1645
第 9 樓
|
發表於: 星期三 九月 04, 2013 9:31 am 文章主題: |
|
|
1.這正是我先前提的,用RecNo()會有問題.
2.我指的差百倍,是指設成BETWEEN(Date ,'0101','1231') 時,有加和沒加progress_bar時的差異,您的差異小,可能是您的電腦的規格強,我的是10年前的NB,沒加progress_bar時,同樣是不到一秒;有加時,可就天荒地老了,但,我們也不能事先知道,使用者用的是那一個等級的電腦
3.『不到1秒的 query 可以考慮不使用 progress_bar 』這句話當然沒錯,問題是一個函數要運用到很多的 Select 場合,事先根本無法預測它會跑多久。
4.我個人的想法,加到 Where 後的方式,實在會影響效能,尤其是老一點的電腦,如果改用Timer,再加上 garfield 的建議,也許會好一點
5.既然叫做『進度條』就得名實相符,要從一而終,否則,不如改個名稱和呈現方式,免得被說是廣告不實^^ |
|
回頂端 |
|
 |
小賴
註冊時間: 2004-12-27 文章: 476
第 10 樓
|
發表於: 星期三 九月 04, 2013 11:27 am 文章主題: |
|
|
ckp6250 寫到: |
Select * From 傳票檔 ;
WHERE !Deleted() And ;
BETWEEN(Date ,'0901','0930') And ;
progress_bar(RECNO()*100/RECCOUNT(),'處理進度.... '+TRANSFORM(INT(RECNO()*100/RECCOUNT()))+'%');
INTO Cursor _tmpf
[/code]
1.它不會由 1% 起跳,會從66%起跳
|
不知 WHERE BETWEEN(Date ,'0901','0930') And progress_bar
改成 WHERE progress_bar AND BETWEEN(Date ,'0901','0930')
或 BETWEEN(Date ,'0901','0930') OR progress_bar
是否可成
記得 A AND B
當 A = .F. 時好像不會判斷B |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 11 樓
|
發表於: 星期三 九月 04, 2013 12:37 pm 文章主題: |
|
|
小賴兄是對的
把 progress 放在 WHERE 後第一個判斷式,
就會顯示全進度條,
缺點是速度變慢了,
另外...不可以用OR, 因為...其他條件式都變成無效!
下午再來試試 Garfield 兄的方式 |
|
回頂端 |
|
 |
garfield Site Admin

註冊時間: 2003-01-30 文章: 2160
第 12 樓
|
發表於: 星期三 九月 04, 2013 1:48 pm 文章主題: |
|
|
不用recno() 改用count會比較準,
假設會處理全部的資料,
執行時改用
progress_bar(RECC() ,'處理進度.... ')
*****
程式碼要修正
Define Class my_progress As Form
......
WindowType=0
加上2行
mint = -1
mcount = 0
****
Procedure show_progress
.........
pt_per2=Int(pt_per1)
改成
this.mcount = this.mcount + 1
pt_per2=Int( this.mcount*100 / pt_per1)
加上這5行
IF pt_per2 =this.mint
RETURN
ELSE
this.mint = pt_per2
endif _________________ 利用>>搜尋<<的功能會比問的還要快得到答案. |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 13 樓
|
發表於: 星期三 九月 04, 2013 2:00 pm 文章主題: |
|
|
剛剛測了一下 Garfield 兄早先的方式
IF pt_per1=this.mint
RETURN
ELSE
this.mint=pt_per1
ENDIF
WAIT WINDOW pt_per1 TIMEOUT 1 * 加了這一行
實際有從1跑到99%,
只是進度條 REFRESH 速度不夠快而已 |
|
回頂端 |
|
 |
jerryclt
註冊時間: 2009-03-10 文章: 334 來自: 佛心來的
第 14 樓
|
發表於: 星期三 九月 04, 2013 5:25 pm 文章主題: |
|
|
Garfield兄,
測試有mcount的結果和沒有mcount的結果是一樣的,
除非加上 wait window '' timeout 0.05
不然進度條都是跳著跑 |
|
回頂端 |
|
 |
ckp6250
註冊時間: 2004-07-30 文章: 1645
第 15 樓
|
發表於: 星期三 九月 04, 2013 9:59 pm 文章主題: |
|
|
百尺竿頭,更進一步
精益求精,加油! |
|
回頂端 |
|
 |
|
|
您 無法 在這個版面發表文章 您 無法 在這個版面回覆文章 您 無法 在這個版面編輯文章 您 無法 在這個版面刪除文章 您 無法 在這個版面進行投票 您 無法 在這個版面附加檔案 您 無法 在這個版面下載檔案
|
|