ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 112569|回复: 235

[原创] VBA窗体表格神器——VSFlexgrid Pro 8.0基础教程

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2018-12-31 22:57 | 显示全部楼层 |阅读模式
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖已被收录到知识树中,索引项:控件
本帖最后由 ivccav 于 2019-1-2 22:17 编辑

VSFlexGrid Pro 8.0是一款功能强大而体积小巧的表格控件,不但可以直接编辑单元格并同步到数据库,且单元格编辑方式多样,支持文本框、列表框、组合框,单元格按钮和复选框等等,还支持排序(常规排序和自定义排序)、多表头、合并单元格、汇总和OLE拖放等功能,当然还可以限制单元格编辑、隐藏行列,等等,可设计复杂的表格,是数据库前端和ERP系统开发的神器,可替代Listbox,Combobox,TextBox,Listview,Treeview等控件,一个600k的控件,同时支持VB、VC++等多种开发语言。

如此神奇的控件,网络上并无教程,就是介绍属性、方法等等,也是语焉不详,不知就里,莫非大家都闷声发大财,偷偷地用着不吭声?在Listview控件上实现一个可编辑的功能,就得使用几百行API,VSFlexGrid Pro 8.0这么好的控件如果不会用,的确有点可惜,这篇文章权且粗略地介绍一下如何使用该控件,“师傅领进门,修行看个人”,该控件共有288个属性、方法和事件,要深入地了解,只能看自己了。其实用得到的属性方法也不会很多,就算一行代码也不用,也能轻松能把数据库连接起来,实现在窗体上编辑数据库数据。本文主要涉及这几个问题,已足够日常使用了。

1. 绑定数据

1.1 ADO Data控件绑定法
1.2 直接绑定数据源
1.3 绑定控件到数组
1.4 绑定到自定义数据源
1.5 绑定的模式

2. 操作网格

2.1 认识网格的行和列
2.2 认识网格的单元格
2.3 给网格装点色彩
2.4 自动调整行高、列宽
2.5 使用复选框
2.6 使用列表框和组合框
2.7 使用掩码和自定义编辑器
2.8 数据的查询与筛选
2.9 复制、粘贴、清除内容、删除行和插入行
2.10 合并单元格做出复杂表头
2.11 拖曳行列、排序和滚动条提示
2.12 小计汇总
2.13 打印表格
2.14 导出网格数据

电子文档.zip (691.23 KB, 下载次数: 5721)

源代码和所用控件.zip (1.02 MB, 下载次数: 5922)

2019/1/2新增附件:
增删改查 测试文件.zip (548.15 KB, 下载次数: 4861)

点击获取完整中文文档






补充内容 (2019-2-28 19:54):
如控件无法使用,可直接安装完整版。

可到该帖第37楼下载官方完整版,已包括注册码:

http://club.excelhome.net/forum. ... p;extra=#pid9839254

评分

33

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-31 23:02 | 显示全部楼层

1. 绑定数据

要在网格(即VSFlexGrid,下边都简称“网格”或“网格控件”,控件命名为fg)上显示数据,首先要绑定数据库有很多种方法,可以使用ADO Data控件,Data Environment设计器等控件绑定数据库,然后赋值给VSFlexGrid的DataSource属性,也可以直接把ADO记录集赋值给DataSource属性。这里只说一下ADO 数据控件的绑定法和直接绑定ADO记录集两种方法。

1.1 ADO Data控件绑定法

所谓ADO Data控件,是指Microsoft ADO Data Control 6.0(SP6)(OLED),引用MSAdoDc.OCX。要使用该控件,只要设置ConnectionString和RecordSource两个属性就可以使用了。

设置ConnectionString属性

设置ConnectionString有3种方法,弹窗中可以看得到:

1.png
图1

方法一:使用Data Link文件的方法:

要创建Data Link文件,可随意新建一个记事本文件,把.txt后缀改为.udl,然后双击该文件,弹出设置窗口,首先选择驱动程序,Access和Excel文件可以用Jet 4.0驱动,SQL Server、MySQL、Oracle等数据库则选择相应的驱动程序:

2.png
图2

然后,在“连接”选项卡中浏览目标数据库,这里举例连接的是VB6自带的示例数据库Nwind.mdb;选择文件后,点一下“测试连接”,连通之后确定即可。

3.png
图3

这样就得到了Data Link文件,ADO Data控件就可引用了。Data Link文件中包含连接字符串:
[oledb]
; Everything after this line is an OLE DB initstring
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files\Microsoft Visual Studio\VB98\NWIND.MDB;Persist Security Info=False

方法二:使用ODBC数据资源名称:

控制面板\所有控制面板项\管理工具\数据源(ODBC),在“用户DSN”选项卡中点“添加”,同样地,首先选择驱动程序,这里连接的是Access数据库,所以选Access驱动。所谓DSN(Data Source Name),顾名思义,就是数据源名称,很好懂,不解释。

4.png
图4

选好驱动之后,点击“完成”。

5.png
图5

然后弹出如下对话框,给你的DSN取个动听的且大家看得懂的名字。然后点击“选择…”,选择你的数据库位置,选好之后确定即可。其他选项可按需要选择。

6.png
图6

7.png
图7

这样在用户数据源中,就有你创建的DSN了。ADO Data控件也会列出可用的DSN列表以供选择。也可以点击旁边的“新建…”按钮创建DSN而不通过控制面板。个人喜好而定。

方法三:使用连接字符串:

各种数据库的连接字符串是不同的,是记不住的,直接点旁边的“生成…”按钮吧!点击该按钮后,弹出的界面和操作方法跟上边第一种方法一模一样,无需赘言。连接NWIND数据库的连接字符串是:Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files\Microsoft Visual Studio\VB98\NWIND.MDB;Persist Security Info=False

8.png
图8

连接字符串也有现成的, https://www.connectionstrings.com/上面提供了很多连接字符串,根据实际情况直接复制也可。

设置RecordSource属性

RecordSource属性就是设置SQL语句,从数据库中检索需要的数据集。这个没啥好说的了。注意合理使用Where子句,免得获取不必要的数据,浪费时间。

这两个属性设置完成,ADO Data控件就可以用了。可以把其他控件,如VSFlexGrid控件的DataSource属性设置为该控件,语句:Set VSFlexGrid1.DataSource = Adodc1,这样就可以使用数据库了。类似的控件还有很多,MSDN说,任何具有 DataSource 属性的控件都可以绑定到ADO Data 控件上,比如DataList、DataCombo、DataGrid、Microsoft Hierarchical FlexGrid、RichTextBox和Microsoft Chart等等,不一而足。

