設為首頁收藏本站Access中國

Office中國論壇/Access中國論壇

 找回密碼
 注冊

QQ登錄

只需一步,快速開始

123下一頁
返回列表 發(fā)新帖
查看: 10618|回復: 25
打印 上一主題 下一主題

[Access本身] Access中自繪自定義“控件”

[復制鏈接]

點擊這里給我發(fā)消息

跳轉到指定樓層
1#
發(fā)表于 2015-3-16 14:17:53 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
本帖最后由 站到終點站 于 2015-3-16 20:17 編輯

       在論壇也混了蠻長時間了,一直沒有發(fā)表過什么專題性質的文章。主要是論壇上高手如云,很多學習過程中的問題在論壇上都能找到答案,特別是論壇的精華帖。通過不斷學習,我也開始對一些問題形成了些自己的想法。比如最近一段時間碰到一個問題:關于Access中動態(tài)添加控件的問題,Access中要給Form動態(tài)添加控件之類的,必須切換到窗體的設計模式,即使通過VBA代碼也必須這么做。以往碰到這個問題,一般的做法是在窗體中先添加固定數(shù)目的控件,然后窗體加載時將其隱藏,當需要動態(tài)添加時就將其顯示出來,但是這個方法一旦超出當初添加控件的數(shù)目時,就沒辦法解決了,并且控件添加多了對窗體加載速度也有一定影響。另外的話也可以通過一些ActiveX控件來做到這些,不過要找到適合Access且適合自己需求的ActiveX控件并不是件容易的事情,鑒于此我就想怎么才能在窗體上動態(tài)添加控件。
       其實這個問題糾結了差不多有1年了,當初也想到來自繪這個途徑,但是有好幾個問題都不懂,所以解決不了。這些問題包括:
1、自繪的話,用什么在窗體上自繪?      肯定不能用Access的控件,線條、框什么的都不能用,因為這些都不能動態(tài)添加到窗體上。只有選擇通過API來繪圖,可以使用的包括GDI、GDI+。但是我那時對GDI和GDI+是一點了解都沒有,所以畫了很長時間研究VBA中用API、GDI跟GDI+。
2、要用API繪圖就要有窗體句柄、要獲得設備環(huán)境(DC),Access里怎么獲取這些了?
     可能有些人馬上會想到Access窗體有個hwnd屬性啊,不就可以了嗎?其實這里面還有些曲折,后面我會詳細說。這里大家所要了解的是Access的窗體下面還包含了好幾個,包括窗體頁眉、主體跟窗體頁腳,它們都有句柄,要進行繪圖的話,你得獲取對應的句柄,而不是直接使用Access窗體的hwnd屬性。
3、以上2個問題解決了,還只是完成了在窗體上自繪,要怎樣才能將這些自繪窗體像控件一樣使用到其他窗體上了?
     可能大家看完這個問題,對Access有些了解的朋友會馬上想到子窗體。但是當時我是想了1個星期才想到用子窗體,因為當初對這個問題我的想法是怎么在Access中做自定義控件,而沒有想到怎么將窗體放到窗體里面這個方法。使用子窗體作為類似“控件”容器的承載體,這就解決的自定義控件的“容器”問題。
     好了,說完這幾個問題,那么我再總結下要讀懂本文內容所需要儲備的知識,如果你還對以下內容完全不了解的話,我建議你首先百度下或者找找相關的書什么的了解下,當然你也可以繼續(xù)讀下去,因為我會盡力講的通俗易懂。不過如果你感覺閱讀的很吃力的話,那你最好還是補一補相關的內容再來。
1、VBA中如何使用API?
2、GDI是用來干什么的?如何使用GDI?GDI句柄跟設備環(huán)境的關系,如何用GDI繪圖?
3、Access窗體的構成。
4、Access子窗體是什么?怎么使用子窗體?
5、VBA中的類模塊是什么?怎么使用類模塊?類模塊屬性、方法、事件怎么建立?
6、Access窗體與類模塊的關系;
7、使用VBA代碼怎么調用自定義“控件”?
8、集合在類模塊中的使用;
     另外我也想說明一下,由于本貼內容可能會比較長,我會分批將所寫內容更新進來,由于平時工作比較忙,可能一次更新的內容也不會太多,所以希望大家也不要急躁,慢慢看慢慢消化。另外相應的代碼部分也有很多在調試之中,但是大部分主體的代碼已經(jīng)完成,我暫時不把源代碼隨帖子一起發(fā)布,我會將其中的大部分代碼寫到本貼里面并講解,希望有興趣的將貼看下去。


下面我們就開始講怎么在Access來做一個類似TabControl的“控件”。
首先,我們來看下最終的效果,示例中包含了2個窗體,frmTest是個測試窗體,TabControl就是我們所謂的當作控件來使用的子窗體。另外還有些模塊跟類模塊,有些模塊是無用的,因為我在做這個的時候,借鑒了部分代碼,只是沒有刪除,我在后面會說到有哪些模塊跟代碼會使用到的,所以這里就不再說明各個模塊的作用了。
雙擊打開frmTest,默認會建立3個框,相當于3個Tab,點擊添加按鈕,會自動添加Tab,點刪除按鈕會從最后依次刪除Tab,在某個Tab上點擊,會彈出一個對話框顯示當前Tab的序號。


實例附件已上傳,可以下載,部分代碼還需要修改:













本帖子中包含更多資源

您需要 登錄 才可以下載或查看,沒有帳號?注冊

x

本帖被以下淘專輯推薦:

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享分享 分享淘帖1 訂閱訂閱

點擊這里給我發(fā)消息

2#
 樓主| 發(fā)表于 2015-3-16 14:18:13 | 只看該作者

第一部分、建立clsAccTabBar類模塊

本帖最后由 站到終點站 于 2015-3-16 16:37 編輯

     在動手編寫代碼前,首先我們得分析下TabControl控件的結構,搞清楚我們需要建立什么樣的模塊、類模塊以及窗體模塊。從上面我們已經(jīng)看到了我們用了一個子窗體作為TabControl的容器,那么TabControl里面還包括了很多Tab,這些Tab會構成一個集合Tabs,所以這個控件的層級關系就是:
TabControl
+---Tabs
      +----Tab
      之所以要理清楚這個關系,是因為基于這個結構建立我們的“控件”,會大大方便對我們控件的訪問。這里的TabControl對應我們的窗體,Tabs的話我們將在TabControl的窗體代碼中建立一個私有集合變量mTabBars,而Tab這個東西就需要我們自己來寫類模塊了。我將這個類模塊命名為clsAccTabBar,cls代碼是類模塊,Acc表示是Access中的,TabBar就是這個類模塊的含義。
      下面我們來分析下這個類模塊的內容,這個類模塊所代表的是TabControl中的一個TabBar:
