ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

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

  [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-1-1 00:02 | 显示全部楼层
本帖已被收录到知识树中,索引项:控件


2.11 拖曳行列、排序和滚动条提示

DragRow方法以编程方式启用拖动行操作(下面介绍的ExplorerBar属性也可拖动行,且无需使用代码)。然后,用户可以将该行移动到一个新的位置,之后将收到BeforeMoveRow和AfterMoveRow事件通知。该方法返回行的新位置。其语法为:
[form!]VSFlexGrid.DragRow Row As Long

下面的代码在用户单击鼠标右键时启用拖动行操作。代码通过设置背景颜色来突出显示正在拖动的行,并在拖动过程结束后恢复背景色:

Private Sub fg_BeforeMouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single, Cancel As Boolean)
    With fg
        If Button = 2 Then
            Cancel = True
            Dim r%
            r = .Row
            .Cell(flexcpBackColor, r, 1, r, .Cols - 1) = vbRed
            r = .DragRow(r)
            .Cell(flexcpCustomFormat, r, 1, r, .Cols - 1) = False
            Debug.Print "Dragged to "; r
        End If
    End With
End Sub

要拖曳列的位置,需要使用ExplorerBar属性,该属性返回或设置列标题是否用于排序或移动列。
ExplorerBar属性允许用户使用列标题在无需任何代码的情况下对列进行排序和移动。以下是其有效设置的描述:
表13.png
表13

注意,这些值是二进制位的组合,可用Or操作符进行组合设置。例如要运行排序、移动行和移动列,可以这样设置:
fg.ExplorerBar = flexExMoveRows Or flexExSortShowAndMove.

需要注意的是,必须具有至少一行固定行才能够使用ExplorerBar移动和排序列的功能,并且至少有一列固定列才能够使用移动行的功能,且每次只能移动一行或一列。还要注意的是,如果使用ExplorerBar移动行,将不能同时使用固定列来选择整行,只能通过选择可滚动列的单元格实现选择多行。

排序的时候要注意每列的数据类型,我在2.1节已经说过,这里再次说一下。绑定数据到数据库的网格,无需指定每列的数据类型,如果不是绑定模式,默认按照字符串排序,数字、日期很可能无法正确排序,这时需要指定需要排序列的数据类型。

在2.3节还讲过用Cell属性排序,只要在网格单击事件中加一句代码,选择网格的任意区域都会排序,在需要为局部行区域排序时是很有用的:
fg.Cell(flexcpSort, fg.Row, fg.Col, fg.RowSel, fg.ColSel) = 1'升序

点击ExplorerBar一次只能对一列排序, Cell属性也差不多,只对当前单元格所在列排序。这往往无法满足排序需求,这个时候就需要使用Sort属性了。

Sort属性使用所选列作为键设置所选行的排序顺序。Sort属性允许根据一个或多个列中的值按升序或降序对一个区域或行区域进行排序。要排序的行的范围是通过设置Row和RowSel属性指定的。如果Row和RowSel相同,则该控件对所有非固定行进行排序。用于排序的键由Col和ColSel属性决定,总是从左到右。例如,如果Col=3和ColSel=1,也是根据列1、列2、列3的内容进行排序。这个规定挺坑爹的,规避该设置的唯一的办法就是每次只排序一列,先把最不重要的排序,然后把最重要的列排在最后,跟Excel中的Sort排序一样。我们知道,Excel中每次只能指定3个关键字列,要多个列排序,只能按列的重要性依次降低进行多次使用Sort。

VSFlexGrid控件使用的排序算法是稳定算法:这意味着当排序键相同时,排序保持记录的相对顺序。Sort属性的有效设置描述如下:

表14.png
表14

flexSortCustom是最灵活的设置。它触发一个Compare事件,允许您以任何方式比较行,以任何顺序使用任何列。但是,它也比其他的慢得多,所以只有在真正需要的时候或者网格只有少量行时才应该使用它。要排序日期,请确保包含日期的列将其ColDataType属性设置为flexDTDate(7)。

假如我们设计一个窗体用来做排序设置,这样每次都可以方便的按任意列排序了。新建窗体要获取要排序的列和列的重要性,还要获取排序设置的值。注意ColComboLis属性的设置进行了转换,因为Sort属性接收的字符串常数是数字不是字符串。网格控件剪贴字符串的列默认分隔符为Chr(9),行默认分隔符为Chr(13),我们不修改分隔符属性。新建窗体中代码如下:
Private Sub CommandButton1_Click() '取消排序
    Unload Me
End Sub

