用API函數改進ListView控件的顯示效果
發表于:2007-07-14來源:作者:點擊數:
標簽:
王建兵 ListView使用簡介 ListView控件是 VB 開發 者非常喜愛的控件之一。作為 Windows 95公共控件組(COMCTL32.OCX) 的成員,它經常與經常與TreeView、ImageList等控件聯合使用。即用TreeView顯示一個的樹 型結構,而用ListView顯示選中的節點(Node)對象的記
王建兵
ListView使用簡介
ListView控件是
VB開發者非常喜愛的控件之一。作為
Windows95公共控件組(COMCTL32.OCX) 的成員,它經常與經常與TreeView、ImageList等控件聯合使用。即用TreeView顯示一個的樹 型結構,而用ListView顯示選中的節點(Node)對象的記錄
集。
這是筆者在開發財務軟件項目中的$#@60;$#@60;憑證管理$#@62;$#@62;模塊的一個用戶界 面。屏幕左邊是一個TreeView控件,用來顯示會計憑證的類別;右邊是一個istView,用來顯示 對應類別的憑證目錄;上方是一個菜單條控件(MenuBar)和一個工具條控件(ToolBar);下方是 一個狀態欄控件(StatusBar),用來顯示憑證數個當前日期。
大家可以看到圖中所 示的界面非常類似于Window95/98的資源瀏覽器,Windows的界面風格做為一種標準已為廣大 用戶所接受。而
Windows操作系統的主要的優點就是為所有的應用程序提供了公用的界面。知道 如何使用基于Windows的應用程序的用戶,很容易學會使用其他應用程序。
這種使 用Windows95公共控件組合的方法能夠達到與Windows界面的一致性,所以在目前VB5.0應用 程序的開發中經常使用。
二、填充大量結果集所遇到的問題
在實際應用開發中,經常用ListView填充一個
數據庫結果集(Recordset)的內容。即先寫 一段
SQL查詢語句,產生一個結果集,然后將結果集的每一條記錄用DO...LOOP循環語句中填到ListView 中。
但是當結果集很大時(例如有5000條以上的記錄),填充所需要的時間會很長。 用戶不得不等很長時間完成一個查詢。所以在查詢的過程中必須允許用戶按Escape鍵退出。具 體做法是在DO...LOOP循環體中加一條DoEvents函數,并寫一段中斷退出程序代碼。
DoEvents函數的功能是:轉讓控制權,以便讓操作系統處理其它的事件。這樣在長時間的查詢 過程中,如果用戶按了Escape鍵,將退出循環體,結束查詢過程。
但是這樣又會引 發另外一個問題:由于DoEvents可以讓操作系統響應別的事件,循環體中填充每一條ListView 項目(ListItem)的過程也會顯示出來,所以在填充的過程中屏幕會不停的閃動,這種現象當然 不能被用戶所接受。如何解決這個問題呢?
三、
解決方案
用WindowsAPI函數可以解決這個問題。首先對幾個用到的API函數做一解釋和說明。
1.GetClientRectLib"user32"(ByValhwndAsLong,lpRectAsRECT)As Long
此函數的功能是獲得一個指定對象窗 Window)的矩型框區域(rectangle)。
Hwnd為指定對象或窗體的句柄。LpRect為返回矩型框的結構(必須定義為結構類型的變量)。
2.ValidateRectLib"user32"(ByValhwndAsLong,lpRectAsRECT)As Long
此函數的功能是使指定的矩型區域生效。這樣會通知Windows不必對指定 的區域進行重畫(Redraw)。
3.InvalidateRectLib"user32"(ByVal hwndAsLong,lpRectAsRECT,ByValbEraseAsLong)AsLong
此函數的 功能是使指定的矩型區域無效。這樣會通知Windows要對指定的區域進行重畫。
具體實現的步驟如下:
1.在填充結果集之前先用GetClientRect函數獲得ListView的 顯示區域。
2.在增加完一個顯示項目(ListItem)后用ValidateRect函數置這一 區域為有效。這樣Windows就不會顯示每一條ListItem,屏幕閃動的現象就會消失。
3.在填充結果集之后,用InvalidateRect函數置這一區域為無效。這樣Windows就會重畫ListView 的內容,結果集被完整的顯示出來。
下面是筆者在項目開發中的一個程序實例。程 序名為FillListView。該程序將填寫一個A
clearcase/" target="_blank" >ccess數據庫(FISCAL.MDB)的憑證表(Table)的內容 到ListView中。
首先進入VB5.0,新建一個窗體(Form),名為Form1。
然后在Form中增加下列控件。
控件名Name
ListViewLvw
ImagelistimlList
CommandButton。Command1
將ImageList控件中充填一個名為“item”的圖象后與ListView控件關聯。
在$#@60;$#@60;工程$#@62;$#@62;菜單命令條中進入“引用”對話框,選擇“MicrosoftDAOObjectLibrary”
在Form的通用模塊(Modle)中定義以下變量。
PrivateTypeRECT用來定義一個區域的坐標。
LeftAsLong
TopAsLong
Right AsLong
BottomAsLong
EndType
--
Windows API函數的聲明。
PrivateDeclareFunctionInvalidateRectLib"user32"
(ByVal hwndAsLong,lpRectAsRECT,ByValbEraseAsLong)AsLong
PrivateDeclare FunctionValidateRectLib"user32"
(ByValhwndAsLong,lpRect AsRECT)AsLong
PrivateDeclareFunctionGetClientRectLib"user32"
(ByVal hwndAsLong,lpRectAsRECT)AsLong
DimmbSearchCancelAsBoolean
用來定義查詢中斷的標志。
True表示中止查詢;False表示正在查詢。
將該Form的KeyPreview屬性設為True,以控制窗體接收鍵盤事件。
然后在Form 的KeyPress事件中寫下列代碼:
IfKeyAscii=
vbKeyEscapeThen
mbSearchCancel=True
當用戶按Escape 鍵時,置mbSearchCancel變量為True。
EndIf
表示結束查詢。
在Command Button的Click事件中調用填充子程序:CallFillListView。
子程序的代碼 為:
PrivateSubFillListView()
DimitmXAsListItem定義一 個ListView的顯示項目。
DimsSQLAsString查詢字串變量。
Dim rcAsRECTListView的顯示區域。
DimwrkJetAsWorkspace數據庫工作空間。
Dim dbFISCALAsDatabase數據庫對象。
DimRSAsRecordset數據結果集。
On ErrorGoToErrFillListView
Screen.MousePointer=vbHourglass
lvw.ListItems.Clear: 清除ListView的內容。
定義ListView的列頭的名稱。
With lvw.ColumnHeaders
.Add,,"憑證編號",800
.Add,," 憑證日期",1000
.Add,,"憑證字號",1000
.Add,," 憑證類別",800
.Add,,"首行摘要",1440
.Add,," 借方金額合計",1000,lvwColumnRight
EndWith
- --
產生查詢語句。
sSQL="selectvoucher_id,voucher_number,voucher_date,
voucher_type_shortname,"
sSQL=sSQL&"voucher_type_name,voucher_memo,voucher_amount fromVOUCHER"
sSQL=sSQL&"orderbyvoucher_number"
---
打開一個數據庫結果集。
SetwrkJet=CreateWorkspace("NewJetWorkspace", "admin","",
dbUseJet)
SetdbFISCAL=wrkJet.OpenDatabase("FISCAL.mdb")
Set RS=.dbFISCAL.OpensSQL,dbOpenForwardOnly
獲得listview 的顯示區域。
CallGetClientRect(lvw.hwnd,rc)
DoWhileNotRS.EOF()
DoEvents
If mbSearchCancelThen
中斷退出
RS.Close:SetRS=Nothing關閉、清 除結果集。
mbSearchCancel=False
Screen.MousePointer=vbDefault
--
刷新ListView的內容,顯示已經查出的記錄數。
CallInvalidateRect(lvw.hwnd, rc,True)
ExitSub
EndIf
---
增加一個顯示 項目ListItem。
Withlvw.ListItems
SetitmX=.Add(,,""& RS!voucher_number,"item","item")
憑證編號
itmX.SubItems(1) =Format$(""&RS!voucher_date,"yyyy/mm/dd")
憑證日期
itmX.SubItems(2)=""&RS!voucher_type_shortname &"-"—
憑證字號
&""&RS!voucher_number
itmX.SubItems(3)="" &RS!voucher_type_name
憑證類別
itmX.SubItems(4)=""&RS!voucher_memo
首行摘要
itmX.SubItems(5)=Format$(""&RS!voucher_amount, "#,###.00")
借方合計金額
itmX.Tag=""& RS!voucher_id
EndWith
--
避免顯示區域的閃動現象。
Call ValidateRect(lvw.hwnd,rc)
RS.MoveNext
Loop
- 刷新ListView的內容。顯示所有查出的記錄數。
CallInvalidateRect(lvw.hwnd,rc, True)
-
關閉、清除結果集。
RS.Close:SetRS=Nothing
creen.MousePointer =vbDefault
ExitSub
ErrFillListView:
Screen.MousePointer= vbDefault
MsgBoxErr&":"&Error,vbInformation,Me.Caption
Exit Sub
EndSub
編寫完畢后按F5執行該程序,用鼠標點擊CommandButton,將 開始查詢并填寫憑證的內容到ListView中去。
關于ListView本文只是描述了它 如何填充大量結果集的方法,它還有很多特性(property)和方法(method),利用它們可以達到 更完美的顯示效果,有興趣的讀者可以進一步研究。不管是開發什么樣的應用程序,只有堅持 面向用戶、方便用戶的原則,這樣的軟件才具有強大的生命力。
原文轉自:http://www.anti-gravitydesign.com