1、與屬性相關的:包括TabBar的位置信息(Top、Left、Right、Bottom)、鼠標是否在其上(IsMouseOn)、是否被單擊(Selected)、顯示文字內容(Text)、標識字符串(Key)?赡艽蠹疫會說有與顏色相關的屬性,這些我都放在了TabControl里面了,因為這些顏色是所有Tab共用的,而不是某一個Tab專屬的,即使是選中色、鼠標移動其上的顏色。
2、與方法相關:Tab重畫,這個方法我將它寫在了TabControl里面了,當然你如果有興趣可以為Tab建立一個ReDraw的方法;
3、與事件相關:TabBar被單擊事件,TabBar鼠標移動事件,這2個事件的實現(xiàn)有些特殊,按道理應該在Tab類模塊里建立這2個事件,但是鼠標的移動跟單擊觸發(fā)都是在TabControl里面,所以這2個事件我都把實現(xiàn)做到了TabControl窗體的事件代碼里面了,后面講述TabControl的時候我會再講;
     從上面的描述來看,我基本上把這個clsAccTabBar類模塊只讓其用于保存各個Tab相關信息,下面是類模塊里面的代碼:
  1. Option Compare Database

  2. Private mIndex As Integer
  3. Private mKey As String
  4. Private mText As String
  5. Private mTargetFom As String
  6. Private mSelected As Boolean
  7. Private mIsMouseOn As Boolean

  8. Public Property Get Index() As Integer
  9.     Index = mIndex
  10. End Property

  11. Public Property Let Index(Value As Integer)
  12.     mIndex = Value
  13. End Property

  14. Public Property Get Key() As String
  15.     Key = mKey
  16. End Property

  17. Public Property Get Text() As String
  18.     Text = mText
  19. End Property

  20. Public Property Let Text(Value As String)
  21.     mText = Value
  22. End Property

  23. Public Property Get TargetFom() As String
  24.     TargetForm = mtargetform
  25. End Property

  26. Public Property Get Left() As Long
  27.     Left = mRect.Left
  28. End Property

  29. Public Property Let Left(Value As Long)
  30.     mRect.Left = Value
  31. End Property

  32. Public Property Get Right() As Long
  33.     Right = mRect.Right
  34. End Property

  35. Public Property Let Right(Value As Long)
  36.     mRect.Right = Value
  37. End Property

  38. Public Property Get Top() As Long
  39.     Top = mRect.Top
  40. End Property

  41. Public Property Let Top(Value As Long)
  42.     mRect.Top = Value
  43. End Property

  44. Public Property Get Bottom() As Long
  45.     Bottom = mRect.Bottom
  46. End Property

  47. Public Property Let Bottom(Value As Long)
  48.     mRect.Bottom = Value
  49. End Property

  50. Public Property Get Width() As Long
  51.     Width = Abs(mRect.Right - mRect.Left)
  52. End Property

  53. Public Property Get Height() As Long
  54.     Height = Abs(mRect.Bottom - mRect.Top)
  55. End Property

  56. Public Property Get IsMouseOn() As Boolean
  57.     IsMouseOn = mIsMouseOn
  58. End Property

  59. Public Property Let IsMouseOn(Value As Boolean)
  60.     mIsMouseOn = Value
  61. End Property

  62. Public Property Get Selected() As Boolean
  63.     Selected = mSelected
  64. End Property

  65. Public Property Let Selected(Value As Boolean)
  66.     mSelected = Value
  67. End Property
復制代碼

     有些屬性我在前面沒有提到,而在代碼里又有,比如Width、Height,這個是寬度、高度,這個都是根據(jù)其他屬性值來計算得到的。當然這里我再給大家提一下類模塊的屬性建立問題。     前面有很多私有變量聲明,我這里把它們叫做類模塊的字段,它們都是以m開頭的,之后我所有的代碼都是以m開頭來代表類模塊中的字段,與這些字段對應的Get/Let屬性方法表示對這些字段的讀取/寫入操作。類模塊中建立字段、屬性的標準范式就是如此,應該避免使用公用變量。如果你對類模塊的屬性建立不是很清楚,還請在論壇或百度查閱相關的內容。




點擊這里給我發(fā)消息

3#
 樓主| 發(fā)表于 2015-3-16 14:18:34 | 只看該作者

第二部分 構建Tabs集合

本帖最后由 站到終點站 于 2015-3-16 19:13 編輯

     前面第一部分大家已經(jīng)看到了clsAccTabBar的代碼,內容是不是比較簡單?確實比較簡單,因為很多東西我都把它放到了TabControl里面實現(xiàn)了。大家對于clsAccTabBar這個類模塊牢記2點:其一:這個類模塊與之前所分析的模型中Tab對應,它將是某個具體Tab對象的模板代碼;
其二:這個類模塊所實現(xiàn)的功能就是用于記錄每一個Tab的信息,在運行時,這個類模塊幫助我們把這些信息存儲在內存中;當要進行重畫時,我們又可以使用這個類模塊讀取數(shù)據(jù),用GDI把所有Tab畫出來,或者畫其中某幾個Tab;
     下面我們就來看看TabControl跟Tabs的實現(xiàn)吧,關于繪圖的內容我將會在后面再單獨說,因為后面我們還會將繪圖部分的功能單獨寫入一個類模塊中。我們先從最簡單的Tabs來分析吧,稍后再看TabControl。Tabs是一個Tab的集合,我們直接使用Collection對象,雖然可能使用這個集合對象對于集合項目數(shù)較多時,性能會下降,但是我想誰也不可能在一個程序界面里出來個成百上千的Tab標簽頁吧!對于一個集合,我們所需要的功能包括添加、刪除以及查找,而Collection對象都有現(xiàn)成的,確實方便多了。
      首先我們要在TabControl窗體代碼里面聲明一個mTabBars的Collection對象:
  1. Private mTabBars As New Collection
