首页 > 数据库技术 > 详细

Access-自定义控件TabControl

时间:2015-12-29 22:42:19      阅读:741      评论:0      收藏:0      [点我收藏+]
转载我之前在Access中国论坛上发的帖子:Access自定义控件TabControl
后来还发了一篇该自定义控件的使用案例:AccTabControl自定义控件应用案例

 在论坛也混了蛮长时间了,一直没有发表过什么专题性质的文章。主要是论坛上高手如云,很多学习过程中的问题在论坛上都能找到答案,特别是论坛的精华帖。通过不断学习,我也开始对一些问题形成了些自己的想法。比如最近一段时间碰到一个问题:关于Access中动态添加控件的问题,Access中要给Form动态添加控件之类的,必须切换到窗体的设计模式,即使通过VBA代码也必须这么做。以往碰到这个问题,一般的做法是在窗体中先添加固定数目的控件,然后窗体加载时将其隐藏,当需要动态添加时就将其显示出来,但是这个方法一旦超出当初添加控件的数目时,就没办法解决了,并且控件添加多了对窗体加载速度也有一定影响。另外的话也可以通过一些ActiveX控件来做到这些,不过要找到适合Access且适合自己需求的ActiveX控件并不是件容易的事情,鉴于此我就想怎么才能在窗体上动态添加控件。
       其实这个问题纠结了差不多有1年了,当初也想到来自绘这个途径,但是有好几个问题都不懂,所以解决不了。这些问题包括:
1、自绘的话,用什么在窗体上自绘?      肯定不能用Access的控件,线条、框什么的都不能用,因为这些都不能动态添加到窗体上。只有选择通过API来绘图,可以使用的包括GDI、GDI+。但是我那时对GDI和GDI+是一点了解都没有,所以画了很长时间研究VBA中用API、GDI跟GDI+。
2、要用API绘图就要有窗体句柄、要获得设备环境(DC),Access里怎么获取这些了?
     可能有些人马上会想到Access窗体有个hwnd属性啊,不就可以了吗?其实这里面还有些曲折,后面我会详细说。这里大家所要了解的是Access的窗体下面还包含了好几个,包括窗体页眉、主体跟窗体页脚,它们都有句柄,要进行绘图的话,你得获取对应的句柄,而不是直接使用Access窗体的hwnd属性。
3、以上2个问题解决了,还只是完成了在窗体上自绘,要怎样才能将这些自绘窗体像控件一样使用到其他窗体上了?
     可能大家看完这个问题,对Access有些了解的朋友会马上想到子窗体。但是当时我是想了1个星期才想到用子窗体,因为当初对这个问题我的想法是怎么在Access中做自定义控件,而没有想到怎么将窗体放到窗体里面这个方法。使用子窗体作为类似“控件”容器的承载体,这就解决的自定义控件的“容器”问题。
     好了,说完这几个问题,那么我再总结下要读懂本文内容所需要储备的知识,如果你还对以下内容完全不了解的话,我建议你首先百度下或者找找相关的书什么的了解下,当然你也可以继续读下去,因为我会尽力讲的通俗易懂。不过如果你感觉阅读的很吃力的话,那你最好还是补一补相关的内容再来。
1、VBA中如何使用API?
2、GDI是用来干什么的?如何使用GDI?GDI句柄跟设备环境的关系,如何用GDI绘图?
3、Access窗体的构成。
4、Access子窗体是什么?怎么使用子窗体?
5、VBA中的类模块是什么?怎么使用类模块?类模块属性、方法、事件怎么建立?
6、Access窗体与类模块的关系;
7、使用VBA代码怎么调用自定义“控件”?
8、集合在类模块中的使用;
     另外我也想说明一下,由于本贴内容可能会比较长,我会分批将所写内容更新进来,由于平时工作比较忙,可能一次更新的内容也不会太多,所以希望大家也不要急躁,慢慢看慢慢消化。另外相应的代码部分也有很多在调试之中,但是大部分主体的代码已经完成,我暂时不把源代码随帖子一起发布,我会将其中的大部分代码写到本贴里面并讲解,希望有兴趣的将贴看下去。