Private Sub CommandButton2_Click() '确定排序
    With fg
        For i = .Rows - 1 To .FixedRows Step -1
            If .Cell(flexcpChecked, i, 1) = flexChecked Then
                If .Cell(flexcpTextDisplay, i, 2) <> "flexSortNone" Then
                    s = s & Chr(13) & .Cell(flexcpText, i, 1, i, 2)
                End If
            End If
        Next
    End With
    UserForm1.SortSettings = Mid(s, 2)
    Unload Me
End Sub

Private Sub UserForm_Initialize()
    With UserForm1.fg
        fg.Rows = .Cols - .FixedCols + 1
        fg.Cols = 3
        fg.TextMatrix(0, 1) = "排序字段"
        fg.TextMatrix(0, 2) = "排序顺序"
        For i = .FixedCols To .Cols - 1
            j = j + 1
            fg.TextMatrix(j, 1) = .TextMatrix(.FixedRows - 1, i)
        Next
        fg.Cell(flexcpText, 1, 2, fg.Rows - 1, 2) = "flexSortNone"
        fg.ColAlignment(-1) = flexAlignCenterCenter
        fg.Cell(flexcpChecked, 1, 1, fg.Rows - 1, 1) = flexUnchecked
        fg.Cell(flexcpPictureAlignment, 1, 1, fg.Rows - 1, 1) = flexAlignRightCenter
        fg.ColComboList(2) = "#0;flexSortNone|#1;flexSortGenericAscending|#2;flexSortGenericDescending|#3;flexSortNumericAscending|" & _
                             "#4;flexSortNumericDescending|#5;flexSortStringNoCaseAscending|#6;flexSortStringNoCaseDescending|" & _
                             "#7;flexSortStringAscending|#8;FlexSortStringDescending"

        fg.Editable = flexEDKbdMouse
        fg.SelectionMode = flexSelectionByRow
        fg.AllowSelection = False
        fg.ExplorerBar = flexExMoveRows
        fg.AutoSize 0, 1
        fg.ExtendLastCol = True
    End With
    Me.Caption = "排序设置"
End Sub

在主窗体中定义一个排序的子过程即可:
Private Sub gridsort(ByVal s As String)
    With fg
        If Len(s) = 0 Then Exit Sub '没有设置排序参数退出
        If .Rows = .FixedRows Then Exit Sub '没有数据退出
        For Each c In Split(s, Chr(13))
            .Row = 1
            a = Split(c, Chr(9))
            .Col = .ColIndex(a(0))
            .Sort = a(1)
        Next
    End With
End Sub

如果网格绑定数据库,排序就不需要自己写代码了,可直接在数据集中排序。下面简单介绍一下记录集的Sort属性:

Sort属性指示一个或多个作为 Recordset 排序基准的字段名,并指示按升序还是降序对每个字段进行排序。

设置和返回值
设置或返回 String 值,指示要作为 Recordset 排序基准的字段名称。每个名称均由逗号隔开,(可选)后面跟空格和关键字 ASC(按升序对字段进行排序)或 DESC(按降序对字段进行排序)。如果未指定关键字,默认情况下将按升序对字段进行排序。

说明一点,Sort属性要求将 CursorLocation 属性设置为 adUseClient。如果索引已不存在,则将为 Sort 属性中指定的每个字段创建临时索引。由于并没有对数据进行物理上的重新排列,因此排序操作仍有效,只不过是按索引指定的顺序进行访问。将 Sort 属性设置为空字符串将会把行重置为原始顺序并删除临时索引。现有的索引不会被删除。

上例中,假设我们按OrderID降序排序,ProductID升序排序,可以将 Sort 属性设置为字符串“OrderID DESC, ProductID ASC”,其他字段会被忽略。如果绑定模式为非零值,网格控件会自动刷新数据,不然请用DataRefresh方法刷新。

不能将字段命名为“ASC”或“DESC”,因为这些名称与关键字 ASC 和 DESC 相冲突。请使用返回 Recordset 的查询中的 AS 关键字来为有名称冲突的字段设置别名。

在滚动垂直滚动条的时候,可以显示提示信息,比如想显示放开滚动条之后,网格最上一行的行内容,可以这样写:
Private Sub fg_BeforeScrollTip(ByVal Row As Long)
    fg.ScrollTipText = "顶行OrderID:" & fg.TextMatrix(Row, 1)
End Sub

15.png
图15

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-1-1 00:07 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助


2.12 小计汇总

使用Subtotal方法插入具有汇总数据的行。其语法为:
[form!]vsFlexGrid.Subtotal Function As SubtotalSettings, [ GroupOn As Long ], [ TotalOn As Long ], [ Format As String ], [ BackColor As Color ], [ ForeColor As Color ], [ FontBold As Boolean ], [ Caption As String ], [ MatchFrom As Long ], [ TotalOnly As Boolean ]