復制代碼
      這里我直接用New聲明了,也就是說這個TabControl“控件”被初始化時,就會在內存里分配空間給mTabBars(當然大家也可以不這么做,而是在添加TabBar方法里面對mTabBars進行檢測,如果是nothing,就使用Set mTabBars=New Collection)。然后在窗體的UnLoad事件里面將mTabBars置為Nothing。這里啰嗦一句,實際編程的時候,大家要養(yǎng)成習慣,對需要進行清理的對象變量或者API中的一些資源對象,當存在調用代碼時,立即在相應處添加清理代碼,這樣可以減少很多莫名奇妙的錯誤,特別是在VBA中使用API進行GDI編程時,這個好習慣可以幫助你減少很多不必要的調試麻煩。例如下面的ReleaseDC,它是GDI操作中的一個API函數(shù),用于清除設備環(huán)境(DC)引用,mFormMainHwnd是對應的窗口句柄,mMainDC就是這個設備環(huán)境,設備環(huán)境是Windows非常珍貴的系統(tǒng)資源,如果用了不記得及時“還回”給系統(tǒng),會造成程序莫名其妙出錯,而且沒有任何錯誤提示,甚至造成系統(tǒng)崩潰!
  1. Private Sub Form_Unload(Cancel As Integer)
  2.     ReleaseDC mFormMainHwnd, mMainDC
  3.     Set mTabBars = Nothing
  4. End Sub
復制代碼
     下面我們再來看看如何向這個集合對象添加TabBar進去:
  1. Public Sub AddTabBar(ByVal Key As String, ByVal Text As String, ByVal TargetForm As String)
  2.     Dim mTabBar As New clsAccTabBar
  3.     Dim lngText As Long
  4.     Dim mTextSize As Size
  5.    
  6.     lngText = LenB(StrConv(Text, vbFromUnicode))
  7.     GetTextExtentPoint32 mMainDC, Text, lngText, mTextSize

  8.     If TabCount = 0 Then
  9.         mTabBar.Left = 0
  10.         mTabBar.Top = 0
  11.         mTabBar.Right = mTextSize.cx + 16
  12.         mTabBar.Bottom = 30
  13.     Else
  14.         mTabBar.Left = mTabBars(TabCount).Right + 0.6
  15.         mTabBar.Top = 0
  16.         mTabBar.Right = mTabBar.Left + mTextSize.cx + 16
  17.         mTabBar.Bottom = 30
  18.     End If
  19.     mTabBar.Text = Text
  20.     mTabBars.Add mTabBar
  21.     ReDrawTabBar mTabBars.count
  22. End Sub
復制代碼
     方法有3個參數(shù),前2個通過英文名就知道是什么意思,里面的代碼我還沒有使用到Key,只使用了Text,最后一個參數(shù)是個預留參數(shù),暫時也沒有用到。下面講下代碼內容,聲明了3個變量,第一個mTabBar用于保存需要添加的TabBar的相關數(shù)據(jù),第二個lngText保存Text字符串的長度,這個參數(shù)傳遞給API函數(shù)GetTextExtentPoint32,用于獲取字符串的實際顯示像素寬度;第三個mTextSize用于保存GetTextExtentPoint32函數(shù)運算后,所獲得的字符串實際顯示像素寬高值,它是一個Size的數(shù)據(jù)結構,代碼如下:
  1. Private Declare Function GetTextExtentPoint32 Lib "gdi32" Alias "GetTextExtentPoint32A" ( _
  2.     ByVal hdc As Long, _
  3.     ByVal lpsz As String, _
  4.     ByVal cbString As Long, _
  5.     lpSize As Size) As Long

  6. Public Type Size
  7.     cx   As Long
  8.     cy   As Long
  9. End Type
復制代碼
      需要提醒的是,GetTextExtentPoint32的聲明最好放在TabControl的代碼窗口中,Size的聲明最好放在單獨的模塊代碼中。GetTextExtentPoint32函數(shù)所使用mMainDC參數(shù)指的是主體窗口的設備環(huán)境DC,大家只需要知道這個東西就可以了,因為只有得到這個才能調用GDI進行繪圖,關于繪圖我再專門講述,所以這里大家不用糾結這個,記住它是個與主體相關的畫圖用的設備環(huán)境就行了。然后后面的代碼意圖是當mTabBars沒有TabBar時,直接寫入首個TabBar的數(shù)據(jù),其中的Right值是字符寬度加上16(左右邊距合計16個像素),當有TabBar時,根據(jù)前一個TabBar的數(shù)據(jù)設置當前添加TabBar的數(shù)據(jù)。隨后將這個TabBar添加到集合中,并調用ReDrawTabBar方法把這個TabBar畫出來。
     下面我們再來說下TabBar的刪除操作,刪除TabBar不僅僅是將其從mTabBars集合中清除掉,還要將窗體上的圖像進行重繪,用背景色填充掉原先TabBar所在的位置,給查看者的感覺就是被刪除掉了。代碼如下,其中有2行代碼(首行與末行)被我注釋掉了,因為關于GDI繪圖的方法我暫時還是寫在了TabControl的代碼里面,還沒有完成對clsAccGDI類模塊的代碼,后面在說到GDI繪圖時我還是繼續(xù)講述TabControl中的代碼,大家有興趣可以自己寫寫clsAccGDI類模塊。
  1. Public Sub RemoveTabBar()
  2. On Error GoTo Err_Handle
  3.     'Dim FormDrawer As New clsAccGDI
  4.     Dim mRect As Rect
  5.     Dim mLastIndex As Integer
  6.    
  7.     mLastIndex = mTabBars.count
  8.    
  9.     mRect.Left = mTabBars(mLastIndex).Left
  10.     mRect.Right = mTabBars(mLastIndex).Right
  11.     mRect.Bottom = mTabBars(mLastIndex).Bottom
  12.     mRect.Top = mTabBars(mLastIndex).Top
  13.     FillTargetRect RGB(255, 255, 255), mRect
  14.     mTabBars.Remove mLastIndex
  15.     GoTo Exit_Sub
  16. Err_Handle:
  17.     MsgBox "出錯!"
  18. Exit_Sub:
  19.     'Set FormDrawer = Nothing
  20. End Sub