设置完数据源之后,就可以把ADO Data控件(默认名:Adodc1)赋值给网格控件了:
Private Sub UserForm_Initialize()
    With Adodc1
        .CommandType = adCmdText
        .ConnectionString = "DSN=NWind"
        .RecordSource = "select  * from [Order Details]"
    End With
    Set fg.DataSource = Adodc1
End Sub

简单几句话,网格上就显示数据集的所有数据了。(嘿嘿,要想编辑网格,还得加一句:fg.Editable = flexEDKbdMouse,不然网格是禁止编辑的。)


TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-31 23:03 | 显示全部楼层


1.2 直接绑定数据源

肯定很多人不喜欢使用更多的控件,且希望控制权在自己手里,那就自己解决怎么绑定数据源吧,什么都不要考虑,在窗体上添加一个网格控件,名为fg,复制如下代码就绑定到数据库:

Private Sub UserForm_Initialize()
    Set cnn = CreateObject("adodb.connection")
    Set rst = CreateObject("adodb.recordset")
    cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=G:\nwind.mdb;Persist Security Info=False;"
    rst.Open "select  * from [Order Details]", cnn, 1, 3
Set fg.DataSource = rst
fg.Editable = flexEDKbdMouse
End Sub

1.3 绑定控件到数组

其实,还可以绑定网格到一个变体型数组。语法为:
[form!]VSFlexGrid.BindToArray [ VariantArray As Variant ], [ RowDim As Long ], [ ColDim As Long ], [ PageDim As Long ], [ CurrentPage As Long ]

当绑定到一个数组时,网格从数组获取数值进行显示,并把任何修改自动写回数组中。数组必须至少有两个维度且必须是变体型。如果数组超过二维,你可以使用控件一次只显示 一“页”,你可以轻易地“翻页”。

这个方法中的参数允许你控制行和列如何映射到数组的维数。默认情况下,列绑定到数组的第一维(0),行绑定到数组的第二维(1),这是ADO使用GetRows方法返回记录集时使用的规则。默认设置的优点是,您可以使用Visual Basic的Redim Preserve语句添加或删除行,同时保留现有数据,你懂的,该语句只允许修改最后一个维度。如果你不喜欢默认设置,你可以用不同的方式来定义。值得注意的是,在所有维度上,映射总是从LBound到Ubound。如果想要隐藏一些行或列,请将其高度或宽度设置为零。绑定不会应用于固定行或列,它只对控件的可滚动(数据)部分有效。

如果更改数组的内容或维度,则应告诉控件重绘自身,以便更改对用户可见。可以使用Refresh方法或再次使用BindToArray方法来完成此操作。而要解除控件的绑定,使用Null参数调用BindToArray方法:fg.BindToArray Null。下面是绑定数组的代码:

Dim arr As Variant
Private Sub UserForm_Initialize()
    ReDim arr(1 To 100, 1 To 6)
    For i = 1 To 100
        For j = 1 To 6
            arr(i, j) = "第" & i & "行,第" & j & "列"
        Next
    Next
    fg.BindToArray arr, 0, 1
    fg.AutoSize 0, fg.Cols - 1
End Sub

绑定数组要特别注意的是,数组必须定义为至少是模块级别的变体型变量,否则窗体初始化完成后,网格会显示一片空白,因为初始化子过程定义的数组变量已不存在了。还有,数组如果需用代码赋值,必须事先用Redim定义好上下标边界,然后再赋值,否则提示类型不匹配。当然,引用工作表内容只要一句代码即可,如:arr = Range("a1").CurrentRegion。

还可以用LoadArray方法使用来自一个变体型数组或另一个网格控件的数据加载网格。它与BindToArray方法语法相同,只是BindToArray方法保持网格连接到源数组或控件。LoadArray只单纯地加载数据,不保持控件和数据源之间的连接。

1.4 绑定到自定义数据源

除此之外, FlexDataSource属性是另一个选项,它基于易于实现且非常灵活的自定义COM接口。
通过FlexDataSource属性进行数据绑定的主要优点是速度和灵活性。主要缺点是您必须编写比其他选项更多的代码。当有大量存储于自定义结构或对象(数据库记录集除外)中的数据时,应该考虑使用FlexDataSource属性。通过使用FlexDataSource属性,可以就地显示和编辑那些数据,而不需要将它复制到网格中并在稍后将其保存回来。事实上,数据甚至可能是虚拟的,由动态计算的值而不是静态信息组成。

当向FlexDataSource属性分配新的数据源时,该控件将根据数据源的字段名自动设置每列的标题文本和ColKey属性。如果愿意的话,可以在设置FlexDataSource属性之后更改这些值。

当绑定到FlexDataSource时,固定行上的值不被视为绑定数据。您可以使用代码设置或获取它们,而不影响数据源。另一方面,固定列被视为绑定数据。它们的内容从数据源读取并写入数据源。

要将VSFlexGrid控件绑定到FlexDataSource属性,需要实现一个对象,该对象需要暴露IVSFlexDataSource COM接口。接口非常简单,它只包括两个方法:GetData和SetData。GetData(Row,Col)返回要由网格在指定位置显示的一个字符串。当需要显示这个值时,网格调用它。SetData(Row,Col,Data)使用新值更新数据源的指定位置。当用户编辑单元格时,网格调用它。下面我们来实现一个简单的自定义数据源(注:本例为控件手册上的例子)。

要实现自定义数据源,首先要创建FlexDataSource对象。插入——类模块,新建一个类,然后输入:Implements IVSFlexDataSource。

注意,Implements语句指定要在包含该语句的类模块中实现的接口或类。其语法为:Implements [InterfaceName | Class],所需的 InterfaceName 或 Class 是类型库中的接口或类的名称,该类型库中的方法用与 Visual Basic 类中相一致的方法来实现。除了提供接口原型与自编过程之间的映射关系之外,Implements 语句还使这个类接收对指定接口 ID 的 COM QueryInterface 调用。

输入Implements IVSFlexDataSource之后,VB自动为新类已实现了IVSFlexDataSource方法,并且任何愿意使用它们的人都可以使用这些方法。但是这些方法都是空函数,代码还需要自己完成。

第二步是实现数据结构。在本例中,数据是完全虚拟的,只简单地显示一个角度表:度数、弧度、正弦以及余弦,因此该表将具有四个“字段”,并给定360条“记录”。以下是实现此结构所需的代码:
Private Function IVSFlexDataSource_GetFieldCount() As Long
    IVSFlexDataSource_GetFieldCount = 4