小计行可以添加在汇总值的顶部或底部。这是由SubtotalPosition属性决定的。在创建大纲时,通常使用SubtotalPosition属性将小计放在数据的上边。在创建报表时,通常使用SubtotalPosition属性将小计放在数据的下边。

Subtotal方法的参数描述如下:

Function As SubtotalSettings
此参数指定用于小计的聚合函数的类型。有效的设置是:

表15.png
表15

GroupOn As Long  (可选)
此参数指定包含为小计计算进行分类的列。默认情况下,控件假定所有数据都从最左边的列到指定为GroupOn的列进行排序。因此,每当从最左边的列到指定为GroupOn的列(包括列GroupOn)之间任何列有变化时,就会生成小计行。
若要基于不从最左侧的列开始的一列或列区域创建小计,请使用MatchFrom参数。如果指定了MatchFrom,则该控件仅在列MatchFrom和列GroupOn之间(包括列MatchFrom和列GroupOn)的任何列中的数据改变时生成小计行。

TotalOn As Long  (可选)
此参数指定包含当计算总计时要使用其值的列。

Format As String (可选)
此参数指定用于显示结果的格式。格式字符串的语法与Visual Basic的Format命令使用的语法相似。

BackColor, ForeColor As Color  (可选)
些参数指定用于小计行中的单元格的颜色。

FontBold As Boolean  (可选)
此参数指定小计行中的文本是否应为粗体。

Caption As Variant  (可选)
此参数指定应该放在小计行中的文本。如果省略,使用的文本是函数名加上类别名(例如,“Total Widgets”)。如果提供,可以添加“%s”标记以指示类别名称应该插入的位置(例如“%s Count”)。

MatchFrom As Variant  (可选)
当决定是否在两个相邻行之间插入小计行时,该控件将比较MatchFrom和GroupOn之间的列中的值。如果这些单元格中的任何一个不同,则插入小计行。MatchFrom的默认值是FixedCols,这意味着GroupOn左边(包括列GroupOn)的所有列必须相匹配,否则将插入小计行。如果将MatchFrom设置为与GroupOn相同的值,那么每当列GroupOn的内容改变时,就会插入小计行。

TotalOnly As Boolean (optional)
默认情况下,该控件将把MatchFrom和GroupOn之间所有列的内容复制到新的小计行,并将计算值放在列TotalOn上。如果将TotalOnly参数设置为True,则控件将不会复制行的内容。小计行将只包含标题和计算值。

假如我们想对OrderID列汇总,其中ProductID列求和(只是举例,不要管其实际意义),Quantity列计数,可以使用代码:
fg.Subtotal flexSTSum, 1, 2, , , vbRed, , "订单 %s", 1
fg.Subtotal flexSTCount, 1, 4, , , vbRed, , , 1
fg.MultiTotals = True

16.png
图16

MultiTotals返回或设置是否将各列小计显示在单一行之中,如果不设置该值,将为每个聚合值创建新的小计行。小计显示在数据之上还是之下,由SubtotalPosition属性决定:
表16.png

表16

如果要想显示大纲树,还需要进行其他设置。OutlineBar属性返回或设置应该显示的大纲栏的类型。此属性确定控件在大纲模式下使用时是否应显示大纲栏。大纲栏包含类似于Windows资源管理器中的树结构。它显示了大纲的结构,并具有按钮,可以用来折叠和展开大纲的部分。OutlineBar属性的设置描述如下:

表17.png
表17

.OutlineCol属性返回或设置用于显示大纲树的列。默认是列0(第一列)。这样就设置好小计了,全部代码为:
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] order by OrderID", cnn, 1, 3
    fg.FontSize = 12
    Set fg.DataSource = rst
    fg.DataMode = flexDMFree
    fg.FocusRect = flexFocusSolid
    fg.ForeColorFixed = vbBlue
    fg.AutoResize = True
    fg.OutlineBar = flexOutlineBarCompleteLeaf
    fg.OutlineCol = 0 '大纲树显示在列0
    fg.Editable = flexEDKbdMouse
    fg.Subtotal flexSTSum, 1, 2, , , vbRed, , "订单 %s", 1
    fg.Subtotal flexSTCount, 1, 4, , , vbRed, , , 1
    fg.MultiTotals = True
    fg.AutoSize 0, fg.Cols - 1
End Sub
显示效果为:
17.png
图17
只讲这么多吧,VSFlexGrid控件的属性和方法有近300个,我只能选一些我认为重要的来讲,并把这些属性和方法按照主题串在一起,以利于理解。