復制代碼
     接下來我們再來看看如何在mTabBars中找到制定的TabBar,由于我之前的代碼沒有使用到Key,所以這里也沒有基于Key來定位TabBar,我也沒有寫一個專門用于定位TabBar的方法,只是使用了最通用的For循環(huán)來查找,如果大家覺得不好,可以自己寫個定位TabBar的方法。我這里把主體的MouseMove事件代碼列出來說明下我搜索的方法。
  1. Private Sub 主體_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
  2.     Dim intX As Integer
  3.     Dim pX As Long, pY As Long
  4.     Dim mCurrentOn As Integer
  5.    
  6.     pX = X / TwipsPerPixelX()
  7.     pY = Y / TwipsPerPixelY()
  8.    
  9.     For intX = 1 To mTabBars.count
  10.         If pX >= mTabBars(intX).Left And pX <= mTabBars(intX).Right And _
  11.             pY >= mTabBars(intX).Top And pY <= mTabBars(intX).Bottom Then
  12.             mTabBars(intX).IsMouseOn = True
  13.             ReDrawTabBar intX
  14.             mCurrentOn = intX
  15.             Exit For
  16.         End If
  17.         'Debug.Print "(x,y):(" & pX & "," & py & ")" & vbTab & "(Rx):(" & mTabBars(intX).Left & ")"
  18.     Next
  19.     If mPreTabBarOn <> mCurrentOn Then
  20.         If mPreTabBarOn > 0 Then
  21.             mTabBars(mPreTabBarOn).IsMouseOn = False
  22.             ReDrawTabBar mPreTabBarOn
  23.         End If
  24.         mPreTabBarOn = mCurrentOn
  25.     End If
  26.     'ReDraw
  27.     mMousePoint.X = pX
  28.     mMousePoint.Y = pY
  29. End Sub
復制代碼
     說明下以上代碼的意思,intX是個循環(huán)變量,在For循環(huán)中作為Index來遍歷mTabBars集合,px,py是鼠標的坐標位置(像素值),VBA中MouseMove事件中返回X,Y是以Twip為單位的值,所以需要使用TwipsPerPixelX、TwipsPerPixelY自定義函數(shù)將其轉換為像素值。建立一個模塊mdlSysInfo,然后復制一下代碼到模塊中。隨后以上的代碼通過鼠標坐標值來判斷其所在TabBar,找到時,完成一系列的設置操作,包括設置TabBar的IsMouseOn屬性,重畫TabBar并保存當前所處TabBar在mTabBars中的序號。隨后再對之前鼠標所在的TabBar重畫,并修改其IsMouseOn屬性、保存之前鼠標所在TabBar的序號。最后保存鼠標當前位置數(shù)據(jù),這個數(shù)據(jù)會在Click事件中使用到。
  1. Option Compare Database
  2. Option Explicit

  3. Public Type Size
  4.     cx   As Long
  5.     cy   As Long
  6. End Type

  7. Private Declare Function GetDC Lib "user32" (ByVal Hwnd As Long) As Long
  8. Private Declare Function ReleaseDC Lib "user32" (ByVal Hwnd As Long, ByVal hdc As Long) As Long
  9. Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long

  10. Private Const HWND_DESKTOP As Long = 0
  11. Private Const LOGPIXELSX As Long = 88
  12. Private Const LOGPIXELSY As Long = 90
  13.          
  14. 'Returns the width of a pixel, in twips.
  15. Public Function TwipsPerPixelX() As Single
  16.   Dim lngDC As Long
  17.   
  18.   lngDC = GetDC(HWND_DESKTOP)
  19.   TwipsPerPixelX = 1440& / GetDeviceCaps(lngDC, LOGPIXELSX)
  20.   ReleaseDC HWND_DESKTOP, lngDC
  21. End Function

  22. 'Returns the height of a pixel, in twips.
  23. Public Function TwipsPerPixelY() As Single
  24.   Dim lngDC As Long
  25.   
  26.   lngDC = GetDC(HWND_DESKTOP)
  27.   TwipsPerPixelY = 1440& / GetDeviceCaps(lngDC, LOGPIXELSY)
  28.   ReleaseDC HWND_DESKTOP, lngDC
  29. End Function
復制代碼







點擊這里給我發(fā)消息

4#
 樓主| 發(fā)表于 2015-3-16 14:18:45 | 只看該作者

第三部分 實現(xiàn)TabControl的功能

本帖最后由 站到終點站 于 2015-3-17 11:38 編輯

     上一個部分我們已經(jīng)講了Tabs的功能實現(xiàn),功能和代碼部分可能還比較粗糙,有興趣的可以自行完善下,下面我們來講整個自定義“控件”的重點之一:TabControl子窗體容器的功能實現(xiàn)。TabControl子窗體是我們所謂的自定義“控件”的容器,同之前我們對Tab一樣,我們也首先來分析下TabControl的各種特征。
1、必要的字段:窗體的各種句柄(子窗體句柄、窗體頁眉句柄、窗體主體句柄、窗體頁腳句柄)、設備環(huán)境(窗體主體的設備環(huán)境)、各種顏色相關的設置(鼠標在其上背/前景色、被選中背/前景色、默認背/前景色)、前一個鼠標移動到的TabBar序號、前一個被選中的TabBar序號、TabBar的集合以及鼠標當前位置;
      這里的設備環(huán)境我只使用了窗體主體的設備環(huán)境,因為在實例中我只使用主體,頁眉頁腳都隱藏了。其他還有部分字段并非是必要的,只是為了擴充完善功能新加入的,這里我就不再說明了,你可以自行根據(jù)需要添加修改。