End Function

Private Function IVSFlexDataSource_GetRecordCount() As Long
    IVSFlexDataSource_GetRecordCount = 360
End Function

Private Function IVSFlexDataSource_GetFieldName(ByVal Field As Long) As String
    Select Case Field
        Case 0: IVSFlexDataSource_GetFieldName = "Angle (Deg)"
        Case 1: IVSFlexDataSource_GetFieldName = "Angle (Rad)"
        Case 2: IVSFlexDataSource_GetFieldName = "Sine"
        Case 3: IVSFlexDataSource_GetFieldName = "Co-Sine"
    End Select
End Function

现在已经定义好了数据结构,下一步是实现GetData和SetData方法:
Private Function IVSFlexDataSource_GetData(ByVal Field As Long, ByVal Record As Long) As String
    Select Case Field
        Case 0: IVSFlexDataSource_GetData = Record
        Case 1: IVSFlexDataSource_GetData = Record / 180# * 3.1416
        Case 2: IVSFlexDataSource_GetData = Sin(Record / 180# * 3.1416)
        Case 3: IVSFlexDataSource_GetData = Cos(Record / 180# * 3.1416)
    End Select
End Function

Private Sub IVSFlexDataSource_SetData(ByVal Field As Long, ByVal Record As Long, ByVal newData As String)
    Err.Raise 666, "IVSFlexDataSource", "This data is read-only."
End Sub

注意,为了举例的简单方便,SetData方法中没有实现任何功能,只是简单粗暴地抛出错误。实际应用中需要根据需求实现该方法。实现完GetData和SetData方法,最后一步就是连接VSFlexGrid和数据提供者,这个最后一步倒是简单:
Private Sub UserForm_Initialize()
    Dim fds As New 类1
    fg.Editable = flexEDKbdMouse
    fg.FlexDataSource = fds
    fg.ColFormat(-1) = "#.###"
    fg.ColFormat(0) = ""
End Sub

类1就是刚才创建的自定义数据源类,fds是该类的实例,直接赋值给网格的FlexDataSource属性就行了。


TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-31 23:10 | 显示全部楼层


1.5 绑定的模式

绑定模式决定了网格的不同行为,设置绑定模式用DataMode属性。DataMode属性的设置如下:

表1.png
表1

flexDMBound模式根据记录集的LockType属性设置,自动处理对记录集的更新。flexDMBoundBatch和flexDMBoundImmediate允许绕过记录集的LockType属性设置。这通常是个坏主意,除非你有充分的理由这样做,否则不应该使用这些设置。

当DataMode属性设置为flexDMFree以外的值时,某些属性和方法会被禁用,或者它们的行为受到限制:

表2.png
表2


2. 操作网格

绑定数据只是开胃菜,正菜是网格的操作。动手能力特别强的童鞋可能已经试验过以上代码,如果细心一点,应该会发现控件绑定到数组的时候没有标题。还有以上提到的“固定行”、“固定列”感到莫名其妙,不知指的什么。固定行、列肯定不是冻结行、列,而是相当于EXCEL工作表的行头(数字1,2,3…)和列头(字母A,B,C…),下面先看一张图,认识网格的各个区域:

9.png
图9

2.1 认识网格的行和列

网格的行数和列数包括固定行和列在内,默认的固定行数和列数为1,可以在窗体初始化时设置为0,这样网格就没有标题行和标题列了。网格总行数和总列数用属性fg.Rows和fg.Cols设置和获取,固定行数和列数用fg.FixedRows和fg.FixedCols设置和获取。网格控件的行号和列号索引都是基于0,从零开始,以此类推,因此如果表述为“第一行”或“第一列”,代表是行0和列0,本帖中如果说行X或列X,都是按索引号引用。一个网格行的索引范围为0到fg.Rows-1,列的索引范围为0到fg.Cols-1.

由fg.Row和fg.Col属性可设置和获取当前单元格位置,当前单元格类似于EXCEL的ActiveCell,但网格控件的当前单元格不一定是选择区域的左上角,而是在选择时框取的第一个单元格,位置可在选择区域的四个角中的任意角。选择区域的大小,除了Row和Col属性,还有RowSel 和ColSel,这两个属性表示选到哪一行或哪一列为止。假如Col=3,ColSel=1,表示从列3开始,选到列1,共选择了3列;假如Col=3,ColSel=6,表示从列3开始,选到列6,共选择了4列。行也是如此。下图中:fg.Row=3,fg.Col=1,fg.RowSel=6,fg.ColSel=2。可以使用这四句代码选择这个区域,也可以返回选择的区域。要选择单元格区域,还可以使用fg.Selected方法,使用的四个参数就是上述四个属性,一步到位选择一个单元恶搞区域,不过VBA中无法使用(在VB中正常使用),可自己定义一个SELECT子过程,带以上四个参数即可。

10.png
图10

要记住fg.Row、fg.Col、fg.RowSel和fg.ColSel四个属性和其顺序,所有单元格区域的使用都是需要这四个属性和其顺序,不过fg.RowSel和fg.ColSel的值可能分别大于或小于fg.Row和fg.Col,这对于循环选中区域比较麻烦,因为还得比较这四个数字的大小才能确定循环边界,为此可使用GetSelection 方法,该方法返回已经排过序以致Row<=RowSel和Col<=ColSel的当前选择区域,其语法为:
[form!]VSFlexGrid.GetSelection Row1 As Long, Col1 As Long, Row2 As Long, Col2 As Long。
要循环图10的选择的区域,可以这样:
Dim r1&, c1&, r2&, c2&
fg.GetSelection r1, c1, r2, c2
For i = r1 To r2
    For j = c1 To c2
        Debug.Print fg.TextMatrix(i, j)
    Next
Next

因为网格控件可以设置成直接拖动列的位置,所以列的位置索引未必总是对的。ColIndex属性与ColKey属性合起来用于标识和引用列,而不管该列在网格上的物理位置如何。要使用这些属性,需使用ColKey属性为每个列指定唯一的键。当希望引用特定列时,使用ColIndex属性将键转换为索引。例如fg.ColIndex("Orders")总能找到正确的列,而不管Orders列拖到哪里去。当你设计的界面可以随意移动列的位置时,要在代码中用ColIndex引用列。

当网格绑定到记录集时,ColKey值将自动设置为字段名,而绑定到数组或无绑定数据时,在窗体初始化时自己写代码指定列的键值:fg.ColKey(4) = " Orders "。

冻结行用fg.FrozenRows=1这种代码,需要冻结几行就写几行,冻结列用fg.FrozenCols。隐藏行列用fg.RowHidden(Index) = True和fg.ColHidden(Index) = True,索引设置为-1会隐藏所有行或列。设置行高和列宽用fg.RowHeight(index)和fg. ColWidth (index),单位都是缇,1440缇等于1英寸,1英寸=2.54厘米,索引设置为-1则设置所有行的高度或列的宽度。

在需要对列排序时,需要考虑数据类型。当控件绑定到记录集时,将自动为每个列设置数据类型属性,当控件处于未绑定模式时,可以使用代码设置ColDataType属性,其有效值为:

表3.png
表3

如何选择行列?
可以用SelectionMode属性。当单击一个单元格时,会自动将按行、按列或类似列表框的方式选择。其值可以为:

表4.png
表4

当SelectionMode被设置为flexSelectionListBox时,可以使用IsSelected属性来读取和设置单个行的选定状态,以及SelectedRows属性来枚举选定行。IsSelected语法为:
[form!]VSFlexGrid.IsSelected(Row As Long)[ = {True | False} ]

将SelectionMode属性设置为flexSelectionListBox,它允许用户使用鼠标或键盘选择单独的行,并通过同时按下CTRL键切换对行的选择状态。如果将SelectionMode属性设置为flexSelectionListBox以外的其他属性,仍然可以使用IsSelected属性选择和取消选择行,但是用户将不能用鼠标或键盘更改选择状态。还可以使用SelectedRows和SelectedRow属性枚举所选行。使用SelectedRows和SelectedRow属性枚举所有选定行比通过读取IsSelected属性扫描整个控件以获得选定行要快。
使用IsSelected的方式为:
For i = 0 to fg.Rows
    If fg.IsSelected(i) Then Debug.Print "行 "; i; " 被选中"
Next

使用SelectedRow的方式为:
For i = 0 to fg.SelectedRows – 1
    Debug.Print "行 "; fg.SelectedRow(i); " 被选中"
Next


评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-31 23:13 | 显示全部楼层


2.2 认识网格的单元格

网格控件的单元格跟Excel单元格也没有多少区别。在Excel中我们使用Range对象来设置单元格区域的属性,在网格控件中使用Cell返回或设置任意区域的单元格属性。语法为:
[form!]vsFlexGrid.Cell(Setting As CellPropertySettings, [R1 As Long], [C1 As Long], [R2 As Long], [C2 As Long]) [ = Value ]

R1和C1的默认值是当前行和当前列(Row和Col属性)。因此,如果不指定这两个值,则使用当前单元格。R2和C2的默认值是R1和C1。因此,如果不指定这两个值,则使用单个单元格。
Setting参数的有效设置为:

表5.png
表5

上面列出的大多数设置也可以通过其他属性(例如Text、TextArray等)读取或设置。然而,使用Cell属性通常更方便,因为它允许指定单元格区域,且一些设置无法通过其他属性访问。

在第一章中绑定到数组的时候,网格没有标题(绑定到数组是没有标题的),我们可以用Cell属性赋值:
Private Sub UserForm_Initialize()
    brr = Range("a3").CurrentRegion '标题
    arr = Range("a5").CurrentRegion '数据
    fg.FixedCols = 0 '设置固定列数为0
    fg.FixedRows = 1 '固定行和列数默认为1,可不设置
    For i = 0 To 7 '设置固定行(列标题)的内容
        fg.Cell(flexcpText, 0, i) = brr(1, i + 1)
    Next
    fg.ForeColorFixed = vbBlue '把列标题前景色改为蓝色
    fg.BindToArray arr, 0, 1 '绑定到数组
    fg.AutoSize 0, fg.Cols - 1 '从第1列到最后1列自动调整列宽
    fg.FocusRect = flexFocusSolid '设置当前单元格矩形框
End Sub

设置单个单元格的文本内容还可以用TextMatrix属性,更简单些,语法为:
[form!]VSFlexGrid.TextMatrix(Row As Long, Col As Long)[ = value As String ]
例如想给行2、列1交叉处的单元格赋值,可用:
fg.TextMatrix(2, 1) = "ExcelHome"
TextMatrix属性只能赋值内容,无法设置格式,功能远不如Cell属性,在处理单元格格式等信息时,要使用Cell属性。

要设置控件是否允许直接编辑单元格,需要设置Editable属性:

表6.png
表6

默认情况下,当用户按下编辑键(F2)、空格键或任何可打印字符时,控件会进入编辑模式。如果Editable属性设置为flexEDKbdMouse(2),当用户双击单元格时,该控件也会进入编辑模式。还可以使用EditCell方法强制控件进入单元格编辑模式,或者通过捕获BeforeEdit事件并将Cancel参数设置为True来阻止其进入编辑模式。要限制某些列不可编辑,可在BeforeEdit事件中判断当前列号。BeforeEdit事件在控件进入单元格编辑模式之前触发。其语法:
Private Sub VSFlexGrid_BeforeEdit( ByVal Row As Long,  ByVal Col As Long, Cancel As Boolean)
Row, Col指示正要编辑或重绘哪个单元格。判断这两个值可限制某些行或列不可以编辑,只要把Cancel参数设置为TRUE即可。

2.3 给网格装点色彩

图9是很重要的图,其上已经注明网格各个区域的前景色和背景色的设置,那些属性都是整个区域一起设置,这里不再举例。如果想对网格上某个特定区域,或者一个单元格设置,可用Cell属性,例如我们想对行0、列1交叉位置的单元格设置字体属性,可以:
fg.Cell(flexcpFontName, 0, 1) = "Arial"
fg.Cell(flexcpFontSize, 0, 1) = 16
fg.Cell(flexcpForeColor, 0, 1) = vbRed
如果要对行1到行10、列1到列2围成的区域背景色设为绿色,可用:
fg.Cell(flexcpBackColor, 1, 1, 10, 2) = vbGreen
设置行1的前景色为红色:
fg.Cell(flexcpForeColor, 1, 0, 1, fg.Cols - 1) = vbRed
要想对选择区域排个顺序,在fg单击事件中输入如下代码,当选定区域释放鼠标时,就会排序:
fg.Cell(flexcpSort, fg.Row, fg.Col, fg.RowSel, fg.ColSel) = 1'升序
给选择区域每个单元格插入一张图片呢?
fg.Cell(flexcpPicture, 1, 1, 10, 2) = LoadPicture("G:\test.jpg")
更多设置见表3。


TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-31 23:18 | 显示全部楼层

2.4 自动调整行高、列宽

2.1节已经介绍如何设置行高和列宽,这里说说怎么自动调整行高和列宽。我们从数据集加载的数据条目长度是未知的,设置好的行高(当允许自动换行时)和列宽未必够用,这时可选择让控件自己调节。AutoResize属性设置加载数据时是否自动调整列宽度,注意,是在加载数据时调整。列宽往往跟字体大小和字体宽度有关,如果设置DataSource属性之后,再设置控件的字体属性,则不会自动调整列宽,因为数据加载完了。要修改控件的字体,必须在DataSource属性设置之前设置字体大小,否则AutoResize属性无效。

且AutoResize属性只在控件绑定到数据库时才有效。如果控件未绑定到数据库,则需要在更改网格内容之后使用AutoSize方法调整指定列的宽度。AutoSize语法为:
[form!]VSFlexGrid.AutoSize Col1 As Long, [ Col2 As Long ], [ Equal As Boolean ], [ ExtraSpace As Single ]

AutoSize方法的参数描述如下:

Col1 As Long, Col2 As Long
指定要调整大小的第一列和最后一列,以便它们的宽度适合每列中最宽的条目。这些参数的有效范围在0和Cols-1之间。Col2是可选的,如果省略它,则仅调整Col1列的大小。

Equal As Boolean  (可选值)
如果为真,则Col1和Col2之间的所有列都设置为相同的宽度。如果为False,则独立调整每个列的大小。此参数是可选的,默认为False。

ExtraSpace As Single  (可选值)
允许指定额外的间距,单位缇,除了满足最宽条目所需的最小值之外,还要添加额外的间距。如果您希望为单元格内的图片或边距留出额外的空间,这通常很有用。此参数是可选的,默认为零。

AutoSize方法还可以用于调整行高。当允许文本在单元格内自动换行时(WordWrap属性),或者当单元格具有不同大小的字体时(参见单元格属性),这非常有用。AutoSizeMode属性确定AutoSize将调整列宽还是行高,当AutoSizeMode=flexAutoSizeRowHeight时调整行高。

此外,还可以设置AllowUserResizing属性。AllowUserResizing允许用户使用鼠标调整行和列的大小,该属性决定用户是否可以用鼠标调整行列大小,有4个选项:不可调节,仅可调节行高,仅可调节列宽,可调节行列大小。当设置完AllowUserResizing属性之后,把AutoSizeMouse属性设置为True,用户即可用鼠标调节行列大小了。

能自动调节行列大小也不是没有问题,有些条目的字符串可能很长,因为每个单元格可容纳32k的字符串,从而导致行列尺寸过大;而有些条目是空的,从而导致行列尺寸过小,这个时候有必要限制行列的尺寸范围,设置合理的ColWidthMax、ColWidthMin、RowHeightMax和RowHeightMin属性,单位缇。

2.5 使用复选框

网格中如果有些列需要使用复选框,可以使用Cell属性的flexcpChecked设置。假设我们想在列1放置未选中的复选框,可以用:
fg.Cell(flexcpChecked, 1, 1, fg.Rows - 1, 1) = flexUnchecked
fg.Cell(flexcpPictureAlignment, 1, 1, fg.Rows - 1, 1) = flexPicAlignRightCenter
flexcpChecked设置的值可以为:

表7.png

表7

复选框可以出现在单元格的左边、右边或中心,这取决于PictureAlignment属性的设置:

表8.png
表8

设置后的效果如图11:

11.png

图11

默认操作是单击方框“□”才会选中,我们可以在网格控件的Click事件中稍微改改:
If fg.Col = 1 Then
    fg.Cell(flexcpChecked, fg.Row, fg.Col) = IIf(fg.CellChecked = flexChecked, flexUnchecked, flexChecked)
End If
判断选中单元格复选框是否选中用CellChecked属性,当然,也可以用Cell,如果不嫌长的话。

不同于Listbox和Listview等控件,网格控件的单元格是可以直接编辑的,跟Excel没有什么区域,只要:fg.Editable = flexEDKbdMouse,Editable还有两个值可选:flexEDNone(不可编辑网格)和flexEDKbd(在单元格上键入内容来启动编辑模式),flexEDKbdMouse是按键盘字母和双击鼠标都可以进行编辑,显然更方便。


TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-31 23:22 | 显示全部楼层


2.6 使用列表框和组合框

有时候需要使用列表框和组合框,例如性别、学历等信息可做成列表框供选择,而籍贯的省份比较多,可以做成列表框,也可做成组合框。列表框和组合框的区别是列表框只能选择项目,组合框既可选择项目,也可输入内容。要创建列表框和组合框,可以使用ComboList属性和ColComboList属性。ComboList和ColComboList属性密切相关,它们具有相同的功能,并且用于定义列表的语法完全相同。但它们有两点不同:

ColComboList属性应用于整个列,它可以只设置一次,当控件加载后,你就可以忘记它了。ComboList属性仅应用于当前单元格。若要使用它,您需要捕获BeforeEdit事件,并将ComboList属性设置为适用于要编辑时调用的列表。

ColComboList属性进行数据转换。如果提供了数据值,则将这些数据值存储在网格中,而不是实际的字符串。ComboList属性不会进行数据转换。

如果一列中的所有单元格都要从同一列表中选择项目,就像大多数数据库应用程序一样,则使用ColComboList属性。这样就不需要处理BeforeEdit事件,代码将更干净、更有效。此外,还可以选择使用数据转换,这简化了代码,并提高了数据完整性。

ComboList属性控制编辑单元格要使用的编辑器的类型。可以使用文本框、下拉列表、下拉组合框或一个弹出自定义编辑器窗口的编辑按钮。

要使用常规文本框编辑单元格,请将ComboList属性设置为空字符串("")。

要使用下拉列表编辑单元格,请将ComboList属性设置为包含有效选项的字符串,以管道字符(“|”)分隔。例如:ComboList = "列表项 1|列表项2"。

要使用下拉组合框编辑单元格,请将ComboList属性设置为包含有效选项的字符串,以管道字符(“|”)分隔,并以管道字符开始。例如:ComboList = "|组合项 1|组合项2"。

要显示编辑按钮,请将ComboList属性设置为包含省略号(...)的字符串。编辑按钮看起来像常规按钮,对齐到单元格的右边,省略号作为标题。当用户单击编辑按钮时,该控件将触发CellButtonClick事件。例如:ComboList = "..."。

CellButtonClick事件用于弹出单元格的自定义编辑器(例如,用于选择颜色、日期、文件、图片等的对话框)。还可以通过给CellButtonPicture属性指定图片来定制编辑按钮的外观。例如我们可以用编辑按钮来显示文件选择窗口:
Private Sub fg_CellButtonClick(ByVal Row As Long, ByVal Col As Long)
    With Application.FileDialog(msoFileDialogFilePicker)
        .AllowMultiSelect = False
        .InitialFileName = "C:\"
        .Filters.Clear
        .Filters.Add "Excel文件", "*.xls*;*.xlw;*.xlt"
        .Filters.Add "所有文件", "*.*"
        If .Show = -1 Then fg.TextMatrix(Row, Col) = .SelectedItems.Item(1)
    End With
End Sub

还可以创建定义多列下拉列表和转换列表(每个项具有相关联数值的列表)的列表。

若要定义多列列表,请使用Tab字符(Chr(9)或vbTab)分隔列。定义多列组合时,单元格中只显示一列(其他列只在下拉列表中可见)。默认情况下,第一列是在单元格中显示的列。要显示不同的替代列,请在第一项中添加格式为“*nnn;”的字符串,其中nnn是要显示的列的基于零的索引。

为了创建转换列表,通过在行的开头添加格式为“#xxx;”的字符串,向每个列表项附加一个数值,其中xxx是数值。在使用ComboData属性编辑单元格时可以读取此值。例如:
s = "|#10*3;张" & vbTab & "无忌" & vbTab & "广西" & vbTab & "15890902345" & _
  "|#20;李" & vbTab & "世民" & vbTab & "广东" & vbTab & "13278992633" & _
  "|#30;赵" & vbTab & "盾" & vbTab & "湖南" & vbTab & "18745457867" & _
  "|#40;赢" & vbTab & "政" & vbTab & "海南" & vbTab & "15678457676"
fg.ColComboList(4) = s

上面的代码将显示一个具有四列的下拉组合。这些项将具有关联的数据值10、20、30和40。单元格中显示的值将是列3(手机号)中的值。因为第一个字符是管道,所以将是一个下拉组合框,而不是一个下拉列表框。如图12

12.png
图12

也许大家发现了,如果列表数据很多,编辑ComboList字符串不仅很辛苦,也很容易错。有没有更简单的方法呢?答案是可以使用BuildComboList方法从记录集中的数据返回ColComboList字符串。BuildComboList语法为:
[form!]VSFlexGrid.BuildComboList rs As Object, FieldList As String, [ KeyField As Variant ], [ BackColor As Variant ]
BuildComboList方法的参数描述如下:

rs As Object
包含要在网格上显示的值的ADO或DAO记录集。

FieldList As String
包含要显示的字段名的一个逗号分隔列表字符串。如果列表包含多个字段,则创建多列下拉列表。可以通过在字段名称前面加上星号“*”来定义默认字段(当列表关闭时显示在单元格中)。

KeyField As String (optional)
被用作键的字段的名称。这个字段必须是数字,且通常是记录集的ID字段。

BackColor As OLE_COLOR (optional)
用于在显示列表时绘制默认字段的背景色。如果省略,则使用当前单元格背景色绘制整个列表。

比如我们想在列3加个列表框,数据来源是数据库的供应商表,可以这样:
Set rst = CreateObject("adodb.recordset")
rst.Open "select SupplierID,CompanyName from Suppliers order by CompanyName", cnn, 1, 3
If rst.RecordCount > 0 Then
    fg.ColComboList(3) = fg.BuildComboList(rst, "SupplierID,*CompanyName", "SupplierID", 12379351)
End If


TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-31 23:26 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册


2.7 使用掩码和自定义编辑器

可以使用EditMask属性和ComboList属性设置掩码。这两个属性允许指定用于自动输入格式化和验证有效性的输

入掩码。掩码语法类似于Microsoft MaskedEdit控件和Microsoft Access数据库中所使用的语法。可根据

BeforeEdit事件设置EditMask属性,与设置ComboList属性的方式相同。如果要使用相同的掩码编辑列中的所有

值,则请使用ColEditMask属性,这会简化代码,也不需要捕获BeforeEdit事件。
EditMask必须是由以下符号组成的字符串:

通配符
0    数字
9    数字或空格
#    数字或符号
L    字母
?    字母或空格
A   字母或数字
a    字母、数字或空格
&   任意字符

本地化字符
.     本地化小数点分隔符
,     本地化千分位分隔符
:     本地化时间分隔符
/     本地化日期分隔符

命令字符
\     转义字符。使其后的字符显示为原义字符。(例如,\A 显示为 A)
>    把字母转换成大写字母
<    把字母转换成小写字母
;     组分隔符(参见下文)

组分隔符字符用于控件的附加选项。如果组分隔符出现在掩码字符串中,那么在第一个分隔符左边的掩码部分

将用作实际的掩码,而其右边的部分将按如下方式解释:
如果存在小写字母“q”,则控件采用“静默”模式编辑(输入无效字符不会发出蜂鸣器声),最后一个字符用

作占位符(而不是默认的下划线)。

更多掩码语法详情可参考Access的掩码使用方法。

有时候下拉列表和组合框也无法满足编辑需求,这时候可自定义编辑器,比如做一个具有查询功能的窗体,可

以双击网格弹出它,也可以点击编辑按钮弹出。如果要输入日期,可以自己做一个日历窗体,也可以使用现有

VB控件,有日期时间选择器(Microsoft Date and Time Picker Control,引用Mscomct2.ocx)和日历控件

12.0(引用MSCAL.OCX),这里不讲怎么使用这些控件,只说说如何定位这些控件的位置。
CellHeight、CellWidth、CellTop和CellLeft属性非常有用,无论何时读取这些属性中的任何一个,网格控件

都假定你想要处理当前单元格,并且它自动将其带入可见视图。当想要把其他控件放置在特定单元格之上或附

近时,可以使用这四个属性。它们分别是当前单元格的高度、宽度和相对于网格控件的Y、X坐标,单位都是缇

。由于在VBA窗体中的度量单位是磅,需要转换,1磅=20缇。假如我们想把一个日期时间选择器定位到当前单元

格上,可用该控件Move方法:
DTP1.Move fg.Left + fg.CellLeft / 20, fg.Top + fg.CellTop / 20, fg.CellWidth / 20, fg.CellHeight / 20

2.8数据的查询与筛选

要查询某个数据,可以使用Cell属性或TextMatrix属性循环整个网格,查询方法就太多了,可参考:

http://club.excelhome.net/thread-1450458-1-1.html。也可以设置AutoSearch属性,不过AutoSearch只查询

首字母和数字,不适合汉字,类似在资源管理器按首字母定位文件,比如你在系统文件夹下按“S”键,可以快

速定位到System32文件夹,而不需要使用搜索框。
AutoSearch属性的设置描述如下:

表9.png
表9

如果开启“自动搜索”,控件将在用户键入时搜索当前列,并自动移动光标且高亮显示匹配部分字符。搜索不

区分大小写。当用户按下ESC键或用鼠标或光标键移动选择区域时,将取消搜索。

当用户停止输入约两秒钟后,搜索缓冲区将被重置。可以通过设置AutoSearchDelay属性更改此时间延迟量

(AutoSearchDelay属性接收一个单精度数字,单位为秒)。

如果开启“自动搜索”功能,且Editable属性设置为TRUE,则用户将需要单击回车键、空格或F2键来进行编辑

单元格。其他键被用于搜索。

此属性仅影响网格控件本身的行为。若要在用户键入组合框或列表框控件时自动选择选项,请使用ComboSearch

属性。ComboSearch属性的设置描述如下:

表10.png
表10

如果网格绑定了数据库,只能使用数据集自己的方法,网格本身没提供任何查询方法。查询数据库的方法也在

刚才给出的链接中写得很明白详细,这里只简单说一下。如果绑定模式fg.DataMode = flexDMFree,那么在每

次查询之后,都需要使用fg.DataRefresh 刷新表格,不然看不到筛选结果,如果fg.DataMode=flexDMBound绑

定数据,库无需刷新数据,自动同步。一个简单的例子:

窗体初始化:
Private Sub UserForm_Initialize()
    Set cnn = CreateObject("adodb.connection")
    Set rst = CreateObject("adodb.recordset")
    cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=G:\nwind.mdb;Persist Security

Info=False;"

    rst.Open "select ProductID & '' as ProductID ,ProductName from [Products]", cnn, 1, 3

'ProductID & ''把长整型转为字符串好匹配
    fg.VirtualData = True '虚拟数据,需要时才加载
    fg.DataMode = flexDMFree '自由绑定模式,不修改记录集
    Set fg.DataSource = rst
    fg.AutoResize = True
    fg.SelectionMode = flexSelectionByRow
    fg.AllowSelection = False
    TextBox1.ForeColor = vbBlue
    TextBox1.SetFocus
    Me.Caption = "产品查询输入"
End Sub

模糊查询代码:
Private Sub TextBox1_Change()
    If Len(TextBox1) Then
        rst.Filter = "ProductID like '%" & TextBox1 & "%' or ProductName like '%" & TextBox1 &

"%'"
    Else
        rst.Filter = ""
    End If
    fg.DataRefresh '如果fg.DataMode=flexDMBound,绑定数据库无需刷新数据
End Sub

把选中的项目输出到其他控件:
Private Sub CommandButton1_Click()
    With UserForm1.fg
        .TextMatrix(.Row, 1) = fg.TextMatrix(fg.Row, 1)
    End With
    Unload Me
End Sub

要特别主要的是,切不可使用网格的双击事件fg_DblClick()输出数据,否则第二次显示该窗体时将无法关闭,

一直处在“正在运行”。我研究了很久为什么无法关闭窗体,排除了各种可能性,才找到是双击造成的,但为

什么双击输出数据会导致窗体无法卸载,原因未知,可能是Bug。在VBA中使用网格控件也无法使用Select方法

和EditCell方法,好在这些方法都有替代方式,不会影响使用。

网格自带的FindRow属性也可以进行简单的查询。FindRow属性返回包含指定字符串或RowData值的行的索引。其

语法为:
val& = [form!]VSFlexGrid.FindRow(Item As Variant, [ Row As Long ], [ Col As Long ], [

CaseSensitive As Boolean ], [ FullMatch As Boolean])

FindRow属性允许基于单元格内容或RowData值查找行,这种搜索比Visual Basic循环更快、更容易实现。

FindRow属性的参数描述如下:

Item As Variant
此参数包含待搜索的数据。

Row As Long (可选)
此参数包含搜索要开始的行。默认值是FixedRows。

Col As Long (可选)
这个参数告诉控件应该搜索哪个列。默认情况下,此值被设置为-1,这意味着控件将查找与RowData匹配的列。

如果Col设置为大于-1的值,则该控件将查找与给定列的单元格内容的匹配项。

CaseSensitive As Boolean (可选)
此参数默认值为True,搜索区分大小写。如果希望搜索不区分大小写,则将其设置为False。此参数仅在查找字

符串时才有意义。

FullMatch As Boolean (可选)

此参数默认值为True,这意味着搜索是完全匹配的。如果希望允许部分匹配,则将其设置为False。此参数仅在

查找字符串时才有意义。

FindRow返回找到数据的行的索引,如果没有找到数据,则返回-1。

此外,还可以使用控件FindRowRegex属性,其返回包含匹配的行的索引,如果没有找到匹配,则返回-1。其语

法为:FindRowRegex(Pattern As String, Row As Long, Col As Long) As Long。Pattern包含要查找的正则

表达式(有关正则表达式语法,请参阅VBScript Regex对象中的Pattern属性)。Row为搜索的起始行(使用-1

则从第一个可滚动行开始)。Col为要搜索的列。



TA的精华主题

TA的得分主题

发表于 2018-12-31 23:42 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
ivccav兄又出手了
上次你的listview教學,就用了大量api編輯,這個可以更輕易的定格編輯嗎

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-12-31 23:58 | 显示全部楼层


2.9 复制、粘贴、清除内容、删除行和插入行

这些功能网格控件都已提供,无需编写代码,我把这些功能做成右键菜单,方便使用。右键菜单的代码如下:
Sub PopupMenu()
    On Error Resume Next
    CommandBars("PopupMenu").Delete

    With CommandBars.Add("PopupMenu", msoBarPopup, , True)
        With .Controls.Add(msoControlButton)
            .Caption = "复制[&C]"
            .OnAction = "复制"
            .FaceId = 19
        End With

        With .Controls.Add(msoControlButton)
            .Caption = "清除[&R]"
            .OnAction = "清除"
            .FaceId = 47
        End With

        With .Controls.Add(msoControlButton)
            .Caption = "剪切[&T]"
            .OnAction = "剪切"
            .FaceId = 21
        End With

        With .Controls.Add(msoControlButton)
            .Caption = "粘贴[&P]"
            .OnAction = "粘贴"
            .FaceId = 22
        End With

        With .Controls.Add(msoControlButton)
            .Caption = "插入行[&I]"
            .OnAction = "插入行"
            .FaceId = 137
            .BeginGroup = True
        End With

        With .Controls.Add(msoControlButton)
            .Caption = "删除行[&D]"
            .OnAction = "删除行"
            .FaceId = 478
        End With

    End With
End Sub

Sub 复制() '复制选择区域、整行或整列文本
UserForm1.fg.Copy
End Sub

Sub 粘贴() '粘贴,可根据剪贴板数据自适应目标区域
UserForm1.fg.Paste
End Sub

Sub 清除() '清除选择区域、整行或整列文本
'fg.Clear flexClearSelection, flexClearText
UserForm1.fg.Delete '两者都可以用
End Sub

Sub 剪切() '剪切选择区域、整行或整列文本
UserForm1.fg.Cut
End Sub

Sub 插入行() '在当前行之前插入任意行(选中多少行插入多少行)
    With UserForm1.fg
        Dim r&, p&
        p = Application.Min(.Row, .RowSel)
        For r = 1 To Abs(.Row - .RowSel) + 1
            .AddItem "", p
        Next
    End With
End Sub

Sub 删除行() '删除当前选择的所有行
    With UserForm1.fg
        Dim r&, r1&, c1&, r2&, c2&
        .GetSelection r1, c1, r2, c2
        For r = r2 To r1 Step -1:
            .RemoveItem r
        Next
    End With
End Sub

窗体中的代码为,注意窗体初始化时调用PopupMenu:
Private Sub UserForm_Initialize()
    fg.Rows = 20
    For i = 1 To fg.Rows - 1
        fg.TextMatrix(i, 1) = "test" & i
        fg.TextMatrix(i, 2) = Rnd() * 10000
    Next
    fg.Editable = flexEDKbdMouse
    PopupMenu
End Sub

Private Sub fg_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    If Button = 2 Then CommandBars("PopupMenu").ShowPopup
End Sub

需要注意的是,如果你不希望鼠标在列0或行0也启动鼠标右键,可以修改事件过程:
Private Sub fg_BeforeMouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single, Cancel As Boolean)
    If Button = 2 Then
        If fg.MouseCol = 0 Or fg.MouseRow = 0 Then
            Cancel = True
        Else
            CommandBars("PopupMenu").ShowPopup
        End If
    End If
End Sub

BeforeMouseDown事件发生在MouseDown之前。.MouseRow和MouseCol属性返回鼠标指针下面的行、列基于零的索引。最后得到的效果如下:

13.png
图13


2.10 合并单元格做出复杂表头

如果需要合并单元格制作复杂的表头,可MergeCells、MergeRow、MergeCol和MergeCompare四个属性一起使用。若要创建具有合并单元格的表,必须将MergeCell设置为flexMergeNever以外的值,然后将MergeRow和MergeCol属性设置为true,以用于希望合并的行和列(除非使用flexMergeSpill模式时)。在设置这些属性之后,控制将自动合并具有相同内容的相邻单元格。每当单元格内容发生变化时,控件就更新合并状态。用于比较单元格内容并决定它们是否应该合并的算法通过MergeCompare属性设置。

MergeCells返回或设置是否具有相同内容的单元格将合并到单个单元格中。MergeCells属性的设置如下:
常数        值        描述
flexMergeNever        0        不合并单元格。
flexMergeFree        1        合并具有相同内容的任何相邻单元格(如果它们位于RowMerge设置为True的行或MergeCol设置为True的列上)。
flexMergeRestrictRows        2        只有在上边的单元格也被合并时才合并行。
flexMergeRestrictColumns        3        只有在左边的单元格也被合并时才合并列。
flexMergeRestrictAll        4        只有在上边或左边的单元格也被合并时,才合并单元格。
flexMergeFixedOnly        5        只合并固定单元。此设置用于为数据设置复杂的表头并防止数据本身被合并。
flexMergeSpill        6        允许长条目溢出到相邻空单元格中。
flexMergeOutline        7        允许小计行(大纲节点)中的条目溢出到相邻空单元格中。

表11.png
表11

flexMergeSpill设置与其他设置稍有不同。这是唯一不需要设置MergeCol和MergeRow属性的设置,并且不会将具有相同设置的单元格合并。相反,它允许具有长条目的单元格溢出到相邻单元格中,只要它们是空的。

MergeRow返回或设置某行是否合并单元格,而MergeCol返回或设置某列是否合并单元格,-1设置所有行或列。MergeCompare属性返回或设置合并单元格时使用的比较类型,其设置如下:
常数        值        描述
FlexMCExact        0        只有当单元格的内容完全匹配时才合并。
FlexMCNoCase        1        不区分大小写条件下单元格中的内容匹配,则合并单元格。
FlexMCTrimNoCase        2        不区分大小写条件下单元格中的内容剔除空白符后匹配,则合并单元格。
FlexMCIncludeNulls        3        合并空单元格。

表12.png
表12

因为合并单元格并不复杂,只要让要合并的单元格具有相同的值,网格控件会自动合并单元格。这里提供一个成绩表的合并表头作为参考:
Private Sub UserForm_Initialize()
    fg.Rows = 99
    fg.Cols = 10
    fg.FixedRows = 2
    fg.Cell(flexcpText, 0, 1, 1, 1) = "学生姓名"
    fg.Cell(flexcpText, 0, 2, 0, 9) = "课程成绩"
    fg.TextMatrix(1, 2) = "语文"
    fg.TextMatrix(1, 3) = "数学"
    fg.TextMatrix(1, 4) = "英语"
    fg.TextMatrix(1, 5) = "物理"
    fg.TextMatrix(1, 6) = "化学"
    fg.TextMatrix(1, 7) = "地理"
    fg.TextMatrix(1, 8) = "生物"
    fg.TextMatrix(1, 9) = "思品"
    fg.FixedAlignment(-1) = flexAlignCenterCenter
    fg.ForeColorFixed = vbBlue
    fg.MergeCells = flexMergeFixedOnly
    fg.MergeCol(-1) = True
    fg.MergeRow(-1) = True
    fg.AutoSize 0
    fg.Editable = flexEDKbdMouse
End Sub

运行以上代码,得到的效果如下图:

14.png
图14


您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-22 20:51 , Processed in 0.046466 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表