——End——


评分

2

查看全部评分

TA的精华主题

TA的得分主题

发表于 2019-1-1 03:21 | 显示全部楼层
很好的教程

盼楼主再来点打印的例子

TA的精华主题

TA的得分主题

发表于 2019-1-1 08:15 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2019-1-1 08:38 | 显示全部楼层
先收藏了,看來信息量很大,需要時才學習吧

TA的精华主题

TA的得分主题

发表于 2019-1-1 09:17 | 显示全部楼层
VBA窗体表格神器——VSFlexgrid Pro 8.0基础教程,感谢分享。

TA的精华主题

TA的得分主题

发表于 2019-1-1 10:54 | 显示全部楼层
感谢楼主的精彩分享,收藏备用。

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-1-1 12:47 | 显示全部楼层
chis3 发表于 2018-12-31 23:42
ivccav兄又出手了
上次你的listview教學,就用了大量api編輯,這個可以更輕易的定格編輯嗎

这个控件可以像在Excel中一样直接编辑单元格,且单元格可使用列表框、组合框、复选框,还可以使用自定义编辑按钮弹出查询窗体输入需要复杂查询的内容,单元格图片也支持。还支持大纲树,连Treeview都给取代了。最重要的是,实现以上内容都是控件本身的,不需要另外写代码。

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-1-1 15:03 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助


2.13 打印表格

PrintGrid 方法实现在打印机上打印网格。其语法为:
[form!]VSFlexGrid.PrintGrid [ DocName As String ], [ ShowDialog As Boolean ], [ Orientation As Integer ], [ MarginLR As Long ], [ MarginTB As Long ]
PrintGrid方法的参数描述如下:

DocName As String  (可选)
包含要打印的文档的名称。此字符串出现在打印机窗口的作业列表中,并且还用作页脚。

ShowDialog As Variant  (可选,默认值为False)
如果设置为True,则在文档开始打印之前显示打印机选择/设置对话框。然后,用户可以选择使用哪台打印机、页面方向等。

Orientation As Variant  (可选,默认值为False)
将此参数设置为1,以纵向模式打印网格,或将其设置为2,以横向模式打印网格。默认设置为零,使用打印机默认的方向。

MarginLR As Variant  (可选,默认值为1440)
左边和右边页边空白,单位缇。页边空白必须相等。默认值1440缇对应于1英寸的页边空白。

MarginTB As Variant  (可选,默认值为1440)
顶部和底部页边空白,单位缇。页边空白必须相等。默认值1440缇对应于1英寸的页边空白。

网格使用与在屏幕上显示的相同字体来打印,因此,为了获得最佳效果,请确保网格的字体属性设置为TrueType字体(例如Arial、Times New Roman、Tahoma或Verdana)。

在打印网格时,该控件触发BeforePageBreak和GetHeaderRow事件。这些事件允许控制分页和设置重复的标题。

PrintGrid方法打印整个网格,可能溢出并下溢到新页面。若只想打印网格的一部分,请隐藏不想打印的行和列,然后调用PrintGrid方法,并在打印完成后恢复隐藏的行和列。下面的代码显示了如何做到这一点:

Private Sub PrintSelection(fg As VSFlexGrid, Row1&, Col1&, Row2&, Col2&)
    ' 保存当前设置
Dim hl%, tr&, lc&, rd%
            hl = fg.HighLight: tr = fg.TopRow: lc = fg.LeftCol: rd = fg.Redraw
fg.HighLight = 0
fg.Redraw = flexRDNone
'隐藏未选中的行和列
Dim i&
    For i = fg.FixedRows To fg.Rows – 1
       If i < Row1 Or i > Row2 Then fg.RowHidden(i) = True
    Next
    For i = fg.FixedCols To fg.Cols – 1
      If i < Col1 Or i > Col2 Then fg.ColHidden(i) = True
    Next
    ' 滚动到左上角
    fg.TopRow = fg.FixedRows
    fg.LeftCol = fg.FixedCols
    '打印可视区域
    fg.PrintGrid
    '恢复控件设置
    fg.RowHidden(-1) = False
    fg.ColHidden(-1) = False
    fg.TopRow = tr: fg.LeftCol = lc: fg.HighLight = hl
    fg.Redraw = rd
End Sub

BeforePageBreak 事件在打印控件时触发以便控制分页。其语法为:
Private Sub VSFlexGrid_BeforePageBreak( ByVal Row As Long, BreakOK As Boolean)
说明:
将BreakOK参数设置为True,以指示行号为Row的行应该被允许在页面顶部打印,或将其设置为False以指示其他情况。例如,如果行是小计行或标题行,则将BreakOK设置为True。