2、與方法相關:添加與刪除TabBar(這2個方法在前面講Tabs集合的時候已經(jīng)詳細說了)、畫TabBar方法(包括畫所有Tab與畫單個Tab)、前面這些方法都是共有的,就是使用這個控件時,我們可以看到這些方法,另外還有一個私有方法FillTargetRect,這個方法是用于畫一個實心矩形的,它被畫TabBar方法所調用,當使用TabControl這個控件時,這個方法是不可見的。
3、與事件相關:“控件”的初始化事件(就是TabControl窗體的Load事件,完成各種內置字段的初始化以及添加3個默認TabBar)、“控件”的銷毀事件(就是TabControl窗體的UnLoad事件,完成各種對象和設備環(huán)境的清理工作)、“控件”的單擊事件(通過主體的Click事件實現(xiàn))用于根據(jù)鼠標單擊位置觸發(fā)TabBar單擊事件、“控件”的鼠標移動事件(通過主體的MouseMove事件實現(xiàn))、“控件”重繪事件(通過主體的Paint事件實現(xiàn))用于重繪所有TabBar,以上所有事件都借助于窗體的事件來實現(xiàn),另外還有一個自定義事件TabClick,該事件在“控件”的單擊事件中被觸發(fā),同時反饋一個被單擊TabBar的序號。      由于帖子內容過長,代碼無法放下,我將TabControl的代碼分成2段放了。這里面的代碼還是有些Bug,大家自己可以參照著修改下,我一時半會兒還沒法去調試這些Bug,當然大致的問題都不多,可能會是添加刪除,以及鼠標移動時,可能會因為mPreTabBarSelected、mPreTabBarOn找不到而出現(xiàn)錯誤。
  1. Option Compare Database

  2. '****************************************************************************
  3. '發(fā)布日期:2015/03/16
  4. '描    述:在Access中通過子窗體實現(xiàn)自繪TabControl控件
  5. 'E-mail  :alex_ywt@163.com
  6. 'QQ      :21959068
  7. '          如需引用源代碼,請注釋代碼出處
  8. '****************************************************************************

  9. Private Declare Function SetBkMode Lib "gdi32" ( _
  10.     ByVal hdc As Long, _
  11.     ByVal nBkMode As Long) As Long
  12. Private Declare Function GetDC Lib "user32" (ByVal Hwnd As Long) As Long
  13. Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
  14. Private Declare Function ReleaseDC Lib "user32" ( _
  15.     ByVal Hwnd As Long, _
  16.     ByVal hdc As Long) As Long
  17. Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
  18. Private Declare Function GetWindowDC Lib "user32" (ByVal Hwnd As Long) As Long
  19. Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _
  20.     ByVal hWnd1 As Long, _
  21.     ByVal hWnd2 As Long, _
  22.     ByVal lpsz1 As String, _
  23.     ByVal lpsz2 As String) As Long
  24.    
  25. Private Declare Function Polygon Lib "gdi32" ( _
  26.     ByVal hdc As Long, _
  27.     lpPoint As POINTAPI, _
  28.     ByVal nCount As Long) As Long
  29. Private Declare Function Rectangle Lib "gdi32" ( _
  30.     ByVal hdc As Long, _
  31.     ByVal X1 As Long, _
  32.     ByVal Y1 As Long, _
  33.     ByVal X2 As Long, _
  34.     ByVal Y2 As Long) As Long
  35. Private Declare Function LoadImage Lib "user32" Alias "LoadImageA" ( _
  36.     ByVal hInst As Long, _
  37.     ByVal lpsz As String, _
  38.     ByVal un1 As Long, _
  39.     ByVal n1 As Long, _
  40.     ByVal n2 As Long, _
  41.     ByVal un2 As Long) As Long
  42. Private Declare Function BitBlt Lib "gdi32" ( _
  43.     ByVal hDestDC As Long, _
  44.     ByVal x As Long, _
  45.     ByVal y As Long, _
  46.     ByVal nWidth As Long, _
  47.     ByVal nHeight As Long, _
  48.     ByVal hSrcDC As Long, _
  49.     ByVal xSrc As Long, _
  50.     ByVal ySrc As Long, _
  51.     ByVal dwRop As Long) As Long
  52. Private Declare Function CreateBitmap Lib "gdi32" ( _
  53.     ByVal nWidth As Long, _
  54.     ByVal nHeight As Long, _
  55.     ByVal nPlanes As Long, _
  56.     ByVal nBitCount As Long, _
  57.     lpBits As Any) As Long
  58. Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
  59. Private Declare Function CreatePatternBrush Lib "gdi32" (ByVal hBitMap As Long) As Long
  60. Private Declare Function SelectObject Lib "gdi32" ( _
  61.     ByVal hdc As Long, _
  62.     ByVal hObject As Long) As Long
  63. Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" ( _
  64.     ByVal hObject As Long, _
  65.     ByVal nCount As Long, _
  66.     lpObject As Any) As Long
  67. Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
  68. Private Declare Function InvalidateRectAsAny Lib "user32" Alias "InvalidateRect" ( _
  69.     ByVal Hwnd As Long, _
  70.     lpRect As Any, _
  71.     ByVal bErase As Long) As Long
  72. Private Declare Function FillRect Lib "user32" ( _
  73.     ByVal hdc As Long, _
  74.     lpRect As Rect, _
  75.     ByVal hBrush As Long) As Long
  76. Private Declare Function GetTextExtentPoint32 Lib "gdi32" Alias "GetTextExtentPoint32A" ( _
  77.     ByVal hdc As Long, _
  78.     ByVal lpsz As String, _
  79.     ByVal cbString As Long, _
  80.     lpSize As Size) As Long
  81. Private Declare Function DrawText Lib "user32" Alias "DrawTextA" ( _
  82.     ByVal hdc As Long, _
  83.     ByVal lpStr As String, _
  84.     ByVal nCount As Long, _
  85.     lpRect As Rect, _
  86.     ByVal wFormat As Long) As Long

  87. Private Const IMAGE_BITMAP = 0
  88. Private Const LR_LOADFROMFILE = &H10
  89. Private Const LR_CREATEDIBSECTION = &H2000

  90. Private Const TRANSPARENT = 1

  91. 'wFormat文字輸出格式,DT即Draw Text
  92. Private Const DT_BOTTOM = &H8 '靠底輸出,必須與DT_SINGLELINE配合(用OR)
  93. Private Const DT_CENTER = &H1  '居中
  94. Private Const DT_CALCRECT = &H400  '自動計算(調整)輸出區(qū)域的大小
  95. Private Const DT_EXPANDTABS = &H40   '將Tab字符視為定位點
  96. Private Const DT_EXTERNALLEADING = &H200 '包含行間距
  97. Private Const DT_LEFT = &H0           '居左
  98. Private Const DT_NOCLIP = &H100    '文字輸出不受限于輸出區(qū)域
  99. Private Const DT_NOPREFIX = &H800 '不處理前導字符&。若不指定,會把緊跟的字母加下劃線(類似定義菜單快捷鍵)
  100. Private Const DT_RIGHT = &H2       '居右
  101. Private Const DT_SINGLELINE = &H20  '單行輸出
  102. Private Const DT_TABSTOP = &H80   '設置定位點,wFormat中高字節(jié)8-15位表示定位點的寬度(默認8)
  103. Private Const DT_TOP = &H0       '居上,須與DT_SINGLELINE配合
  104. Private Const DT_VCENTER = &H4   '垂直居中,須與DT_SINGLELINE配合
  105. Private Const DT_WORDBREAK = &H10 '超過右邊界時,自動換行

  106. Private mFormHwnd As Long
  107. Private mFormHeaderHwnd As Long
  108. Private mFormMainHwnd As Long
  109. Private mFormFooterHwnd As Long
  110. Private mMainDC As Long
  111. Private mCurrentDrawTarget As ENUM_DrawTarget

  112. Private mMouseLeaveBackColor As OLE_COLOR   '鼠標移開后顯示的背景色
  113. Private mMouseOnBackColor As OLE_COLOR      '鼠標在其上顯示的背景色
  114. Private mSelectedBackColor As OLE_COLOR     '當前項被選中時的背景色

  115. Private mMouseLeaveFontColor As OLE_COLOR   '鼠標移開后顯示的前景色
  116. Private mMouseOnFontColor As OLE_COLOR      '鼠標在其上顯示的前景色
  117. Private mSelectedFontColor As OLE_COLOR     '當前項被選中時的前景色

  118. Private mMouseLeaveBorderColor As OLE_COLOR '鼠標移開后顯示的邊框色
  119. Private mMouseOnBorderColor As OLE_COLOR    '鼠標在其上顯示的邊框色
  120. Private mSelectedBorderColor As OLE_COLOR   '當前項被選中時的邊框色

  121. Private mBorderWidth As Long                '邊框的寬度

  122. Private mTabBars As New Collection
  123. Private mPreTabBarOn As Integer
  124. Private mPreTabBarSelected As Integer

  125. Private mMousePoint As POINTAPI

  126. Public Event TabClick(Index As Integer)
