給pb的listview或者treeview控制元件加上背景圖 (轉)

worldblog發表於2007-12-14
給pb的listview或者treeview控制元件加上背景圖 (轉)[@more@]

此文章獻給想美化介面的pb程式設計師。

一.載入點陣圖資源並建立PatternBrush作為填充背景圖的刷子
long ll_bmp
long h_deskdc
long ll_memDc

if ih_BkBrush>0 then
 delete(ih_BkBrush)
 ih_BkBrush=0
end if

h_deskdc =GetDc(0)
//載入圖片
ll_bmp = LoadImage(0,BMPBkName,0,0,0,16)
//失敗
if ll_bmp = 0 then
 releaseDc(0,h_deskdc)
 return
end if
ll_memDC = CreateCompatibleDC(h_deskdc)
//選入到場景
Object(ll_memDC,ll_bmp)
//建立繪製背景圖的刷子
ih_BkBrush =CreatePatternBrush(ll_bmp)
//釋放不需要的資源
releaseDc(0,h_deskdc)
Deleteobject(ll_bmp)
DeleteDc(ll_memDC)


二.給listview加背景圖
1.得到listview客戶區域矩形
getClientRect(handle(this),lvclientRect)

2.在listview中以pbm_erasebkgnd為事件id,自定義事件ue_erasebkgnd ,script如下 
if ih_BkBrush>0 then
 FillRect(hdc,lvClientrect,ih_BkBrush)
 return 1
end if

3.當listview的顯示風格為listviewreport!,listviewlist!時候,拖動捲軸時候會出現擠壓需要以pbm_vscroll和pbm_hscroll作為eventid自定義事件ue_vscroll,ue_hscroll。
if ih_BkBrush>0 and (View=listviewreport! or View=listviewlist!) then
 if (scrollcode<>SB_ENDSCROLL) and (scrollcode<>SB_THUMBPOSITION) then
 InvalidateRect(handle(this),lvclientRect,1)
 end if
end if
儘管如此,在上述兩種風格中拖動捲軸依然有閃爍的情況,我還沒有能夠解決,歡迎大家提出意見。

4.如果想要listview中item的文字和圖片背景透明,只需以下程式碼
Constant Long CLR_NONE = 4294967295
Constant Long LVM_FIRST  =4096
Constant Long LVM_SETTEXTBKCOLOR = (LVM_FIRST + 38)
Constant Long LVM_GETIMAGELIST = (LVM_FIRST + 2)
Constant Long LVM_SETBKCOLOR = (LVM_FIRST + 1)
Constant Long  LVSIL_NORMAL= 0
Constant Long  LVSIL_SMALL=1
Constant Long  LVSIL_STATE=2
//讓文字的背景色透明
Send(handle(this),LVM_SETTEXTBKCOLOR,0,CLR_NONE)
//讓圖片的背景色透明
Send(handle(this),LVM_SETBKCOLOR,0,CLR_NONE)

此外,如果使用pb自帶的圖片,需要將PictureMaskColor設定為Silver。

三.給treeview加背景圖
  如果按照上述listview的方法給treeview新增背景圖,也可以基本實現,但是在樹的子項展開,收縮時候以及拖動捲軸時會擠壓圖形,如果用setredraw控制會出現嚴重的閃爍情況。此外樹的子項的文字和圖片背景也不能透明。

1.我參考了其他程式語言實現的例程,基本都會在WM_PAINT事件中處理,因此我以pbm_paint作為eventid自定義事件ue_paint。但由於此事件的引數Hdc在任何情況下均為0,所以我猜測在pb中,此事件只是在呼叫WindowProc處理WM_PAINT訊息前,並沒有使用beginPaint開始進行繪圖操作。
  要讓樹的子項的文字和圖片背景透明,只需要做一些光柵運算就可以了
  相關程式碼如下:
if ih_BkBrush>0 then

 if message.Parm >0 then
 //由send帶WordParm引數觸發,不執行下面的操作
 return 0
 end if
 
 tagPAINTSTRUCT ps
 //開始paint操作
 HDC=BEGINPAINT(handle(this),ps)
 long memdc,maskdc,ResultDc;
 long hbitmap;
 long li_RCWidth,li_RCHeight
 
 li_RCWidth=tvclientRect.right -tvclientRect.left
 li_RCHeight=tvclientRect.bottom -tvclientRect.top
 ResultDc=CreateCompatibleDC(hdc);
 hbitmap=CreateCompatibleBitmap(hdc,li_RCWidth,li_RCHeight);
 SelectObject(ResultDc, hbitmap );
 deleteObject(hbitmap)
 
 //將背景圖繪製到裝置場景ResultDc上
 FillRect(ResultDc,tvclientRect,ih_BkBrush)
 
 // create a compatible memory dc
 memdc=CreateCompatibleDC(hdc);
 hbitmap=CreateCompatibleBitmap(hdc,li_RCWidth,li_RCHeight);
 SelectObject(memdc, hbitmap );
 deleteObject(hbitmap)
 //將tv的內容繪製到裝置場景memdc上
 send(handle(this),WM_PAINT,memdc, 0)
 
 // create mask dc
 maskdc=CreateCompatibleDC(hdc);
 hbitmap=CreateBitmap(li_RCWidth,li_RCHeight,1, 1,0);
 SelectObject(maskdc, hbitmap );
 deleteObject(hbitmap)
 //只有單色
 BitBlt(maskdc,0,0,li_RCWidth,li_RCHeight,memdc,0,0,SRCCOPY);
 
 SetBkColor(memdc,RGB(0,0,0));
 SetTextColor(memdc,RGB(255,255,255))
 //白色替換為黑色
 BitBlt(memdc,0,0,li_RCWidth,li_RCHeight,maskdc,0,0,SRCAND);
 
 //透過and操作,將item和文字置為黑色新增到背景圖上
 BitBlt(ResultDc,0,0,li_RCWidth,li_RCHeight,maskdc,0,0,SRCAND);
 //透過or操作,將treeitem替換為原有顏色
 BitBlt(ResultDc,0,0,li_RCWidth,li_RCHeight,memdc,0,0,SRCPAINT);
 
 //將合併後的圖copy到hdc上
 BitBlt(hDc,0,0,li_RCWidth,li_RCHeight,ResultDc,0,0,SRCCOPY);

 deleteDc(memdc)
 deleteDc(maskdc)
 deleteDc(ResultDc)
 //結束paint操作
 endpaint(handle(this),ps)
end if

由於做了多次的點陣圖處理操作,在較低的機器上可能會有延遲的現象,所以treeview控制元件的長度和寬度不要太大,子項的數目應該控制在合理的範圍內。

2、由於我們在ue_paint事件中已經對背景進行了繪製,因此需要遮蔽預設的重新整理背景操作。
ue_erasebkgnd:
if ih_BkBrush>0 then
 //不執行預設的訊息處理程式
 return 1
end if

3.對於treeview由於子項展開,收縮時候會擠壓圖形,需要itemcollapsin、itemexpanding和selectchanging事件控制從而使整個控制元件重畫。
if ih_BkBrush>0 then InvalidateRect(handle(this),tvclientRect,0)
 
4、對於由於捲軸拖動產生的圖形積壓,也需要做類似處理。
pbm_vscroll和pbm_hscroll:
if ih_BkBrush>0 and (scrollcode<>SB_ENDSCROLL) and (scrollcode<>SB_THUMBPOSITION) then
 InvalidateRect(handle(this),tvclientRect,0)
end if

在這裡我只對程式的關鍵實現部分作了說明,省略了相關的變數、外部函式、結構宣告和其他部分。完整的pb8例程可在 
?boardID=23&ID=934">,歡迎大家作進一步探討:)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993472/,如需轉載,請註明出處,否則將追究法律責任。

相關文章