GetHeaderRow 事件当在打印控件时触发以便设置重复标题行。其语法:
Private Sub VSFlexGrid_GetHeaderRow( ByVal Row As Long, HeaderRow As Long)

在打印时,GetHeaderRow事件在每个页面的开头(除了第一页之外)被触发,并且可以返回每个页面上应该用作标题的行数。这对于打印需要控制分页的复杂报告特别有用。GetHeaderRow事件的参数描述如下:

Row As Long
此参数包含一页上将作为第一行的行号。

HeaderRow As Long
该参数最初设置为-1,这意味着不需要标题行。如果希望页上有标题行,请将HeaderRow设置为用作标题的行数。

控件可以用PrintGrid方法打印,也可以用VSPrinter控件打印。使用VSPrinter控件的优势在于,它提供了打印预览、将多个网格和其他图形元素整合到单个文档上的能力,以及对打印机的完全控制。VSPrinter控件是一个独立的控件。

2.14 导出网格数据

SaveGrid方法将网格内容和格式保存到文件中。其语法为:
[form!]VSFlexGrid.SaveGrid FileName As String, SaveWhat As SaveLoadSettings, [Options As Boolean ]

此方法将网格保存到二进制文件或文本文件中,以后可以使用LoadGrid方法恢复网格。保存到文本文件的网格也可以由其他程序读取,像Microsoft Excel或Microsoft Word。

SaveGrid方法的参数描述如下:

FileName As String
要创建的文件的名称,包括完整路径。如果具有相同名称的文件已经存在,则覆盖该文件。

SaveWhat As SaveLoadSettings
此参数指定应该保存什么。有效的选项是:

表18.png
表18

Options  As Variant  (可选)
当保存和加载文本文件时,该参数允许你指定固定单元格是否被保存和恢复。默认值False,这意味着固定单元格不被保存或恢复。当保存和加载EXCEL文件时,该参数允许你指定被加载工作表的名称或索引,或被保存工作表的名称。如果省略,则第一个工作表被加载。当保存到Excel时,如果该参数为False,则不会保存标题行和标题列,需要特别注意,且只支持Excel2003格式,如果导出为2007以上版本,该文件无法用Excel打开,而导入2007以上版本会提示文件已经存在。该选项用于保存固定行、列和转换复选框值,选项包括:

表19.png
表19

例如,这些选项可以写成:
fg.SaveGrid "book1.xls", flexFileExcel
fg.SaveGrid "book1.xls", flexFileExcel, "sheetName"
fg.SaveGrid "book1.xls", flexFileExcel, flexXLSaveFixedCells
fg.SaveGrid "book1.xls", flexFileExcel, flexXLSaveFixedCells Or flexXLSaveRaw
fg.SaveGrid "G:\" & Format(Now, "yy-mm-dd hhmmss") & ".xls", flexFileExcel, flexXLSaveFixedCells

flexFileExcel选项不需要Excel安装在电脑上。可以加载和保存Excel97工作表(BIFF9格式),每个工作簿只能有一个工作表(加载时,可以使用Options参数指定加载哪个工作表)。Excel过滤器支持单元格值(包括公式值)、字体、格式、颜色、行和列尺寸。已经做了一些改进,使其现在也支持超过30k行、自动换行和所有ColorAlternate和ColorFrozen属性。它不支持不转换到网格中的那些特性,诸如宏、图表、旋转文本、单元格边框和其他高级格式。

LoadGrid方法从以前使用SaveGrid方法保存的文件、逗号分隔文本文件(CSV格式)如Excel文本文件或Tab分隔符文本文件中加载网格。其语法为:
[form!]VSFlexGrid.LoadGrid FileName As String, LoadWhat As SaveLoadSettings, [ Options As Variant ]
各参数的选项和SaveGrid一致,不再解释。


TA的精华主题

TA的得分主题

 楼主| 发表于 2019-1-1 15:14 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
HHAAMM 发表于 2019-1-1 03:21
很好的教程

盼楼主再来点打印的例子



感谢版主深夜支持。已增加PrintGrid 方法打印表格(BeforePageBreak和GetHeaderRow 事件设置每页表头、页边距),和SaveGrid方法保存网格数据。

可惜该控件不支持预览功能,如果要设计报表和对打印机的完全控制,需要VSPrinter控件,VSPrinter控件跟VSFlexgrid控件一样,有几百个方法和属性。

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

本版积分规则

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

GMT+8, 2024-11-15 22:51 , Processed in 1.051131 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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