復制代碼




點擊這里給我發(fā)消息

5#
 樓主| 發(fā)表于 2015-3-16 14:18:59 | 只看該作者

第三部分 TabControl的實現(xiàn)代碼

本帖最后由 站到終點站 于 2015-3-17 11:40 編輯
  1. Private Sub Form_Load()
  2.     mMouseLeaveBackColor = RGB(155, 155, 155)   '鼠標移開后顯示的背景色
  3.     mMouseOnBackColor = RGB(0, 255, 255)      '鼠標在其上顯示的背景色
  4.     mSelectedBackColor = RGB(255, 0, 0)    '當前項被選中時的背景色
  5.    
  6.     mMouseLeaveFontColor = RGB(255, 255, 255)   '鼠標移開后顯示的前景色
  7.     mMouseOnFontColor = RGB(0, 0, 255)          '鼠標在其上顯示的前景色
  8.     mSelectedFontColor = RGB(0, 0, 0)           '當前項被選中時的前景色

  9.     mMouseLeaveBorderColor = RGB(155, 155, 155) '鼠標移開后顯示的邊框色
  10.     mMouseOnBorderColor = RGB(155, 155, 155)    '鼠標在其上顯示的邊框色
  11.     mSelectedBorderColor = RGB(155, 155, 155)   '當前項被選中時的邊框色
  12.    
  13.     mFormHeaderHwnd = FindWindowEx(Me.Hwnd, 0&, "OFormSub", vbNullString)
  14.     mFormMainHwnd = FindWindowEx(Me.Hwnd, mFormHeaderHwnd, "OFormSub", vbNullString)
  15.     mMainDC = GetWindowDC(mFormMainHwnd)
  16.    
  17.     SetBkMode mMainDC, TRANSPARENT
  18.    
  19.     Me.InsideHeight = 30 * TwipsPerPixelY
  20.     For I = 1 To 3
  21.         AddTabBar "", "Tab" & I, ""
  22.     Next
  23.     'ReDraw
  24. End Sub

  25. Private Sub Form_Unload(Cancel As Integer)
  26.     ReleaseDC mFormMainHwnd, mMainDC
  27.     Set mTabBars = Nothing
  28. End Sub

  29. Private Sub 主體_Click()
  30.     Dim intX As Integer
  31.     Dim mCurrentSelected As Integer
  32.    
  33.     For intX = 1 To mTabBars.count
  34.         If mMousePoint.x >= mTabBars(intX).Left And mMousePoint.x <= mTabBars(intX).Right And _
  35.             mMousePoint.y >= mTabBars(intX).Top And mMousePoint.y <= mTabBars(intX).Bottom Then
  36.             mTabBars(intX).Selected = True
  37.             ReDrawTabBar intX
  38.             mCurrentSelected = intX
  39.             Exit For
  40.         End If
  41.         'Debug.Print "(x,y):(" & pX & "," & py & ")" & vbTab & "(Rx):(" & mTabBars(intX).Left & ")"
  42.     Next
  43.     If mPreTabBarSelected <> mCurrentSelected Then
  44.         If mPreTabBarSelected > 0 And mCurrentSelected > 0 Then
  45.             mTabBars(mPreTabBarSelected).Selected = False
  46.             ReDrawTabBar mPreTabBarSelected
  47.         End If
  48.         mPreTabBarSelected = mCurrentSelected
  49.         RaiseEvent TabClick(mCurrentSelected)
  50.     End If
  51. End Sub

  52. Private Sub 主體_DblClick(Cancel As Integer)
  53.     'Static dblClickCount As Long
  54.     'dblClickCount = dblClickCount + 1
  55.     'AddTabBar "", "雙擊添加Tab" & dblClickCount, ""
  56.     'ReDraw
  57. End Sub

  58. Private Sub 主體_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
  59.     Dim intX As Integer
  60.     Dim pX As Long, pY As Long
  61.     Dim mCurrentOn As Integer
  62.    
  63.     pX = x / TwipsPerPixelX()
  64.     pY = y / TwipsPerPixelY()
  65.    
  66.     For intX = 1 To mTabBars.count
  67.         If pX >= mTabBars(intX).Left And pX <= mTabBars(intX).Right And _
  68.             pY >= mTabBars(intX).Top And pY <= mTabBars(intX).Bottom Then
  69.             mTabBars(intX).IsMouseOn = True
  70.             ReDrawTabBar intX
  71.             mCurrentOn = intX
  72.             Exit For
  73.         End If
  74.         'Debug.Print "(x,y):(" & pX & "," & py & ")" & vbTab & "(Rx):(" & mTabBars(intX).Left & ")"
  75.     Next
  76.     If mPreTabBarOn <> mCurrentOn Then
  77.         If mPreTabBarOn > 0 Then
  78.             mTabBars(mPreTabBarOn).IsMouseOn = False
  79.             ReDrawTabBar mPreTabBarOn
  80.         End If
  81.         If mCurrentOn > 0 Then
  82.             mPreTabBarOn = mCurrentOn
  83.         Else
  84.             mPreTabBarOn = 0
  85.         End If
  86.     End If
  87.     'ReDraw
  88.     mMousePoint.x = pX
  89.     mMousePoint.y = pY
  90. End Sub

  91. Private Sub 主體_Paint()
  92.     ReDraw
  93. End Sub

  94. Public Property Get TabCount() As Long
  95.     TabCount = mTabBars.count
  96. End Property

  97. Public Sub AddTabBar(ByVal Key As String, ByVal Text As String, ByVal TargetForm As String)
  98.     Dim mTabBar As New clsAccTabBar
  99.     Dim lngText As Long
  100.     Dim mTextSize As Size
  101.    
  102.     lngText = LenB(StrConv(Text, vbFromUnicode))
  103.     GetTextExtentPoint32 mMainDC, Text, lngText, mTextSize

  104.     If TabCount = 0 Then
  105.         mTabBar.Left = 0
  106.         mTabBar.Top = 0
  107.         mTabBar.Right = mTextSize.cx + 16
  108.         mTabBar.Bottom = 30
  109.     Else
  110.         mTabBar.Left = mTabBars(TabCount).Right + 0.6
  111.         mTabBar.Top = 0
  112.         mTabBar.Right = mTabBar.Left + mTextSize.cx + 16
  113.         mTabBar.Bottom = 30
  114.     End If
  115.     mTabBar.Text = Text
  116.     mTabBars.Add mTabBar
  117.     ReDrawTabBar mTabBars.count
  118. End Sub

  119. Public Sub RemoveTabBar()
  120. On Error GoTo Err_Handle
  121.     'Dim FormDrawer As New clsAccGDI
  122.     Dim mRect As Rect
  123.     Dim mLastIndex As Integer
  124.    
  125.     mLastIndex = mTabBars.count
  126.    
  127.     mRect.Left = mTabBars(mLastIndex).Left
  128.     mRect.Right = mTabBars(mLastIndex).Right
  129.     mRect.Bottom = mTabBars(mLastIndex).Bottom
  130.     mRect.Top = mTabBars(mLastIndex).Top
  131.     FillTargetRect RGB(255, 255, 255), mRect
  132.     If mTabBars(mLastIndex).Selected Then mPreTabBarSelected = 0
  133.     'rt = DrawText(mMainDC, mTabBars(Index).Text, LenB(StrConv(mTabBars(Index).Text, vbFromUnicode)), mRect, DT_CENTER Or DT_VCENTER Or DT_SINGLELINE)
  134.     mTabBars.Remove mLastIndex
  135.     GoTo Exit_Sub
  136. Err_Handle:
  137.     MsgBox "出錯!"
  138. Exit_Sub:
  139.     'Set FormDrawer = Nothing
  140. End Sub

  141. Public Sub ReDraw()
  142. On Error GoTo Err_Handle
  143.     'Dim FormDrawer As New clsAccGDI
  144.     Dim mRect As Rect
  145.     Dim mTabCount As Long
  146.    
  147.     mTabCount = TabCount
  148.    
  149.     For I = 1 To mTabCount
  150.         mRect.Left = mTabBars(I).Left
  151.         mRect.Right = mTabBars(I).Right
  152.         mRect.Bottom = mTabBars(I).Bottom
  153.         mRect.Top = mTabBars(I).Top
  154.         If mTabBars(I).Selected Then
  155.             FillTargetRect RGB(255, 0, 0), mRect
  156.         Else
  157.             If mTabBars(I).IsMouseOn Then
  158.                 FillTargetRect RGB(0, 255, 0), mRect
  159.             Else
  160.                 FillTargetRect RGB(255, 255, 0), mRect
  161.             End If
  162.         End If
  163.         rt = DrawText(mMainDC, mTabBars(I).Text, LenB(StrConv(mTabBars(I).Text, vbFromUnicode)), mRect, DT_CENTER Or DT_VCENTER Or DT_SINGLELINE)
  164.     Next

  165.     GoTo Exit_Sub
  166. Err_Handle:
  167.     MsgBox "出錯!"
  168. Exit_Sub:
  169.     'Set FormDrawer = Nothing
  170. End Sub

  171. Public Sub ReDrawTabBar(Index As Integer)
  172. On Error GoTo Err_Handle
  173.     'Dim FormDrawer As New clsAccGDI
  174.     Dim mRect As Rect
  175.    
  176.     mRect.Left = mTabBars(Index).Left
  177.     mRect.Right = mTabBars(Index).Right
  178.     mRect.Bottom = mTabBars(Index).Bottom
  179.     mRect.Top = mTabBars(Index).Top
  180.     If mTabBars(Index).Selected Then
  181.         FillTargetRect RGB(255, 0, 0), mRect
  182.     Else
  183.         If mTabBars(Index).IsMouseOn Then
  184.             FillTargetRect RGB(0, 255, 0), mRect
  185.         Else
  186.             FillTargetRect RGB(255, 255, 0), mRect
  187.         End If
  188.     End If
  189.     rt = DrawText(mMainDC, mTabBars(Index).Text, LenB(StrConv(mTabBars(Index).Text, vbFromUnicode)), mRect, DT_CENTER Or DT_VCENTER Or DT_SINGLELINE)

  190.     GoTo Exit_Sub
  191. Err_Handle:
  192.     MsgBox "出錯!"
  193. Exit_Sub:
  194.     'Set FormDrawer = Nothing
  195. End Sub

  196. Private Sub FillTargetRect(DrawColor As OLE_COLOR, TargetRect As Rect)
  197.     Dim hOldBrush As Long
  198.     Dim hBrush As Long
  199.    
  200.     hBrush = CreateSolidBrush(CLng(DrawColor))
  201.     hOldBrush = SelectObject(mMainDC, hBrush)
  202.     FillRect mMainDC, TargetRect, hBrush
  203.     'Rectangle hdc, TargetRect.Left, TargetRect.Top, TargetRect.Right, TargetRect.Bottom
  204.     SelectObject mMainDC, hOldBrush
  205.     DeleteObject hBrush
  206. End Sub