下面我们就开始讲怎么在Access来做一个类似TabControl的“控件”。
首先,我们来看下最终的效果,示例中包含了2个窗体,frmTest是个测试窗体,TabControl就是我们所谓的当作控件来使用的子窗体。另外还有些模块跟类模块,有些模块是无用的,因为我在做这个的时候,借鉴了部分代码,只是没有删除,我在后面会说到有哪些模块跟代码会使用到的,所以这里就不再说明各个模块的作用了。
双击打开frmTest,默认会建立3个框,相当于3个Tab,点击添加按钮,会自动添加Tab,点删除按钮会从最后依次删除Tab,在某个Tab上点击,会弹出一个对话框显示当前Tab的序号。

技术分享

第一部分、建立clsAccTabBar类模块

     在动手编写代码前,首先我们得分析下TabControl控件的结构,搞清楚我们需要建立什么样的模块、类模块以及窗体模块。从上面我们已经看到了我们用了一个子窗体作为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个事件的实现有些特殊,按道理应该在Tab类模块里建立这2个事件,但是鼠标的移动跟单击触发都是在TabControl里面,所以这2个事件我都把实现做到了TabControl窗体的事件代码里面了,后面讲述TabControl的时候我会再讲;
     从上面的描述来看,我基本上把这个clsAccTabBar类模块只让其用于保存各个Tab相关信息,下面是类模块里面的代码:

 1 Option Compare Database
 2 
 3 Private mIndex As Integer
 4 Private mKey As String
 5 Private mText As String
 6 Private mTargetFom As String
 7 Private mSelected As Boolean
 8 Private mIsMouseOn As Boolean
 9 
10 Public Property Get Index() As Integer
11     Index = mIndex
12 End Property
13 
14 Public Property Let Index(Value As Integer)
15     mIndex = Value
16 End Property
17 
18 Public Property Get Key() As String
19     Key = mKey
20 End Property
21 
22 Public Property Get Text() As String
23     Text = mText
24 End Property
25 
26 Public Property Let Text(Value As String)
27     mText = Value
28 End Property
29 
30 Public Property Get TargetFom() As String
31     TargetForm = mtargetform
32 End Property
33 
34 Public Property Get Left() As Long
35     Left = mRect.Left
36 End Property
37 
38 Public Property Let Left(Value As Long)
39     mRect.Left = Value
40 End Property
41 
42 Public Property Get Right() As Long
43     Right = mRect.Right
44 End Property
45 
46 Public Property Let Right(Value As Long)
47     mRect.Right = Value
48 End Property
49 
50 Public Property Get Top() As Long
51     Top = mRect.Top
52 End Property
53 
54 Public Property Let Top(Value As Long)
55     mRect.Top = Value
56 End Property
57 
58 Public Property Get Bottom() As Long
59     Bottom = mRect.Bottom
60 End Property
61 
62 Public Property Let Bottom(Value As Long)
63     mRect.Bottom = Value
64 End Property
65 
66 Public Property Get Width() As Long
67     Width = Abs(mRect.Right - mRect.Left)
68 End Property
69 
70 Public Property Get Height() As Long
71     Height = Abs(mRect.Bottom - mRect.Top)
72 End Property
73 
74 Public Property Get IsMouseOn() As Boolean
75     IsMouseOn = mIsMouseOn
76 End Property
77 
78 Public Property Let IsMouseOn(Value As Boolean)
79     mIsMouseOn = Value
80 End Property
81 
82 Public Property Get Selected() As Boolean
83     Selected = mSelected
84 End Property
85 
86 Public Property Let Selected(Value As Boolean)
87     mSelected = Value
88 End Property

 有些属性我在前面没有提到,而在代码里又有,比如Width、Height,这个是宽度、高度,这个都是根据其他属性值来计算得到的。当然这里我再给大家提一下类模块的属性建立问题。     前面有很多私有变量声明,我这里把它们叫做类模块的字段,它们都是以m开头的,之后我所有的代码都是以m开头来代表类模块中的字段,与这些字段对应的Get/Let属性方法表示对这些字段的读取/写入操作。类模块中建立字段、属性的标准范式就是如此,应该避免使用公用变量。如果你对类模块的属性建立不是很清楚,还请在论坛或百度查阅相关的内容。 

Access-自定义控件TabControl

原文:http://www.cnblogs.com/alexywt/p/5087175.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!