復制代碼


點擊這里給我發(fā)消息

6#
 樓主| 發(fā)表于 2015-3-16 14:19:12 | 只看該作者

第四部分 TabControl控件的使用

本帖最后由 站到終點站 于 2015-3-17 13:43 編輯

     到此為止,相關的一些核心代碼已經(jīng)全部貼出來了,TabControl窗體中的代碼包含了很多的API函數(shù)聲明,并在TabControl中通過GDI完成了繪圖操作,但是我暫時還不打算去解釋這些API函數(shù)以及Access中如何通過GDI進行繪圖。我先說明下如何來使用這個TabControl控件。因為即使使用的人不知道TabControl是如何具體實現(xiàn)其功能的,也不妨礙使用它。通過我們所提供的屬性、方法以及事件就可以操作這個控件,這就是面向對象編程的好處。類模塊或者窗體封裝后,使用人只需要知道其公用的屬性、方法以及事件(也就是我們流行講的接口),就可以輕松使用這些東西,跟我們Access內置的其他控件一樣。
      好吧,那么我們就先來看看frmTest窗體是如何使用TabControl這個子窗體控件的。這個窗體的界面非常簡單,包括一個子窗體以及2個按鈕(添加喝刪除),將之前所建立的TabControl窗體直接拖入frmTest窗體中就可以建立一個子窗體。下面我們來看看它的代碼:
  1. Option Compare Database

  2. '****************************************************************************
  3. '發(fā)布日期:2015/03/16
  4. '描    述:自繪TabControl控件的測試窗體
  5. 'E-mail  :alex_ywt@163.com
  6. 'QQ      :21959068
  7. '          如需引用源代碼,請注釋代碼出處
  8. '****************************************************************************

  9. Private WithEvents mTabControl As Form_TabControl

  10. Private Sub cmdAdd_Click()
  11.     Static iCount As Integer
  12.     iCount = iCount + 1
  13.     mTabControl.AddTabBar "", "UserTab" & iCount, ""
  14. End Sub

  15. Private Sub cmdDelete_Click()
  16.     mTabControl.RemoveTabBar
  17. End Sub

  18. Private Sub mTabControl_TabClick(Index As Integer)
  19.     MsgBox Index
  20. End Sub

  21. Private Sub 主體_Paint()
  22.     Set mTabControl = Me.TabControl1.Form
  23. End Sub
復制代碼
     窗體的代碼非常簡單,熟悉面向對象編程及事件使用的朋友還會感覺代碼非常熟悉,那么下面我就來簡單的說下:     我們把TabControl視作控件后,并且要使用它的事件,所以我們需要聲明一個WithEvents標識的Form_TabControl對象變量,并且將其聲明為私有的,這里不用New,因為我們要將其與窗體上的那個子窗體關聯(lián)起來。那么關聯(lián)的時機這里需要注意下,因為在Access中窗體加載的時候不一定子窗體會同是完成加載,所以Set mTabControl = Me.TabControl1.Form這句不能放在窗體的Load事件中,我這里選擇了主體的Paint事件,這個時候子窗體必定完成了加載,所以此時的Me.TabControl1.Form必定不會為Nothing。
     2個按鈕的單擊事件非常簡單,直接調用TabControl控件的相應方法即可,而TabClick事件直接通過事件選擇欄選擇出來就行(如果大家不知道如何弄出這個mTabControl_TabClick事件過程的話,可以百度或者論壇上去看看VBA中類模塊的自定義事件的內容)。最后我在補充一句要獲取子窗體中的窗體對象,需要使用子窗體的Form屬性,Access的子窗體只是一個容器。




點擊這里給我發(fā)消息

7#
 樓主| 發(fā)表于 2015-3-16 14:19:25 | 只看該作者

第五部分 Access中GDI繪圖(Access窗體結構)

本帖最后由 站到終點站 于 2015-3-20 12:02 編輯

     帖子的一個重點內容我們還沒有涉及到,這一部分我們就來研究下Access中如何進行GDI繪圖。GDI是Windows中用于完成繪圖的API函數(shù)的集合總稱,大部分的函數(shù)都包含在gdi32.dll這個動態(tài)鏈接庫文件中。要說明的是在Windows中完成繪圖,并不止GDI一種API函數(shù)集合,還有其他的,不過這也是最基礎的。當然,在Windows中無論是通過GDI還是其他的什么API函數(shù)集合,其界面最終都是畫出來的。畫一次是一個靜態(tài)的界面,不停的畫,不停的對變化區(qū)域畫就讓我們看到了動態(tài)的界面。我們通過自繪并結合鼠標移動、雙擊等事件,不停的對窗體進行重畫,就產(chǎn)生了能對用戶操作作出反應的Windows界面,也就達成了自繪控件的目的。     使用GDI繪圖類似于我們畫畫,首先我們需要準備好畫畫所需要的材料跟設備,包括畫布、畫筆、顏料、貼畫等,GDI中所對應的就有設備環(huán)境DC(相當于畫布)、畫筆、畫刷、字體、圖片等。然后我們需要構思圖畫的內容,安排下畫畫的動作次序以及一些畫畫的技巧,GDI中所對應的就是明確最終圖形的外觀、使用哪些API函數(shù)以及函數(shù)的使用先后順序。
     首先我們來解決第一個問題,就是在Access中畫圖時,如何做好材料設備的準備工作。首先我們需要一張畫布,既然我們需要在窗體中畫(我們可以把窗體看做是畫板),那就得獲取“鋪”在窗體畫板上的畫布。這個畫布是依據(jù)窗體畫板量身定做的,所以我們得根據(jù)窗體畫板的標識號來定制一個畫布,這個標識號就是窗體的句柄。我們將窗體句柄傳遞給GetWindowDC這個函數(shù)就可以獲取一個與該窗體對應的畫布。
     所以現(xiàn)在的問題就轉換為如何獲取窗體的標識符即句柄了。Access的窗體比較特殊,它包括了窗體頁眉、窗體主體、窗體頁腳三個窗體,即使沒有顯示窗體頁眉和頁腳,它們也只是被隱藏了而已。通俗點說,就是Access窗體這個畫板上還放了三塊畫板,這三塊畫板你都撤不掉,它們一定放在那塊窗體畫板的上面,只是我們可以隱藏其中幾塊而已。如果我們通過Access窗體本身的hwnd屬性獲取畫布并畫內容的話,這些畫的內容將被窗體頁眉、窗體主體和窗體頁腳所遮擋,所以我們在Access中畫圖的時候通常會在主體上進行繪畫。

點擊這里給我發(fā)消息

8#
 樓主| 發(fā)表于 2015-3-16 14:19:38 | 只看該作者
占位用7
回復

使用道具 舉報

點擊這里給我發(fā)消息

9#
 樓主| 發(fā)表于 2015-3-16 14:19:51 | 只看該作者
占位用8
回復

使用道具 舉報

點擊這里給我發(fā)消息

10#
 樓主| 發(fā)表于 2015-3-16 14:20:06 | 只看該作者
占位用9
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則

QQ|站長郵箱|小黑屋|手機版|Office中國/Access中國 ( 粵ICP備10043721號-1 )  

GMT+8, 2024-10-23 10:32 , Processed in 0.152978 second(s), 37 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回復 返回頂部 返回列表