Вы находитесь на странице: 1из 44

CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 1 of 44

CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGRID

Trong hầu hết các ví dụ này đều có thể dùng cho MSHFlexGrid, bạn chỉ việc thay đổi MSFlexGrid sang MSHFlexGrid

Hàm sau nhằm tự động điều chỉnh chiều rộng cột và chiều cao của hàng trong MSFlexgrid:

Public Function FG_AutosizeRows(myGrid As MSFlexGrid, Optional ByVal lFirstRow As Long = -1, Optional ByVal lLastRow As Long = -1, Optional bCheckFont As Boolean = False)
' This will only work for Cells with a Chr(13)
' To have it working with WordWrap enabled
' you need some other routine
' Which has been added too
Dim lCol As Long, lRow As Long, lCurCol As Long, lCurRow As Long
Dim lCellHeight As Long, lRowHeight As Long
Dim bFontBold As Boolean
Dim dFontSize As Double
Dim sFontName As String
If bCheckFont Then
' save the forms font settings
bFontBold = Me.FontBold
sFontName = Me.FontName
dFontSize = Me.FontSize
End If
With myGrid
If bCheckFont Then
lCurCol = .Col
lCurRow = .Row
End If
If lFirstRow = -1 Then lFirstRow = 0
If lLastRow = -1 Then lLastRow = .Rows - 1
For lRow = lFirstRow To lLastRow
lRowHeight = 0
If bCheckFont Then .Row = lRow
For lCol = 0 To .Cols - 1
If bCheckFont Then
.Col = lCol
Me.FontBold = .CellFontBold
Me.FontName = .CellFontName
Me.FontSize = .CellFontSize
End If
lCellHeight = Me.TextHeight(.TextMatrix(lRow, lCol))
If lCellHeight > lRowHeight Then lRowHeight = lCellHeight
Next lCol
.RowHeight(lRow) = lRowHeight + Me.TextHeight("Wg") / 5
Next lRow
If bCheckFont Then
.Row = lCurRow
.Col = lCurCol
End If
End With
If bCheckFont Then
' restore the forms font settings
Me.FontBold = bFontBold
Me.FontName = sFontName
Me.FontSize = dFontSize
End If
End Function
Public Function FG_AutosizeCols(myGrid As MSFlexGrid, Optional ByVal lFirstCol As Long = -1, Optional ByVal lLastCol As Long = -1, Optional bCheckFont As Boolean = False)
Dim lCol As Long, lRow As Long, lCurCol As Long, lCurRow As Long
Dim lCellWidth As Long, lColWidth As Long
Dim bFontBold As Boolean
Dim dFontSize As Double
Dim sFontName As String
If bCheckFont Then
' save the forms font settings
bFontBold = Me.FontBold
sFontName = Me.FontName
dFontSize = Me.FontSize
End If
With myGrid
If bCheckFont Then
lCurRow = .Row
lCurCol = .Col
End If
If lFirstCol = -1 Then lFirstCol = 0

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 2 of 44

If lLastCol = -1 Then lLastCol = .Cols - 1


For lCol = lFirstCol To lLastCol
lColWidth = 0
If bCheckFont Then .Col = lCol
For lRow = 0 To .Rows - 1
If bCheckFont Then
.Row = lRow
Me.FontBold = .CellFontBold
Me.FontName = .CellFontName
Me.FontSize = .CellFontSize
End If
lCellWidth = Me.TextWidth(.TextMatrix(lRow, lCol))
If lCellWidth > lColWidth Then lColWidth = lCellWidth
Next lRow
.ColWidth(lCol) = lColWidth + Me.TextWidth("W")
Next lCol
If bCheckFont Then
.Row = lCurRow
.Col = lCurCol
End If
End With
If bCheckFont Then
' restore the forms font settings
Me.FontBold = bFontBold
Me.FontName = sFontName
Me.FontSize = dFontSize
End If
End Function

Kéo và thả giữa hai MSFlexgrid:

Trong ví dụ này cần MSFlexgrid1, MSFlexgrid2, txtDrag (TextBox)

Private Sub Form_Load()


Dim lCol As Long
Dim lRow As Long
With MSFlexGrid1
.Rows = 10
.Cols = 9
For lRow = 0 To .Rows - 1
For lCol = 0 To .Cols - 1
.TextMatrix(lRow, lCol) = "Src: " & lRow & ";" & lCol
Next lCol
Next lRow
End With
With MSFlexGrid2
.Rows = 10
.Cols = 9
For lRow = 0 To .Rows - 1
For lCol = 0 To .Cols - 1
.TextMatrix(lRow, lCol) = "Dst: " & lRow & ";" & lCol
Next lCol
Next lRow
End With
End Sub
Private Sub MSFlexGrid1_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
If Button = vbLeftButton Then
With MSFlexGrid1
.Col = .MouseCol
.Row = .MouseRow
txtDrag.Move .CellLeft, .CellTop, .CellWidth, .CellHeight
txtDrag.Text = .Text
txtDrag.Drag vbBeginDrag
End With
End If
End Sub
Private Sub MSFlexGrid2_DragDrop(Source As Control, x As Single, y As Single)
Dim lCol As Long
Dim lRow As Long
Dim curX As Single
Dim curY As Single
With MSFlexGrid2
For lRow = 0 To .Rows - 1
.Row = lRow

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 3 of 44

.Col = 0
If y > .CellTop And y < .CellTop + .CellHeight Then
For lCol = 0 To .Cols - 1
.Col = lCol
If x > .CellLeft And x < .CellLeft + .CellWidth Then
.Text = txtDrag.Text
Exit For
End If
Next lCol
End If
Next lRow
End With
End Sub

Lưu các giá trị trong lưới vào Excel:

Public Function FG_SaveAsExcel(FG As MSFlexGrid, sFileName As String, Optional sHeader As String = "", Optional sFooter As String = "")
Dim myExcel As ExcelFileV2
Dim lRow As [b]Integer[/b], lCol As [b]Integer[/b]
Dim excelDouble As Double
Dim rowOffset As Long
Dim aTemp() As String
If Len(sHeader) > 0 Then
aTemp = Split(sHeader, vbTab)
rowOffset = UBound(aTemp) + 1
End If
Set myExcel = New ExcelFileV2
With myExcel
.OpenFile sFileName
' Heading
For lRow = 1 To rowOffset
.eWritestring lRow, 1, aTemp(lRow - 1)
Next lRow
' FlexGrid -> Fixedrows
For lRow = 1 To FG.FixedRows
For lCol = 1 To FG.Cols
.eWritestring lRow + rowOffset, lCol, FG.textmatrix(lRow - 1, lCol - 1)
Next lCol
Next lRow
' Data
For lRow = FG.FixedRows + 1 To FG.Rows
' FlexGrid -> Fixedcols
For lCol = 1 To FG.FixedCols
.eWritestring lRow + rowOffset, lCol, FG.textmatrix(lRow - 1, lCol - 1)
Next lCol
' FlexGrid -> Data
For lCol = FG.FixedCols + 1 To FG.Cols
If IsNumeric(FG.textmatrix(lRow - 1, lCol - 1)) Then
excelDouble = CDbl(FG.textmatrix(lRow - 1, lCol - 1)) + 0
.EWriteDouble lRow + rowOffset, lCol, excelDouble
Else
.eWritestring lRow + rowOffset, lCol, FG.textmatrix(lRow - 1, lCol - 1)
End If
Next lCol
Next lRow
' Footer
If Len(sFooter) > 0 Then
aTemp = Split(sFooter, vbTab)
For lRow = 0 To UBound(aTemp)
.eWritestring lRow + rowOffset + FG.Rows + 1, 1, aTemp(lRow)
Next lRow
End If
[b].CloseFile[/b]
End With
End Function

Tự động điều chỉnh kích thước chiều cao của hàng với thuộc tính WordWrap=TRUE

Để dùng ví dụ này các bạn cần có một Form, MSFlexGrid1, Label1

Option Explicit
Private Sub Form_Load()
Dim lCol As Long, lRow As Long

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 4 of 44

' just add some data


With MSFlexGrid1
.Cols = 8
.Rows = 8
.WordWrap = True
For lRow = 1 To .Rows - 1
For lCol = 1 To .Cols - 1
.TextMatrix(lRow, lCol) = "This line is to long and should wrap to the next line"
Next lCol
Next lRow
End With
FG_AutosizeRows MSFlexGrid1, Label1
End Sub
Public Function FG_AutosizeRows(myGrid As MSFlexGrid, myLabel As Label, Optional ByVal lFirstRow As Long = -1, Optional ByVal lLastRow As Long = -1, Optional bCheckFont As Boolean = False)
Dim lCol As Long, lRow As Long, lCurCol As Long, lCurRow As Long
Dim lCellHeight As Long, lRowHeight As Long
Dim bFontBold As Boolean
Dim dFontSize As Double
Dim sFontName As String
With myLabel
.AutoSize = True
.WordWrap = True
End With
With myGrid
If bCheckFont Then
lCurCol = .Col
lCurRow = .Row
End If
If lFirstRow = -1 Then lFirstRow = 0
If lLastRow = -1 Then lLastRow = .Rows - 1
For lRow = lFirstRow To lLastRow
lRowHeight = 0
If bCheckFont Then .Row = lRow
For lCol = 0 To .Cols - 1
If bCheckFont Then
.Col = lCol
myLabel.FontBold = .CellFontBold
myLabel.FontName = .CellFontName
myLabel.FontSize = .CellFontSize
End If
myLabel.Width = .ColWidth(lCol)
myLabel.Caption = .TextMatrix(lRow, lCol)
lCellHeight = myLabel.Height
If lCellHeight > lRowHeight Then lRowHeight = lCellHeight
Next lCol
.RowHeight(lRow) = lRowHeight + Me.TextHeight("Wg") / 5
Next lRow
If bCheckFont Then
.Row = lCurRow
.Col = lCurCol
End If
End With
End Function

Người dùng nhập vào một cách đơn giản:

Private Sub MSFlexGrid1_KeyPress(KeyAscii As Integer)


Dim sTemp As String
With MSFlexGrid1
sTemp = .TextMatrix(.Row, .Col)
Select Case KeyAscii
Case 8 ' backspace
If Len(sTemp) > 0 Then
sTemp = Left$(sTemp, Len(sTemp) - 1)
End If
Case 27 ' escape
sTemp = ""
Case 0 To 31
KeyAscii = 0
Case Else
sTemp = sTemp & Chr$(KeyAscii)
End Select
.TextMatrix(.Row, .Col) = sTemp
End With

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 5 of 44

End Sub

Xoay lưới và chuyển đổi hàng/cột:

Public Sub FG_Rotate(FG As MSFlexGrid)


Dim lRow As Long, lCol As Long
Dim fgText() As String, fgCellAlignment() As Long
Dim fgColHidden() As Boolean, fgRowHidden() As Boolean
Dim fgCols As Long, fgRows As Long
Dim fgFixedCols As Long, fgFixedRows As Long
Dim iMergeCells As Integer, fgMergeRows() As Boolean, fgMergeCols() As Boolean
With FG
' store data
fgRows = .Rows
fgCols = .Cols
fgFixedCols = .FixedCols
fgFixedRows = .FixedRows
iMergeCells = .MergeCells
ReDim fgText(fgRows - 1, fgCols - 1)
ReDim fgCellAlignment(fgRows - 1, fgCols - 1)
ReDim fgRowHidden(fgRows - 1)
ReDim fgColHidden(fgCols - 1)
ReDim fgMergeRows(fgRows - 1)
ReDim fgMergeCols(fgCols - 1)
For lRow = 0 To fgRows - 1
fgRowHidden(lRow) = (.RowHeight(lRow) = 0)
fgMergeRows(lRow) = .MergeRow(lRow)
.Row = lRow
For lCol = 0 To fgCols - 1
If lRow = 0 Then
fgColHidden(lCol) = (.ColWidth(lCol) = 0)
fgMergeCols(lCol) = .MergeCol(lCol)
End If
fgText(lRow, lCol) = .TextMatrix(lRow, lCol)
.Col = lCol
fgCellAlignment(lRow, lCol) = .CellAlignment
Next lCol
Next lRow
' rebuild grid and swap columns/rows
.Redraw = False
.Clear
.Rows = fgCols
.Cols = fgRows
.FixedRows = fgFixedCols
.FixedCols = fgFixedRows
For lRow = 0 To fgRows - 1
.Col = lRow
For lCol = 0 To fgCols - 1
.Row = lCol
.TextMatrix(lCol, lRow) = fgText(lRow, lCol)
.CellAlignment = fgCellAlignment(lRow, lCol)
Next lCol
Next lRow
.MergeCells = iMergeCells
' set hidden columns/rows and merge settings
For lRow = 0 To fgRows - 1
If fgRowHidden(lRow) Then .ColWidth(lRow) = 0
.MergeCol(lRow) = fgMergeRows(lRow)
Next lRow
For lCol = 0 To fgCols - 1
If fgColHidden(lCol) Then .RowHeight(lCol) = 0
.MergeRow(lCol) = fgMergeCols(lCol)
Next lCol
.Redraw = True
End With
End Sub

Sắp xếp nhiều cột:

MSFlexGrid không có chức năng sắp xếp, sau đây là module giúp cho việc sắp xếp này:

Option Explicit
' ***

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 6 of 44

' MSFlexgrid multicolumn sort:


' FG_Sort & MergeSort:
'
' Written by Arnout de Vries for www.visualbasicforum.com
' Use freely
'
' MergeSort is a stable sort, which means that previous sorts
' performed on the data will not be destroyed.
'
' ***
Public Sub FG_Sort(FG As MSFlexGrid, cColToSort As Collection, cColDescending As Collection, cColNumeric As Collection)
Dim lRow As Long, lCol As Long
Dim lNofRows As Long, lNofCols As Long
Dim sGridData() As String
With FG
lNofRows = .Rows - .FixedRows
lNofCols = .Cols
' copy the data to a temp string array
ReDim sGridData(lNofRows - 1, lNofCols - 1)
For lRow = .FixedRows To .Rows - 1
For lCol = 0 To .Cols - 1
sGridData(lRow - .FixedRows, lCol) = .TextMatrix(lRow, lCol)
Next lCol
Next lRow
' sort the data per column (main column last)
For lCol = cColToSort.Count To 1 Step -1
MergeSort sGridData, 0, lNofRows - 1, cColToSort(lCol), lNofCols - 1, cColDescending(lCol), cColNumeric(lCol)
' < These lines can be safely removed
If cColDescending(lCol) Then
.TextMatrix(0, cColToSort(lCol)) = "<(" & lCol & ") " & .TextMatrix(0, cColToSort(lCol))
Else
.TextMatrix(0, cColToSort(lCol)) = ">(" & lCol & ") " & .TextMatrix(0, cColToSort(lCol))
End If
' > These lines can be safely removed
Next lCol
' copy data from string array to flexgrid
For lRow = .FixedRows To .Rows - 1
For lCol = 0 To .Cols - 1
.TextMatrix(lRow, lCol) = sGridData(lRow - .FixedRows, lCol)
Next lCol
Next lRow
End With
Erase sGridData
End Sub
Public Sub MergeSort(sArray() As String, ByVal lLow As Long, ByVal lHigh As Long, lColumn As Long, lDepth As Long, Optional bDescending As Boolean = False, Optional bNumeric As Boolean = False)
Dim lLength As Long
Dim lPivot As Long
Dim Working() As String
Dim i As Long, j As Long
Dim lM1 As Long
Dim lM2 As Long
Dim bGreater As Boolean
If lLow >= lHigh Then Exit Sub
lLength = lHigh - lLow + 1
lPivot = (lLow + lHigh) \ 2
Call MergeSort(sArray, lLow, lPivot, lColumn, lDepth, bDescending, bNumeric)
Call MergeSort(sArray, lPivot + 1, lHigh, lColumn, lDepth, bDescending, bNumeric)
ReDim Working(lLength - 1, lDepth)
For i = 0 To lLength - 1
For j = 0 To lDepth
Working(i, j) = sArray(lLow + i, j)
Next j
Next i
lM1 = 0
lM2 = lPivot - lLow + 1
For i = 0 To lLength - 1
If lM2 <= lHigh - lLow Then
If lM1 <= lPivot - lLow Then
If bNumeric Then
bGreater = CDbl(Working(lM1, lColumn)) > CDbl(Working(lM2, lColumn))
Else
bGreater = Working(lM1, lColumn) > Working(lM2, lColumn)
End If
If bDescending Then bGreater = Not bGreater
If bGreater Then

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 7 of 44

For j = 0 To lDepth
sArray(i + lLow, j) = Working(lM2, j)
Next j
lM2 = lM2 + 1
Else
For j = 0 To lDepth
sArray(i + lLow, j) = Working(lM1, j)
Next j
lM1 = lM1 + 1
End If
Else
For j = 0 To lDepth
sArray(i + lLow, j) = Working(lM2, j)
Next j
lM2 = lM2 + 1
End If
Else
For j = 0 To lDepth
sArray(i + lLow, j) = Working(lM1, j)
Next j
lM1 = lM1 + 1
End If
Next i
Erase Working
End Sub

Chỉnh sửa Cell (More advanced in cell editing):

Để dùng ví dụ này các bạn cần MSFlexGrid1, txtCell (TextBox)

Option Explicit
' to store the row/column of the cell
' being edited
Dim m_lCellCol As Long
Dim m_lCellRow As Long
Private Sub Form_Load()
m_lCellRow = -1
m_lCellCol = -1
txtCell.BorderStyle = 0
txtCell.Visible = False
' set the text background color to the
' backcolor of the tooltip text to make
' the cell being edited having a different color
txtCell.BackColor = vbInfoBackground
MSFlexGrid1.Cols = 10
MSFlexGrid1.Rows = 10
End Sub
Private Sub MSFlexGrid1_DblClick()
showTxtCell
End Sub
Private Sub MSFlexGrid1_RowColChange()
removeTxtCell
End Sub
Private Sub MSFlexGrid1_Scroll()
removeTxtCell
End Sub
Private Sub MSFlexGrid1_SelChange()
removeTxtCell
End Sub
Private Sub txtCell_Change()
MSFlexGrid1.Text = txtCell.Text
End Sub
Private Sub showTxtCell()
If m_lCellRow = -1 Then
With MSFlexGrid1
' store the current row and column
m_lCellRow = .Row
m_lCellCol = .Col
' move the textbox to the correct cell
txtCell.Move .Left + .CellLeft, .Top + .CellTop, .CellWidth, .CellHeight
txtCell.Text = .Text
' select all text
txtCell.SelLength = Len(.Text)
End With

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 8 of 44

txtCell.Visible = True
txtCell.SetFocus
End If
End Sub
Private Sub removeTxtCell()
If m_lCellRow <> -1 Then
MSFlexGrid1.TextMatrix(m_lCellRow, m_lCellCol) = txtCell.Text
m_lCellRow = -1
m_lCellCol = -1
txtCell.Visible = False
End If
End Sub
Private Sub txtCell_Validate(Cancel As Boolean)
removeTxtCell
End Sub

Tô màu xen kẻ cho các hàng:

Để dùng ví dụ này các bạn cần MSFlexGrid1, Command1

Option Explicit
Private Sub Command1_Click()
FG_AlternateRowColors MSFlexGrid1, RGB(255, 255, 192), RGB(255, 255, 255)
End Sub
Private Sub Form_Load()
Dim lCol As Long, lRow As Long
' just fill the grid with some dummy data
With MSFlexGrid1
.Cols = 10
.Rows = 10
For lRow = 0 To .Rows - 1
For lCol = 0 To .Cols - 1
.TextMatrix(lRow, lCol) = "R" & lRow & "C" & lCol
Next lCol
Next lRow
End With
End Sub
Public Sub FG_AlternateRowColors(FG As MSFlexGrid, lColor1 As Long, lcolor2 As Long)
Dim lRow As Long, lCol As Long
Dim lOrgRow As Long, lOrgCol As Long
Dim lColor As Long
With FG ' MSFlexGrid1 <- Bugfix as stated by Trivium
.Redraw = False
' save the current cell position
lOrgRow = .Row
lOrgCol = .Col
' only the data rows
For lRow = .FixedRows To .Rows - 1
.Row = lRow
If lRow / 2 = lRow \ 2 Then
lColor = lColor1
Else
lColor = lcolor2
End If
' only the data columns
For lCol = .FixedCols To .Cols - 1
.Col = lCol
.CellBackColor = lColor
Next lCol
Next lRow
' restore the orginal cell position
.Row = lOrgRow
.Col = lOrgCol
.Redraw = True
End With
End Sub

AutoFilter giống như trong Excel.

Đây là code của Form

Option Explicit

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 9 of 44

' to change the height of a combobox


Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Const CB_SETITEMHEIGHT = &H153
' to get the width a vertical scrollbar
Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
Private Const SM_CXVSCROLL = 2
Dim m_bFilterEnabled As Boolean
Dim m_lRowHeight As Long
Dim m_lComboHeight As Long
Dim m_lScrollWidth As Long
Private Sub cmbFilter_Click(Index As Integer)
If cmbFilter(Index).Visible Then
updateFilter MSFlexGrid1
End If
End Sub
Private Sub cmdFilter_Click()
If m_bFilterEnabled Then
removeFilter MSFlexGrid1
m_bFilterEnabled = False
cmdFilter.Caption = "Show filters"
Else
m_bFilterEnabled = True
showFilter MSFlexGrid1
cmdFilter.Caption = "Hide filters"
End If
End Sub
Private Sub Form_Load()
Dim aColors(4) As String
Dim lCol As Long, lRow As Long
Dim lRnd As Long
' just to fill the grid with some random data
aColors(0) = "Red"
aColors(1) = "Blue"
aColors(2) = "Green"
aColors(3) = "Black"
aColors(4) = "White"
Randomize
m_lScrollWidth = GetSystemMetrics(SM_CXVSCROLL) * Screen.TwipsPerPixelY
With MSFlexGrid1
.Cols = 8
.Rows = 40
.AllowUserResizing = flexResizeColumns
.FixedRows = 1
.FixedCols = 0
.SelectionMode = flexSelectionFree
.ScrollTrack = True
.FocusRect = flexFocusNone
.HighLight = flexHighlightNever
.Row = 0
.Col = 0
m_lComboHeight = (.CellHeight / Screen.TwipsPerPixelY) - 3
.ColSel = .Cols - 1
.FillStyle = flexFillRepeat
.Text = "Color"
.FillStyle = flexFillSingle
For lRow = 1 To .Rows - 1
For lCol = 0 To .Cols - 1
lRnd = Int(Rnd * 5)
.TextMatrix(lRow, lCol) = aColors(lRnd)
Next lCol
Next lRow
'.RowHeight(0) = cmbFilter(0).Height
' store the default rowHeight
' so we can reset the hidden rows
m_lRowHeight = .RowHeight(1)
End With
End Sub
Private Sub Form_Resize()
On Error Resume Next
With MSFlexGrid1
.Move .Left, .Top, Me.ScaleWidth - 2 * .Left, Me.ScaleHeight - .Top - .Left
End With
checkFilter MSFlexGrid1
End Sub
Private Sub MSFlexGrid1_RowColChange()

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 10 of 44

checkFilter MSFlexGrid1
End Sub
Private Sub MSFlexGrid1_Scroll()
checkFilter MSFlexGrid1
End Sub
Private Sub MSFlexGrid1_SelChange()
checkFilter MSFlexGrid1
End Sub
Private Sub showFilter(FG As MSFlexGrid)
Dim cData As Collection
Dim lCol As Long, lRow As Long
Dim i As Long
With MSFlexGrid1
For lCol = .FixedCols To .Cols - 1
' collection to store unique row entries per column
Set cData = New Collection
' cmbFilter(0) already exist on our form
If lCol > 0 Then Load cmbFilter(lCol)
For lRow = .FixedRows To .Rows - 1
' enable error handling, because adding duplicate
' keys to a collection raises an error
' and we only want the unique items
On Error Resume Next
cData.Add .TextMatrix(lRow, lCol), "key:" & .TextMatrix(lRow, lCol)
Next lRow
' add all unique items per column to the combobox
With cmbFilter(lCol)
.Clear
' first add the wildcard for showing all rows
.AddItem "*"
For i = 1 To cData.Count
.AddItem cData(i)
Next i
' make "*" the default selected item
.ListIndex = 0
' move the combobox to the front
.ZOrder
End With
Next lCol
End With
checkFilter FG
End Sub
Private Sub removeFilter(FG As MSFlexGrid)
Dim i As Long
Dim lRow As Long
If Not m_bFilterEnabled Then Exit Sub
' unload all loaded comboboxes
For i = cmbFilter.UBound To cmbFilter.LBound Step -1
If i <> 0 Then Unload cmbFilter(i)
Next i
cmbFilter(0).Visible = False
' remove the row filters
With FG
.Redraw = False
For lRow = .FixedRows To .Rows - 1
.RowHeight(lRow) = m_lRowHeight
Next lRow
.Redraw = True
End With
End Sub
Private Sub checkFilter(FG As MSFlexGrid)
' check whether our comboboxes need
' to be moved or made (in)visible
Dim lCol As Long
Dim lTotWidth As Long
Dim lScrollWidth As Long
If Not m_bFilterEnabled Then Exit Sub
With FG
' is there a vertical scrollbar
lScrollWidth = 0
If .ScrollBars = flexScrollBarBoth Or .ScrollBars = flexScrollBarBoth Then
If Not .RowIsVisible(0) Or Not .RowIsVisible(.Rows - 1) Then
lScrollWidth = m_lScrollWidth
End If
End If

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 11 of 44

For lCol = .FixedCols To .Cols - 1


cmbFilter(lCol).Move .ColPos(lCol) + .Left + 3 * Screen.TwipsPerPixelX, .RowPos(0) + .Top + 2 * Screen.TwipsPerPixelY, .ColWidth(lCol)
cmbFilter(lCol).Visible = False
If .ColIsVisible(lCol) Then
' check if the complete column is visible
' don't want partial columns
lTotWidth = lTotWidth + .ColWidth(lCol)
cmbFilter(lCol).Visible = (lTotWidth < (.Width - lScrollWidth - 4 * Screen.TwipsPerPixelX))
' set the correct height for the combobox
Call SendMessage(cmbFilter(lCol).hWnd, CB_SETITEMHEIGHT, -1&, ByVal m_lComboHeight)
End If
Next lCol
End With
End Sub
Private Sub updateFilter(FG As MSFlexGrid)
Dim lRow As Long, lCol As Long
Dim bShowRow As Boolean
Dim sFilterText As String
With MSFlexGrid1
.Redraw = False
For lRow = .FixedRows To .Rows - 1
' initially we want to show every row
bShowRow = True
For lCol = .FixedCols To .Cols - 1
sFilterText = cmbFilter(lCol).Text
If sFilterText <> "*" Then ' is always ok
If sFilterText <> .TextMatrix(lRow, lCol) Then
' except this one
bShowRow = False
' no need to check the other colums
Exit For
End If
End If
Next lCol
If bShowRow Then
.RowHeight(lRow) = m_lRowHeight
Else
.RowHeight(lRow) = 0
End If
Next lRow
.Redraw = True
End With
End Sub

Xóa cột:

' To remove a column of a MSHFlexGrid


Public Function HFG_RemoveColumn(myGrid As MSHFlexGrid, ByVal lColumn As Long)
With myGrid
.Redraw = False
If lColumn < .Cols Then
.ColPosition(lColumn) = .Cols - 1
.Cols = .Cols - 1
End If
.Redraw = True
End With
End Function
' To remove a column of a MSFlexGrid
Public Function FG_RemoveColumn(myGrid As MSFlexGrid, ByVal lColumn As Long)
With myGrid
.Redraw = False
If lColumn < .Cols Then
.ColPosition(lColumn) = .Cols - 1
.Cols = .Cols - 1
End If
.Redraw = True
End With
End Function

Chọn các hàng giống như trong ListBox:

Option Explicit
' variable to hold our selected rows

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 12 of 44

Private m_cSelectedRows As Collection


Private m_lForeColorSel As Long ' Our forecolor for selections
Private m_lBackColorSel As Long ' Our backcolor for selections
Private Sub Form_Load()
Dim lCol As Long, lRow As Long
' initialise our "selection" settings
Set m_cSelectedRows = New Collection
m_lBackColorSel = vbHighlight
m_lForeColorSel = vbHighlightText
' initialise the grid
With MSFlexGrid1
.Redraw = False
.Cols = 10
.Rows = 10
.AllowBigSelection = False
.SelectionMode = flexSelectionFree
.ForeColorSel = .ForeColor
.BackColorSel = .BackColor
.FocusRect = flexFocusLight
' fill the grid with some data
For lRow = .FixedRows To .Rows - 1
.TextMatrix(lRow, 0) = "Row: " & lRow
For lCol = .FixedCols To .Cols - 1
.TextMatrix(lRow, lCol) = "R" & lRow & "C" & lCol
Next lCol
Next lRow
'
.Redraw = True
End With
End Sub
Private Sub MSFlexGrid1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
' going to check whether a (new) row is selected
' If CTRL is pressed we add the row to the selection
' otherwise we clear the previous selection
With MSFlexGrid1
If .MouseCol >= .FixedCols Then
' not clicked on a fixed column
Exit Sub
End If
If .MouseRow < .FixedRows - 1 Then
' clicked on a fixed row
Exit Sub
End If
If Shift <> vbCtrlMask Then
ClearSelectedRows
End If
AddSelectedRow .MouseRow
End With
End Sub
Private Sub ClearSelectedRows()
Dim lCol As Long, lRow As Long
Dim lColSel As Long, lRowSel As Long
Dim lFillStyle As Long
If m_cSelectedRows.Count = 0 Then
' no previous selected rows
Exit Sub
End If
With MSFlexGrid1
.Redraw = False
' store the original settings
lCol = .Col
lRow = .Row
lColSel = .ColSel
lRowSel = .RowSel
lFillStyle = .FillStyle
' clear the selection
.FillStyle = flexFillRepeat
.Col = .FixedCols
.Row = .FixedRows
.ColSel = .Cols - 1
.RowSel = .Rows - 1
.CellBackColor = .BackColor
.CellForeColor = .ForeColor
' restore the settings
.Col = lCol

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 13 of 44

.Row = lRow
.ColSel = lColSel
.RowSel = lRowSel
.FillStyle = lFillStyle
.Redraw = True
.Refresh
End With
' clear our collection
Do While m_cSelectedRows.Count > 0
m_cSelectedRows.Remove 1
Loop
End Sub
Private Sub AddSelectedRow(lCurRow As Long)
Dim sKey As String
Dim lCol As Long, lRow As Long
Dim lColSel As Long, lRowSel As Long
Dim lFillStyle As Long
' keys in a collection can't be numeric
sKey = "row" & CStr(lCurRow)
With MSFlexGrid1
.Redraw = False
' store the original settings
lCol = .Col
lRow = .Row
lColSel = .ColSel
lRowSel = .RowSel
lFillStyle = .FillStyle
' highlight the selection
.FillStyle = flexFillRepeat
.Col = .FixedCols
.Row = lCurRow
.ColSel = .Cols - 1
.RowSel = lCurRow
.CellBackColor = m_lBackColorSel
.CellForeColor = m_lForeColorSel
.Redraw = True
' restore the settings
.Col = lCol
.Row = lRow
.ColSel = lColSel
.RowSel = lRowSel
.FillStyle = lFillStyle
End With
' some error handling for using collections
On Error Resume Next
m_cSelectedRows.Add lCurRow, sKey
End Sub

Hiện một bảng trong MSFlexGrid:

Option Explicit
Dim m_sDBPath As String
Private Sub Command1_Click()
Dim adoConn As ADODB.Connection
Dim adoRST As ADODB.Recordset
On Error Goto errHandler
' open the connection
Set adoConn = New ADODB.Connection
adoConn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source=" & m_sDBPath
' get a recordset
Set adoRST = New ADODB.Recordset
adoRST.Open "Titles", adoConn, adOpenForwardOnly, , adCmdTable
With adoRST
If Not .EOF Then
FG_ShowRecordset MSFlexGrid1, adoRST
End If
.Close
End With
adoConn.Close
Set adoConn = Nothing
Set adoRST = Nothing
Exit Sub
errHandler:
MsgBox "An error occured." & vbLf & Err.Number & ": " & Err.Description, vbCritical

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 14 of 44

Set adoConn = Nothing


Set adoRST = Nothing
End Sub
Private Sub FG_ShowRecordset(myFG As MSFlexGrid, myRST As ADODB.Recordset)
Dim iField As Integer, iNofFields As Integer
Dim lRow As Long
Screen.MousePointer = vbHourglass
With myRST
.MoveFirst
iNofFields = .Fields.Count
End With
With myFG
.Redraw = False
.AllowUserResizing = flexResizeColumns
.ScrollTrack = True
.FixedCols = 0
.FixedRows = 0
.Cols = iNofFields
.Rows = 1
' setup the header
For iField = 0 To iNofFields - 1
.TextMatrix(0, iField) = myRST.Fields(iField).Name
Next iField
End With
With myRST
Do
' increase the number of rows
lRow = myFG.Rows
myFG.Rows = myFG.Rows + 1
' add the values to the current row
For iField = 0 To iNofFields - 1
If Not IsNull(.Fields(iField).Value) Then
myFG.TextMatrix(lRow, iField) = .Fields(iField).Value
End If
Next iField
' proceed to the next record
.MoveNext
Loop Until .EOF
End With
With myFG
.FixedRows = 1
.Redraw = True
End With
Screen.MousePointer = vbNormal
End Sub
Private Sub Form_Load()
m_sDBPath = "C:\Program Files\Microsoft Visual Studio\VB98\Biblio.MDB"
Me.Caption = m_sDBPath
End Sub

Thay đổi màu nền cho cả cột/hàng:

FlexGridColumnColor MSFlexGrid1, 2, vbRed


FlexGridRowColor MSFlexGrid1, 3, vbBlue

Public Sub FlexGridColumnColor(FlexGrid As MSFlexGrid, ByVal lColumn As Long, ByVal lColor As Long)
Dim lPrevCol As Long, lPrevColSel As Long
Dim lPrevRow As Long, lPrevRowSel As Long
Dim lPrevFillStyle As Long
If lColumn > FlexGrid.Cols - 1 Then Exit Sub
With FlexGrid
' Store the current settings
lPrevCol = .Col
lPrevRow = .Row
lPrevColSel = .ColSel
lPrevRowSel = .RowSel
lPrevFillStyle = .FillStyle
' Change the backcolor
.Col = lColumn
.Row = .FixedRows
.ColSel = lColumn

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 15 of 44

.RowSel = .Rows - 1
.FillStyle = flexFillRepeat
.CellBackColor = lColor
' reset the settings
.Col = lPrevCol
.Row = lPrevRow
.ColSel = lPrevColSel
.RowSel = lPrevRowSel
.FillStyle = lPrevFillStyle
End With
End Sub
Public Sub FlexGridRowColor(FlexGrid As MSFlexGrid, ByVal lRow As Long, ByVal lColor As Long)
Dim lPrevCol As Long, lPrevColSel As Long
Dim lPrevRow As Long, lPrevRowSel As Long
Dim lPrevFillStyle As Long
If lRow > FlexGrid.Rows - 1 Then Exit Sub
With FlexGrid
' Store the current settings
lPrevCol = .Col
lPrevRow = .Row
lPrevColSel = .ColSel
lPrevRowSel = .RowSel
lPrevFillStyle = .FillStyle
' Change the backcolor
.Col = .FixedCols
.Row = lRow
.ColSel = .Cols - 1
.RowSel = lRow
.FillStyle = flexFillRepeat
.CellBackColor = lColor
' reset the settings
.Col = lPrevCol
.Row = lPrevRow
.ColSel = lPrevColSel
.RowSel = lPrevRowSel
.FillStyle = lPrevFillStyle
End With
End Sub

Tự động điều chỉnh các cột trong MSFlexGrid:

Public Function FG_AutosizeCols(myGrid As MSHFlexGrid, Optional ByVal lFirstCol As Long = -1, Optional ByVal lLastCol As Long = -1, Optional bCheckFont As Boolean = False)
Dim lCol As Long, lRow As Long, lCurCol As Long, lCurRow As Long
Dim lCellWidth As Long, lColWidth As Long
Dim bFontBold As Boolean
Dim dFontSize As Double
Dim sFontName As String
If bCheckFont Then
' save the forms font settings
bFontBold = Me.FontBold
sFontName = Me.FontName
dFontSize = Me.FontSize
End If
With myGrid
.Redraw = False
If bCheckFont Then
lCurRow = .Row
lCurCol = .Col
End If
If lFirstCol = -1 Then lFirstCol = 0
' Special for MSHFlexGrid with multiple bands
If lLastCol = -1 Then
lLastCol = 0
For i = 0 To .Bands - 1
lLastCol = lLastCol + .Cols(i)
Next i
lLastCol = lLastCol - 1
End If
For lCol = lFirstCol To lLastCol
lColWidth = 0
If bCheckFont Then .Col = lCol
For lRow = 0 To .Rows - 1
If bCheckFont Then
.Row = lRow

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 16 of 44

Me.FontBold = .CellFontBold
Me.FontName = .CellFontName
Me.FontSize = .CellFontSize
End If
lCellWidth = Me.TextWidth(.TextMatrix(lRow, lCol))
If lCellWidth > lColWidth Then lColWidth = lCellWidth
Next lRow
.ColWidth(lCol) = lColWidth + Me.TextWidth("WW")
Next lCol
If bCheckFont Then
.Row = lCurRow
.Col = lCurCol
End If
.Redraw = True
End With
If bCheckFont Then
' restore the forms font settings
Me.FontBold = bFontBold
Me.FontName = sFontName
Me.FontSize = dFontSize
End If
End Function

In MSFlexGrid dùng hàm API SendMessage:

'Dieser Source stammt von [url]http://www.activevb.de[/url]


'und kann frei verwendet werden. Für eventuelle Schäden
'wird nicht gehaftet.
'Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
'Ansonsten viel Spaß und Erfolg mit diesem Source!
'------------- Anfang Projektdatei Projekt1.vbp -------------
' Die Komponente 'Microsoft FlexGrid Control 6.0 (SP3)
' (MSFLXGRD.OCX)' wird benötigt.
'--------- Anfang Formular "Form1" alias Form1.frm ---------
'Control CommandButton: Command1
'Control FlexGrid: MSFlexGrid1
Option Explicit
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Const WM_USER = &H400
Const VP_FORMATRANGE = WM_USER + 125
Const VP_YESIDO = 456654
Private Type Rect
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type TFormatRange
hdc As Long
hdcTarget As Long
rc As Rect
rcPage As Rect
End Type
Private Sub Command1_Click()
Call PrintGrid(MSFlexGrid1, 20, 25, 20, 20, "ActiveVB - FlexGrid drucken über " & "VP_FORMATRANGE", "")
End Sub
Private Sub Form_Load()
Dim Zahl%
' Fill the flex with 'random' data
With MSFlexGrid1
.ColWidth(0) = 1000
.ColWidth(1) = 2000
.ColWidth(2) = 2600
.ColAlignment(3) = 0
.ColWidth(3) = 500
.ColWidth(4) = 2800
.TextArray(0) = "Name"
.TextArray(1) = "E-Mail"
.TextArray(2) = "HomePage"
.TextArray(3) = "Nr."
.TextArray(4) = "Sonstiges"
For Zahl = 1 To 9
.AddItem "Dirk Lietzow" & vbTab & "dirk@activeVB.de" & vbTab & "www.activeVB.de" & vbTab & Zahl & vbTab & "Alle für einen, einer für alle ..."
Next Zahl

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 17 of 44

' 1. leere Zeile löschen


.RemoveItem 1
' Formatierungsbeispiele
.Col = 2
.Row = 2
.CellFontName = "Arial"
.CellFontSize = 11
.Col = 2
.Row = 3
.CellFontName = "Arial"
.CellFontSize = 12
.Col = 2
.Row = 4
.CellFontName = "Arial"
.CellFontSize = 14
.CellFontBold = True
.RowHeight(.Row) = 500
.Col = 2
.Row = 6
.CellBackColor = &H8000000F
.Col = 2
.Row = 8
.CellFontName = "Courier New"
.CellFontSize = 12
.CellFontBold = True
.CellForeColor = vbWhite
.CellBackColor = &HC00000
.RowHeight(.Row) = 500
End With
End Sub
Sub PrintGrid(Grid As MSFlexGrid, ByVal LeftMargin As Single, ByVal TopMargin As Single, ByVal RightMargin As Single, ByVal BottomMargin As Single, Titel As String, Datum As String, Optional many As Integer)
Dim tRange As TFormatRange
Dim lReturn As Long
Dim DName As String
Dim DSchacht As Integer
Dim gbeg As Long
Dim CopyCW() As Long
Dim GRef As Boolean
Dim X%
GRef = False
If many > 0 Then
' Set the number of columns to be printed
' All columns > many get a colwidth = 0
If Grid.Cols > many Then
gbeg = Grid.Cols - many
ReDim CopyCW(gbeg)
Grid.Redraw = False
For X = many To Grid.Cols - 1
CopyCW(X - many) = Grid.ColWidth(X)
Grid.ColWidth(X) = 0
Next X
GRef = True
End If
End If
'With wParam <> 0 can be checked
'whether the control supports OPP, if it does then the value
'456654 (VP_YESIDO) will be returned
lReturn = SendMessage(Grid.hWnd, VP_FORMATRANGE, 1, 0)
If lReturn = VP_YESIDO Then
' Fill the tRange structure
Printer.ScaleMode = vbPixels
With tRange
.hdc = Printer.hdc
' Height and Width (in Pixel)
.rcPage.Right = Printer.ScaleWidth
.rcPage.Bottom = Printer.ScaleHeight
' Set the printing range in pixels
.rc.Left = Printer.ScaleX(LeftMargin, vbMillimeters)
.rc.Top = Printer.ScaleY(TopMargin, vbMillimeters)
.rc.Right = .rcPage.Right - Printer.ScaleX(RightMargin, vbMillimeters)
.rc.Bottom = .rcPage.Bottom - Printer.ScaleY(BottomMargin, vbMillimeters)
End With
' Initialize printer
Printer.Print vbNullString
' Print page (n)

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 18 of 44

Do
Printer.CurrentX = Printer.ScaleX(LeftMargin, vbMillimeters)
Printer.CurrentY = Printer.ScaleY(10, vbMillimeters)
If Titel <> "" Then Printer.Print Titel
Printer.CurrentX = Printer.ScaleX(LeftMargin, vbMillimeters)
Printer.CurrentY = Printer.ScaleY(16, vbMillimeters)
If Datum <> "" Then
Printer.Print Datum
Else
Printer.Print Format(Date, "DD.MM.YYYY")
End If
lReturn = SendMessage(Grid.hWnd, VP_FORMATRANGE, 0, VarPtr(tRange))
If lReturn < 0 Then
Exit Do
Else
Printer.NewPage
End If
Loop
Printer.EndDoc
'Reset
lReturn = SendMessage(Grid.hWnd, VP_FORMATRANGE, 0, 0)
End If
If GRef Then
' Reset all columns to their original width
For X = many To Grid.Cols - 1
Grid.ColWidth(X) = CopyCW(X - many)
Next X
Grid.Redraw = True
End If
End Sub
'---------- Ende Formular "Form1" alias Form1.frm ----------
'-------------- Ende Projektdatei Projekt1.vbp --------------

Flyquy đã tạo ra một class module nhằm giúp cho việc nhập công thức trong MSFlexGrid giống như trong Excel.

Có hai hàm SUM và AVG

cFlexSpread.TextFormula(4, 3) = "=sum([1,1]:[3,3])"
cFlexSpread.TextFormula(4, 3) = "=avg([1,1]:[3,3])"

Các hàm tóan học khác

cFlexSpread.TextFormula(4, 3) = "=[1,1] * Sin([3,3]))"

Và 3 thủ tục sự kiện:

Private Sub cFlexSpread_AfterEdit(Row As Long, Col As Long)


Debug.Print "AfterEdit", Row, Col
End Sub
Private Sub cFlexSpread_BeforeEdit(Row As Long, Col As Long, Cancel As Boolean)
Debug.Print "Before", Row, Col
' lock column 3
Cancel = (Col = 3)
End Sub
Private Sub cFlexSpread_EvalError(Row As Long, Col As Long)
Debug.Print "EvalError", Row, Col
End Sub

Sau đây là đọan code đó

'---------------------------------------------------------------------------------------
' Module : clsFlexSpread
' DateTime : 14-1-2004 00:29
' Author : FlyGuy
'---------------------------------------------------------------------------------------
Option Explicit
Private WithEvents m_txtCell As TextBox
Attribute m_txtCell.VB_VarHelpID = -1
Private WithEvents m_flexGrid As MSFlexGrid
Attribute m_flexGrid.VB_VarHelpID = -1
Private WithEvents m_Eval As ScriptControl

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 19 of 44

' to store the row/column of the cell being edited


Private m_lCellCol As Long
Private m_lCellRow As Long
Private m_bAutoEdit As Boolean
Private m_bSelf As Boolean
Private m_sNumberFormat As String
Private m_aFormula() As String
Event BeforeEdit(Row As Long, Col As Long, ByRef Cancel As Boolean)
Event AfterEdit(Row As Long, Col As Long)
Event EvalError(Row As Long, Col As Long)
' Public Class Properties
Public Property Set EditBox(objValue As TextBox)
Set m_txtCell = objValue
With m_txtCell
.Visible = False
.BorderStyle = 0
.Visible = False
' set the text background color to the
' backcolor of the tooltip text to make
' the cell being edited having a different color
.BackColor = vbInfoBackground
End With
End Property
Public Property Set Grid(objValue As MSFlexGrid)
Set m_flexGrid = objValue
ReDim m_aFormula(m_flexGrid.Rows, m_flexGrid.Cols)
End Property
Public Property Set Parser(objValue As ScriptControl)
Set m_Eval = objValue
End Property
Public Property Let AutoEdit(ByVal bValue As Boolean)
m_bAutoEdit = bValue
End Property
Public Property Get AutoEdit() As Boolean
AutoEdit = m_bAutoEdit
End Property
Public Property Let NumberFormat(ByVal sValue As String)
m_sNumberFormat = sValue
End Property
Public Property Get NumberFormat() As String
NumberFormat = m_sNumberFormat
End Property
Public Property Let TextFormula(ByVal lRow As Long, ByVal lCol As Long, sValue As String)
If lRow <= m_flexGrid.Rows And lCol <= m_flexGrid.Cols And lRow >= 0 And lCol >= 0 Then
m_aFormula(lRow, lCol) = sValue
m_lCellCol = lCol
m_lCellRow = lRow
m_flexGrid.TextMatrix(lRow, lCol) = ParseText(sValue)
m_lCellCol = -1
m_lCellRow = -1
Else
Err.Raise 9
End If
End Property
Public Property Get TextFormula(ByVal lRow As Long, ByVal lCol As Long) As String
TextFormula = m_aFormula(lRow, lCol)
End Property
' Private Class Events
Private Sub m_flexGrid_Click()
If m_bAutoEdit Then showTxtCell
End Sub
Private Sub m_flexGrid_DblClick()
If Not m_bAutoEdit Then showTxtCell
End Sub
Private Sub m_flexGrid_RowColChange()
removeTxtCell
If m_bAutoEdit Then showTxtCell
End Sub
Private Sub m_flexGrid_Scroll()
removeTxtCell
End Sub
Private Sub m_flexGrid_SelChange()
If Not m_bAutoEdit Then removeTxtCell
End Sub
Private Sub m_Eval_Error()

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 20 of 44

RaiseEvent EvalError(m_lCellRow, m_lCellCol)


End Sub
Private Sub m_txtCell_Change()
m_flexGrid.Text = m_txtCell.Text
End Sub
Private Sub m_txtCell_KeyDown(KeyCode As Integer, Shift As Integer)
If Shift = 0 Then
With m_flexGrid
Select Case KeyCode
Case vbKeyUp
KeyCode = 0
If .Row > .FixedRows Then .Row = .Row - 1 Else .Row = .Rows - 1
Case vbKeyDown
KeyCode = 0
If .Row < .Rows - 1 Then .Row = .Row + 1 Else .Row = .FixedRows
Case vbKeyLeft
If m_txtCell.SelStart = 0 Then
KeyCode = 0
If .Col > .FixedCols Then .Col = .Col - 1
End If
Case vbKeyRight
If m_txtCell.SelStart = Len(m_txtCell.Text) Then
KeyCode = 0
If .Col < .Cols - 1 Then .Col = .Col + 1
End If
End Select
End With
End If
End Sub
Private Sub m_txtCell_KeyPress(KeyAscii As Integer)
If KeyAscii = 13 Then
KeyAscii = 0
removeTxtCell
If m_flexGrid.Row < m_flexGrid.Rows - 1 Then
m_flexGrid.Row = m_flexGrid.Row + 1
End If
End If
End Sub
Private Sub m_txtCell_Validate(Cancel As Boolean)
removeTxtCell
End Sub
' Private Class Functions
Private Sub showTxtCell()
Dim bCancel As Boolean
If m_bSelf Then Exit Sub
If m_lCellRow <> -1 Then Exit Sub
On Error GoTo showTxtCell_Error
With m_flexGrid
' store the current row and column
m_lCellRow = .Row
m_lCellCol = .Col
RaiseEvent BeforeEdit(m_lCellRow, m_lCellCol, bCancel)
If bCancel Then
m_lCellRow = -1
Else
m_txtCell.Text = m_aFormula(m_lCellRow, m_lCellCol)
' make sure the cell is visible
m_bSelf = True
Do Until .RowIsVisible(m_lCellRow) Or .RowIsVisible(.Rows - 1)
.TopRow = .TopRow + 1
Loop
Do Until .RowIsVisible(m_lCellRow) Or .RowIsVisible(.FixedRows)
.TopRow = .TopRow - 1
Loop
Do Until .ColIsVisible(m_lCellCol) Or .ColIsVisible(.Cols - 1)
.LeftCol = .LeftCol + 1
Loop
Do Until .ColIsVisible(m_lCellCol) Or .ColIsVisible(.FixedCols)
.LeftCol = .LeftCol - 1
Loop
m_bSelf = False
' move the textbox to the correct cell
m_txtCell.Move .Left + .CellLeft, .Top + .CellTop, .CellWidth, .CellHeight
End If
End With

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 21 of 44

If Not bCancel Then


With m_txtCell
' select all text
If Len(.Text) > 0 Then
.SelStart = 0
.SelLength = Len(.Text)
End If
.Visible = True
.ZOrder
.SetFocus
End With
End If
On Error GoTo 0
Exit Sub
showTxtCell_Error:
Err.Raise 1001, "clsFlexSpread", "Grid dimensions have changed!"
End Sub
Private Sub removeTxtCell()
If m_bSelf Then Exit Sub
If m_lCellRow <> -1 Then
m_flexGrid.TextMatrix(m_lCellRow, m_lCellCol) = ParseText(m_txtCell.Text)
RaiseEvent AfterEdit(m_lCellRow, m_lCellCol)
m_lCellRow = -1
m_lCellCol = -1
m_txtCell.Visible = False
End If
End Sub
Private Function ParseText(ByVal sText As String) As String
Dim sFunction As String
Dim sParam As String
Dim sTemp As String
' by default we return the given text
ParseText = sText
' store the orginal text in the formula array
m_aFormula(m_lCellRow, m_lCellCol) = sText
If Len(Trim$(sText)) = 0 Then Exit Function
If IsNumeric(sText) Then Exit Function
If Left$(sText, 1) <> "=" Then Exit Function
' do we have a range function?
sTemp = UCase$(Mid$(sText, 2, 3))
If sTemp = "SUM" Or sTemp = "AVG" Then
sFunction = sTemp
sParam = Mid$(sText, 6, Len(sText) - 6)
ParseText = ParseFunction(sFunction, sParam)
Else
' Maybe it can be evaluated
ParseText = ParseEvaluate(Mid$(sText, 2))
End If
If ParseText = "#ERR!" Then RaiseEvent EvalError(m_lCellRow, m_lCellCol)
End Function
Private Function ParseFunction(sFunction As String, ByVal sParams As String) As String
Dim bRange As Boolean
' By default we asume it's an error ;-)
ParseFunction = "#ERR!"
On Error GoTo ParseFunction_Error
sParams = Replace$(sParams, ";", ":")
bRange = InStr(1, sParams, ":", vbBinaryCompare) > 0
If bRange Then
ParseFunction = ParseRange(sFunction, sParams)
End If
On Error GoTo 0
Exit Function
ParseFunction_Error:
End Function
Private Function ParseRange(sFunction As String, ByVal sParams As String) As String
Dim aSplitted() As String
Dim sCellFrom As String
Dim sCellTo As String
Dim lColStart As Long, lColEnd As Long
Dim lRowStart As Long, lRowEnd As Long
Dim lCol As Long, lRow As Long
Dim dSum As Double
Dim lCnt As Long
' By default we asume it's an error ;-)
ParseRange = "#ERR!"

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 22 of 44

On Error GoTo ParseRange_Error


sParams = Replace$(sParams, ";", ":")
' cell pairs delimited by :
aSplitted = Split(sParams, ":")
If UBound(aSplitted) <> 1 Then Exit Function
sCellFrom = aSplitted(0)
sCellTo = aSplitted(1)
If GetRowCol(sCellFrom, lRowStart, lColStart) Then
If GetRowCol(sCellTo, lRowEnd, lColEnd) Then
With m_flexGrid
For lRow = lRowStart To lRowEnd
If lRow >= 0 And lRow < .Rows Then
For lCol = lColStart To lColEnd
If lCol >= 0 And lCol < .Cols Then
If IsNumeric(.TextMatrix(lRow, lCol)) Then
dSum = dSum + CDbl(.TextMatrix(lRow, lCol))
lCnt = lCnt + 1
End If
End If
Next lCol
End If
Next lRow
End With
Select Case UCase$(sFunction)
Case "SUM"
ParseRange = Format(dSum, m_sNumberFormat)
Case "AVG"
If lCnt <> 0 Then
ParseRange = Format((dSum / lCnt), m_sNumberFormat)
Else
RaiseEvent EvalError(m_lCellRow, m_lCellCol)
ParseRange = "#DIV0!"
End If
End Select
End If
End If
On Error GoTo 0
Exit Function
ParseRange_Error:
End Function
Private Function ParseEvaluate(ByVal sEval As String) As String
Dim sValue As String
Dim lPos As Long, lPos2 As Long
Dim sTemp As String
ParseEvaluate = "#ERR!"
' First replace all [x,y] with actual grid values
lPos = InStr(1, sEval, "[", vbBinaryCompare)
Do While lPos > 0
lPos2 = InStr(lPos + 1, sEval, "]", vbBinaryCompare)
If lPos2 > 0 Then
sTemp = Mid$(sEval, lPos + 1, lPos2 - lPos - 1)
If GetValue(sTemp, sValue) Then
sEval = Replace$(sEval, "[" & sTemp & "]", sValue, , , vbBinaryCompare)
' search for the next [x,y]
lPos = InStr(1, sEval, "[", vbBinaryCompare)
Else
lPos = 0
End If
Else
lPos = 0
End If
Loop
On Error Resume Next
sTemp = m_Eval.Eval(sEval)
If Err.Number = 0 Then
If Len(sTemp) > 0 Then
If IsNumeric(sTemp) Then
ParseEvaluate = Format(CDbl(sTemp), m_sNumberFormat)
End If
End If
End If
End Function
Private Function GetRowCol(ByVal sText As String, ByRef Row As Long, ByRef Col As Long) As Boolean
Dim lPos As Long
On Error GoTo GetRowCol_Error

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 23 of 44

sText = Replace$(sText, "[", "")


sText = Replace$(sText, "]", "")
lPos = InStr(1, sText, ",", vbBinaryCompare)
If lPos > 0 Then
Row = CLng(Left$(sText, lPos - 1))
Col = CLng(Mid$(sText, lPos + 1))
End If
GetRowCol = True
On Error GoTo 0
Exit Function
GetRowCol_Error:
End Function
Private Function GetValue(ByVal sText As String, ByRef sValue As String) As Boolean
Dim lPos As Long
Dim lRow As Long, lCol As Long
On Error GoTo GetValue_Error
sText = Replace$(sText, "[", "")
sText = Replace$(sText, "]", "")
lPos = InStr(1, sText, ",", vbBinaryCompare)
If lPos > 0 Then
lRow = CLng(Left$(sText, lPos - 1))
lCol = CLng(Mid$(sText, lPos + 1))
sValue = m_flexGrid.TextMatrix(lRow, lCol)
Else
sValue = sText
End If
GetValue = True
On Error GoTo 0
Exit Function
GetValue_Error:
End Function
' Class events
Private Sub Class_Initialize()
m_lCellRow = -1
m_lCellCol = -1
End Sub
Private Sub Class_Terminate()
Set m_flexGrid = Nothing
Set m_txtCell = Nothing
Set m_Eval = Nothing
End Sub

Một ví dụ khác dùng class để lưu / load dữ liệu của MSFlexGrid xuống/từ file *.INI

Code của Form1

Option Explicit
Private Sub Form_Load()
Dim lCol As Long, lRow As Long
' Just fill the first grid with some data
' Note: you can resize the columns using the mouse
With MSFlexGrid1
.Cols = 10
.Rows = 12
.ColAlignment(-1) = flexAlignCenterCenter
.FixedCols = 2
.FixedRows = 2
.AllowUserResizing = flexResizeColumns
For lRow = 0 To .Rows - 1
For lCol = 0 To .Cols - 1
.TextMatrix(lRow, lCol) = "R" & lRow & "C" & lCol
If lRow / 3 = lRow \ 3 Then
If lCol / 2 = lCol \ 2 Then
.Row = lRow
.Col = lCol
.CellFontBold = True
End If
End If
Next lCol
Next lRow
End With
End Sub
' The Save button
Private Sub Command1_Click()

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 24 of 44

Dim cFlexSettings As clsFlexSettings


Set cFlexSettings = New clsFlexSettings
Set cFlexSettings.FlexGrid = MSFlexGrid1
cFlexSettings.SaveSettings "c:\test.flex", True, True, True, True
Me.Caption = "c:\test.flex"
End Sub
' The Load Button
Private Sub Command2_Click()
Dim cFlexSettings As clsFlexSettings
Set cFlexSettings = New clsFlexSettings
Set cFlexSettings.FlexGrid = MSFlexGrid2
cFlexSettings.LoadSettings "c:\test.flex", True, True, True, True
End Sub

Module clsINI

'---------------------------------------------------------------------------------------
' Module : clsINI
' DateTime : 22-8-2003 09:48
' Author : FlyGuy
' Purpose : A collection of clsSection to manipulate INI files
'---------------------------------------------------------------------------------------
Option Explicit
'local variable to hold collection
Private mCol As Collection
Private m_sFileName As String
Private Function NewSection(SectionKey As String) As clsSection
'create a new object
Dim objNewMember As clsSection
Set objNewMember = New clsSection
'set the properties passed into the method
objNewMember.Key = SectionKey
mCol.Add objNewMember, SectionKey
'return the object created
Set NewSection = objNewMember
Set objNewMember = Nothing
End Function
Public Function AddSection(SectionKey As String, cSection As clsSection) As Boolean
' return False if section already exists
If Not SectionExists(SectionKey) Then
mCol.Add cSection, SectionKey
AddSection = True
End If
End Function
Public Property Get Section(vntIndexKey As Variant) As clsSection
Attribute Section.VB_UserMemId = 0
'used when referencing an element in the collection
'vntIndexKey contains either the Index or Key to the collection,
'this is why it is declared as a Variant
'Syntax: Set foo = x.Item(xyz) or Set foo = x.Item(5)
If IsNumeric(vntIndexKey) Then
' get section based on Index
If vntIndexKey > 0 And vntIndexKey <= mCol.Count Then
Set Section = mCol(vntIndexKey)
End If
Else
' get section based on key
' if section doesn't exist, create new one
If SectionExists(CStr(vntIndexKey)) Then
Set Section = mCol(vntIndexKey)
Else
Set Section = New clsSection
Section.Key = CStr(vntIndexKey)
mCol.Add Section, CStr(vntIndexKey)
End If
End If
End Property
Public Function SectionExists(sKey As String) As Boolean
Dim aKeys() As String, i As Long
' Instead of error trapping
If mCol.Count > 0 Then
aKeys = SectionKeys
For i = 0 To UBound(aKeys)
If LCase$(aKeys(i)) = LCase$(sKey) Then

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 25 of 44

SectionExists = True
End If
Next i
End If
End Function
Public Function SectionKeys() As String()
Dim i As Long
Dim aTemp() As String
Dim cSection As clsSection
If mCol.Count > 0 Then
ReDim aTemp(mCol.Count - 1)
For i = 1 To mCol.Count
Set cSection = mCol(i)
aTemp(i - 1) = cSection.Key
Next i
End If
SectionKeys = aTemp
End Function
Public Property Let Value(sSection As String, sItem As String, sValue As String)
If Not SectionExists(sSection) Then
NewSection sSection
End If
mCol.Item(sSection).Item(sItem) = sValue
End Property
Public Property Get Value(sSection As String, sItem As String) As String
If SectionExists(sSection) Then
Value = mCol.Item(sSection).Item(sItem)
End If
End Property
Public Property Get Count() As Long
'used when retrieving the number of elements in the
'collection. Syntax: Debug.Print x.Count
Count = mCol.Count
End Property
Public Property Let FileName(ByVal sValue As String)
m_sFileName = sValue
End Property
Public Property Get FileName() As String
FileName = m_sFileName
End Property
Public Sub Remove(vntIndexKey As Variant)
'used when removing an element from the collection
'vntIndexKey contains either the Index or Key, which is why
'it is declared as a Variant
'Syntax: x.Remove(xyz)
If IsNumeric(vntIndexKey) Then
If vntIndexKey > 0 And vntIndexKey <= mCol.Count Then
mCol.Remove vntIndexKey
End If
Else
If SectionExists(CStr(vntIndexKey)) Then
mCol.Remove vntIndexKey
End If
End If
End Sub
Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Attribute NewEnum.VB_MemberFlags = "40"
'this property allows you to enumerate
'this collection with the For...Each syntax
Set NewEnum = mCol.[_NewEnum]
End Property
Private Sub Class_Initialize()
'creates the collection when this class is created
Set mCol = New Collection
End Sub
Private Sub Class_Terminate()
'destroys collection when this class is terminated
Set mCol = Nothing
End Sub
Public Function FromString(ByVal TheData As String, Optional bAppend As Boolean = False) As String
Dim mcolSection As clsSection
Dim i As Long
Dim sKeySection As String
Dim sKey As String, sData As String, sLine As String

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 26 of 44

Dim lPos As Long


Dim aData() As String
On Error GoTo FromString_Error
If Not bAppend Then
Class_Initialize
End If
Set mcolSection = New clsSection
If Len(TheData) > 0 Then
aData = Split(TheData, vbCrLf)
For i = 0 To UBound(aData)
sLine = aData(i)
If Len(sLine) > 0 And Left$(sLine, 1) <> ";" Then
If Left$(sLine, 1) = "[" Then
' eventueel vorige sectie toevoegen
If Len(mcolSection.Key) > 0 Then
If Not AddSection(mcolSection.Key, mcolSection) Then
FromString = "Section already exists!" & vbCrLf & mcolSection.Key & vbCrLf
End If
End If
' section key
sKeySection = Mid$(sLine, 2, Len(sLine) - 2)
' toevoegen
If SectionExists(sKeySection) Then
Set mcolSection = mCol(sKeySection)
Else
Set mcolSection = New clsSection
mcolSection.Key = sKeySection
End If
Else
lPos = InStr(1, sLine, "=", vbTextCompare)
If lPos > 1 Then
sKey = Left$(sLine, lPos - 1)
sData = Mid$(sLine, lPos + 1)
'Add/update with new values
mcolSection.Item(sKey) = sData
End If
End If
End If
Next i
If Len(mcolSection.Key) > 0 Then
If Not AddSection(mcolSection.Key, mcolSection) Then
FromString = "Section already exists!" & vbCrLf & mcolSection.Key & vbCrLf
End If
End If
End If
On Error GoTo 0
Exit Function
FromString_Error:
MsgBox "Error: " & Err.Number & " on line: " & Erl & vbLf & "Description: " & Err.Description & vbLf & "in procedure FromString of Class Module clsINI", vbCritical
On Error GoTo 0
End Function
Public Function Load(ByVal sName As String, Optional bAppend As Boolean = False) As Long
Dim iID As Integer
Dim sData As String
Dim sMessage As String
On Error GoTo errHandler
Load = -1
m_sFileName = sName
If Len(Dir(sName)) = 0 Then
Load = 53
Exit Function ' file does not exist
End If
' Read from file
iID = FreeFile
Open sName For Input As iID
sData = Input(LOF(iID), iID)
Close iID
' Build data
sMessage = FromString(sData, bAppend)
If Len(sMessage) > 0 Then MsgBox sMessage & vbCrLf & sName, vbExclamation
Load = 0
On Error GoTo 0
Exit Function
errHandler:
Close iID

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 27 of 44

Load = Err.Number
On Error GoTo 0
End Function
Public Function ToString() As String
Dim i As Long, j As Long
Dim cSection As clsSection
For i = 1 To mCol.Count
Set cSection = mCol(i)
If i = 1 Then
ToString = vbCrLf & "[" & cSection.Key & "]"
Else
ToString = ToString & vbCrLf & vbCrLf & "[" & cSection.Key & "]"
End If
For j = 1 To cSection.Count
ToString = ToString & vbCrLf & cSection.DataLine(j)
Next j
Next i
End Function
Public Function Save(Optional ByVal sName As String = "", Optional sApplication As String = "") As Long
Dim iID As Integer
Dim sData As String
On Error GoTo errHandler
If Len(sName) > 0 Then m_sFileName = sName
If Len(m_sFileName) = 0 Then
Save = 53 ' File not found
Exit Function
End If
iID = FreeFile
sData = ToString
If Len(sData) > 0 Then
Open m_sFileName For Output As iID
Print #iID, "; This file is generated by software, do not modify it by hand"
If Len(sApplication) > 0 Then
Print #iID, "; application = " & sApplication
End If
Print #iID, "; date = " & Format(Date, "yyyymmdd")
Print #iID, "; time = " & Format(Time, "HHnnss")
Print #iID, sData
Close iID
End If
Save = 0
On Error GoTo 0
Exit Function
errHandler:
Close iID
Save = Err.Number
On Error GoTo 0
End Function
Public Sub Clone(cINI As clsINI)
Set mCol = New Collection
FromString cINI.ToString
m_sFileName = cINI.FileName
End Sub

Class module clsFlexSettings:

Option Explicit
Private m_FG As MSFlexGrid ' The FlexGrid
Private m_cINI As clsINI ' The INI file in which we store our settings
Private Type tpCELL
Alignment As String
BackColor As String
ForeColor As String
FontBold As String
FontItalic As String
FontSize As String
FontName As String
TextStyle As String
End Type
Public Property Set FlexGrid(theGrid As MSFlexGrid)
Set m_FG = theGrid
End Property

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 28 of 44

Public Property Get FlexGrid() As MSFlexGrid


Set FlexGrid = m_FG
End Property
Public Function LoadSettings(sFileName As String, Optional bLoadGeneral As Boolean, Optional bLoadLayout As Boolean, Optional
bLoadData As Boolean, Optional bLoadCellSettings As Boolean) As Boolean
On Error GoTo LoadSettings_Error
If Not Exists(sFileName) Then Exit Function
If m_FG Is Nothing Then Exit Function
Set m_cINI = New clsINI
m_cINI.Load sFileName
m_FG.Redraw = False
' The general grid settings
If bLoadGeneral Then If m_cINI.SectionExists("General") Then LoadGeneral
' Layout
If bLoadLayout Then If m_cINI.SectionExists("Layout") Then LoadLayout
' Cell definitions
If bLoadCellSettings Then If m_cINI.SectionExists("CellLayout") Then LoadCellLayout
' The actual data
If bLoadData Then If m_cINI.SectionExists("Data") Then LoadData
m_FG.Redraw = True
On Error GoTo 0
Exit Function
LoadSettings_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure LoadSettings of
Class Module clsFlexSettings", vbCritical
End Function
Public Function SaveSettings(sFileName As String, Optional bSaveGeneral As Boolean, Optional bSaveLayout As Boolean, Optional
bSaveData As Boolean, Optional bSaveCellSettings As Boolean) As Boolean
Dim lRow As Long, lCol As Long, lRowSel As Long, lColSel As Long
On Error GoTo SaveSettings_Error
If m_FG Is Nothing Then Exit Function
If Len(sFileName) = 0 Then Exit Function
Set m_cINI = New clsINI
m_cINI.FileName = sFileName
With m_FG
lRow = .Row
lRowSel = .RowSel
lCol = .Col
lColSel = .ColSel
.Redraw = False
End With
If bSaveGeneral Then SaveGeneral
If bSaveLayout Then SaveLayout
If bSaveCellSettings Then SaveCellLayout
If bSaveData Then SaveData
With m_FG
.Row = lRow
.Col = lCol
.RowSel = lRowSel
.ColSel = lColSel
.Redraw = True
End With
m_cINI.Save
SaveSettings = True
On Error GoTo 0
Exit Function
SaveSettings_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure SaveSettings of
Class Module clsFlexSettings", vbCritical
End Function
Private Function Exists(FileName As String) As Boolean
Exists = Len(Dir$(FileName)) > 0
End Function
'---------------------------------------------------------------------------------------
' Procedure : LoadGeneral
' DateTime : 4-7-2004 00:00
' Author : Flyguy
' Purpose :
'---------------------------------------------------------------------------------------
'
Private Sub LoadGeneral()
Dim cSection As clsSection
On Error GoTo LoadGeneral_Error
Set cSection = m_cINI.Section("General")
With m_FG

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 29 of 44

.AllowBigSelection = CBool(cSection.Value("AllowBigSelection", CBool(.AllowBigSelection)))


.AllowUserResizing = CInt(cSection.Value("AllowUserResizing", CInt(.AllowUserResizing)))
.Appearance = CInt(cSection.Value("Appearance", CInt(.Appearance)))
.BackColor = CLng(cSection.Value("BackColor", CLng(.BackColor)))
.BackColorBkg = CLng(cSection.Value("BackColorBkg", CLng(.BackColorBkg)))
.BackColorFixed = CLng(cSection.Value("BackColorFixed", CLng(.BackColorFixed)))
.BackColorSel = CLng(cSection.Value("BackColorSel", CLng(.BackColorSel)))
.BorderStyle = CInt(cSection.Value("BorderStyle", CInt(.BorderStyle)))
.CausesValidation = CBool(cSection.Value("CausesValidation", CBool(.CausesValidation)))
.DragMode = CInt(cSection.Value("DragMode", CInt(.DragMode)))
.Enabled = CBool(cSection.Value("Enabled", CBool(.Enabled)))
.FillStyle = CInt(cSection.Value("FillStyle", CInt(.FillStyle)))
.FocusRect = CInt(cSection.Value("FocusRect", CInt(.FocusRect)))
.Font.Bold = CBool(cSection.Value("Font.Bold", CBool(.Font.Bold)))
.Font.Charset = cSection.Value("Font.Charset", .Font.Charset)
.Font.Italic = CBool(cSection.Value("Font.Italic", CBool(.Font.Italic)))
.Font.Name = cSection.Value("Font.Name", .Font.Name)
.Font.Size = CInt(cSection.Value("Font.Size", CInt(.Font.Size)))
.Font.Strikethrough = CBool(cSection.Value("Font.Strikethrough", CBool(.Font.Strikethrough)))
.Font.Underline = CBool(cSection.Value("Font.Underline", CBool(.Font.Underline)))
.Font.Weight = CInt(cSection.Value("Font.Weight", CInt(.Font.Weight)))
.FontWidth = CLng(cSection.Value("FontWidth", CLng(.FontWidth)))
.ForeColor = CLng(cSection.Value("ForeColor", CLng(.ForeColor)))
.ForeColorFixed = CLng(cSection.Value("ForeColorFixed", CLng(.ForeColorFixed)))
.ForeColorSel = CLng(cSection.Value("ForeColorSel", CLng(.ForeColorSel)))
.FormatString = cSection.Value("FormatString", .FormatString)
.GridColor = CLng(cSection.Value("GridColor", CLng(.GridColor)))
.GridColorFixed = CLng(cSection.Value("GridColorFixed", CLng(.GridColorFixed)))
.GridLines = CLng(cSection.Value("GridLines", CLng(.GridLines)))
.GridLinesFixed = CLng(cSection.Value("GridLinesFixed", CLng(.GridLinesFixed)))
.GridLineWidth = CLng(cSection.Value("GridLineWidth", CLng(.GridLineWidth)))
.HighLight = CInt(cSection.Value("HighLight", CInt(.HighLight)))
.MergeCells = CInt(cSection.Value("MergeCells", CInt(.MergeCells)))
.MousePointer = CInt(cSection.Value("MousePointer", CInt(.MousePointer)))
.RowHeightMin = CLng(cSection.Value("RowHeightMin", CLng(.RowHeightMin)))
.ScrollBars = CInt(cSection.Value("ScrollBars", CInt(.ScrollBars)))
.ScrollTrack = CInt(cSection.Value("ScrollTrack", CInt(.ScrollTrack)))
.SelectionMode = CInt(cSection.Value("SelectionMode", CInt(.SelectionMode)))
.Tag = cSection.Value("Tag", CStr(.Tag))
.TextStyle = CInt(cSection.Value("TextStyle", CInt(.TextStyle)))
.TextStyleFixed = CInt(cSection.Value("TextStyleFixed", CInt(.TextStyleFixed)))
.WordWrap = CBool(cSection.Value("WordWrap", CBool(.WordWrap)))
End With
On Error GoTo 0
Exit Sub
LoadGeneral_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure LoadGeneral of Class
Module clsFlexSettings", vbCritical
End Sub
'---------------------------------------------------------------------------------------
' Procedure : SaveGeneral
' DateTime : 4-7-2004 00:00
' Author : Flyguy
' Purpose :
'---------------------------------------------------------------------------------------
'
Private Sub SaveGeneral()
Dim cSection As clsSection
On Error GoTo SaveGeneral_Error
Set cSection = New clsSection
cSection.Key = "General"
With m_FG
cSection.Item("AllowBigSelection") = CBool(.AllowBigSelection)
cSection.Item("AllowUserResizing") = CInt(.AllowUserResizing)
cSection.Item("Appearance") = CInt(.Appearance)
cSection.Item("BackColor") = CLng(.BackColor)
cSection.Item("BackColorBkg") = CLng(.BackColorBkg)
cSection.Item("BackColorFixed") = CLng(.BackColorFixed)
cSection.Item("BackColorSel") = CLng(.BackColorSel)
cSection.Item("BorderStyle") = CInt(.BorderStyle)
cSection.Item("CausesValidation") = CBool(.CausesValidation)
cSection.Item("DragMode") = CInt(.DragMode)
cSection.Item("Enabled") = CBool(.Enabled)
cSection.Item("FillStyle") = CInt(.FillStyle)
cSection.Item("FocusRect") = CInt(.FocusRect)

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 30 of 44

cSection.Item("Font.Bold") = CBool(.Font.Bold)
cSection.Item("Font.Charset") = .Font.Charset
cSection.Item("Font.Italic") = CBool(.Font.Italic)
cSection.Item("Font.Name") = .Font.Name
cSection.Item("Font.Size") = CInt(.Font.Size)
cSection.Item("Font.Strikethrough") = CBool(.Font.Strikethrough)
cSection.Item("Font.Underline") = CBool(.Font.Underline)
cSection.Item("Font.Weight") = CInt(.Font.Weight)
cSection.Item("FontWidth") = CLng(.FontWidth)
cSection.Item("ForeColor") = CLng(.ForeColor)
cSection.Item("ForeColorFixed") = CLng(.ForeColorFixed)
cSection.Item("ForeColorSel") = CLng(.ForeColorSel)
cSection.Item("FormatString") = .FormatString
cSection.Item("GridColor") = CLng(.GridColor)
cSection.Item("GridColorFixed") = CLng(.GridColorFixed)
cSection.Item("GridLines") = CLng(.GridLines)
cSection.Item("GridLinesFixed") = CLng(.GridLinesFixed)
cSection.Item("GridLineWidth") = CLng(.GridLineWidth)
cSection.Item("HighLight") = CInt(.HighLight)
cSection.Item("MergeCells") = CInt(.MergeCells)
cSection.Item("MousePointer") = CInt(.MousePointer)
cSection.Item("RowHeightMin") = CLng(.RowHeightMin)
cSection.Item("ScrollBars") = CInt(.ScrollBars)
cSection.Item("ScrollTrack") = CInt(.ScrollTrack)
cSection.Item("SelectionMode") = CInt(.SelectionMode)
cSection.Item("Tag") = CStr(.Tag)
cSection.Item("TextStyle") = CInt(.TextStyle)
cSection.Item("TextStyleFixed") = CInt(.TextStyleFixed)
cSection.Item("WordWrap") = CBool(.WordWrap)
End With
m_cINI.Remove cSection.Key
m_cINI.AddSection cSection.Key, cSection
On Error GoTo 0
Exit Sub
SaveGeneral_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure SaveGeneral of Class
Module clsFlexSettings", vbCritical
End Sub
'---------------------------------------------------------------------------------------
' Procedure : LoadLayout
' DateTime : 4-7-2004 00:09
' Author : Flyguy
' Purpose :
'---------------------------------------------------------------------------------------
'
Private Sub LoadLayout()
Dim cSection As clsSection
Dim sData As String, aData() As String
Dim i As Long
On Error GoTo LoadLayout_Error
Set cSection = m_cINI.Section("Layout")
With m_FG
.Cols = CLng(cSection.Value("Cols", CLng(.Cols)))
.Rows = CLng(cSection.Value("Rows", CLng(.Rows)))
.FixedCols = CLng(cSection.Value("FixedCols", CLng(.FixedCols)))
.FixedRows = CLng(cSection.Value("FixedRows", CLng(.FixedRows)))
.LeftCol = CLng(cSection.Value("LeftCol", CLng(.LeftCol)))
.TopRow = CLng(cSection.Value("TopRow", CLng(.TopRow)))
sData = cSection.Value("ColAlignment", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
If Len(aData(i)) > 0 And i < .Cols Then .ColAlignment(i) = CInt(aData(i))
Next i
End If
sData = cSection.Value("ColWidth", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
If Len(aData(i)) > 0 And i < .Cols Then .ColWidth(i) = CLng(aData(i))
Next i
End If
sData = cSection.Value("ColData", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 31 of 44

For i = 0 To UBound(aData)
If Len(aData(i)) > 0 And i < .Cols Then .ColData(i) = CLng(aData(i))
Next i
End If
sData = cSection.Value("RowData", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
If Len(aData(i)) > 0 And i < .Rows Then .RowData(i) = CLng(aData(i))
Next i
End If
sData = cSection.Value("RowHeight", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
If Len(aData(i)) > 0 And i < .Rows Then .RowHeight(i) = CLng(aData(i))
Next i
End If
End With
On Error GoTo 0
Exit Sub
LoadLayout_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure LoadLayout of Class
Module clsFlexSettings", vbCritical
End Sub
'---------------------------------------------------------------------------------------
' Procedure : SaveLayout
' DateTime : 4-7-2004 00:09
' Author : Flyguy
' Purpose :
'---------------------------------------------------------------------------------------
'
Private Sub SaveLayout()
Dim cSection As clsSection
Dim sData() As String, aData() As String
Dim i As Long
On Error GoTo SaveLayout_Error
Set cSection = New clsSection
cSection.Key = "layout"
With m_FG
cSection.Item("Cols") = CLng(.Cols)
cSection.Item("Rows") = CLng(.Rows)
cSection.Item("FixedCols") = CLng(.FixedCols)
cSection.Item("FixedRows") = CLng(.FixedRows)
cSection.Item("LeftCol") = CLng(.LeftCol)
cSection.Item("TopRow") = CLng(.TopRow)
ReDim sData(2)
For i = 0 To .Cols - 1
sData(0) = sData(0) & vbTab & CStr(.ColAlignment(i))
sData(1) = sData(1) & vbTab & CStr(.ColWidth(i))
sData(2) = sData(2) & vbTab & CStr(.ColData(i))
'.ColPosition
Next i
cSection.Item("ColAlignment") = Mid$(sData(0), 2)
cSection.Item("ColWidth") = Mid$(sData(1), 2)
cSection.Item("ColData") = Mid$(sData(2), 2)
ReDim sData(1)
For i = 0 To .Rows - 1
sData(0) = sData(0) & vbTab & CStr(.RowData(i))
sData(1) = sData(1) & vbTab & CStr(.RowHeight(i))
'.RowPosition
Next i
cSection.Item("RowData") = Mid$(sData(0), 2)
cSection.Item("RowHeight") = Mid$(sData(1), 2)
End With
m_cINI.Remove cSection.Key
m_cINI.AddSection cSection.Key, cSection
On Error GoTo 0
Exit Sub
SaveLayout_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure SaveLayout of Class
Module clsFlexSettings", vbCritical
End Sub
Private Sub LoadCellLayout()
Dim i As Long

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 32 of 44

Dim lRow As Long, lCol As Long


Dim aData() As String, sData As String
Dim aXYD() As String
Dim cSection As clsSection
On Error GoTo LoadCellLayout_Error
Set cSection = m_cINI.Section("CellLayout")
With m_FG
sData = cSection.Value("Alignment", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
aXYD = Split(aData(i), ":")
.Row = CLng(aXYD(0))
.Col = CLng(aXYD(1))
.CellAlignment = CInt(aXYD(2))
Next i
End If
sData = cSection.Value("BackColor", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
aXYD = Split(aData(i), ":")
.Row = CLng(aXYD(0))
.Col = CLng(aXYD(1))
.CellBackColor = CLng(aXYD(2))
Next i
End If
sData = cSection.Value("FontBold", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
aXYD = Split(aData(i), ":")
.Row = CLng(aXYD(0))
.Col = CLng(aXYD(1))
.CellFontBold = CBool(aXYD(2))
Next i
End If
sData = cSection.Value("FontItalic", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
aXYD = Split(aData(i), ":")
.Row = CLng(aXYD(0))
.Col = CLng(aXYD(1))
.CellFontItalic = CBool(aXYD(2))
Next i
End If
sData = cSection.Value("FontName", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
aXYD = Split(aData(i), ":")
.Row = CLng(aXYD(0))
.Col = CLng(aXYD(1))
.CellFontName = aXYD(2)
Next i
End If
sData = cSection.Value("FontSize", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
aXYD = Split(aData(i), ":")
.Row = CLng(aXYD(0))
.Col = CLng(aXYD(1))
.CellFontSize = CLng(aXYD(2))
Next i
End If
sData = cSection.Value("ForeColor", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
aXYD = Split(aData(i), ":")
.Row = CLng(aXYD(0))
.Col = CLng(aXYD(1))
.CellForeColor = CLng(aXYD(2))

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 33 of 44

Next i
End If
sData = cSection.Value("TextStyle", "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
For i = 0 To UBound(aData)
aXYD = Split(aData(i), ":")
.Row = CLng(aXYD(0))
.Col = CLng(aXYD(1))
.CellTextStyle = CInt(aXYD(2))
Next i
End If
End With
On Error GoTo 0
Exit Sub
LoadCellLayout_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure LoadCellLayout of
Class Module clsFlexSettings", vbCritical
End Sub
Private Sub SaveCellLayout()
Dim lCol As Long, lRow As Long
Dim xx As tpCELL
Dim cSection As clsSection
On Error GoTo SaveCellLayout_Error
With m_FG
For lRow = 0 To .Rows - 1
.Row = lRow
For lCol = 0 To .Cols - 1
.Col = lCol
If .CellAlignment <> 0 Then xx.Alignment = xx.Alignment & vbTab & lRow & ":" & lCol & ":" & CStr(.CellAlignment)
If .CellBackColor <> 0 And .BackColor <> .CellBackColor Then xx.BackColor = xx.BackColor & vbTab & lRow & ":" & lCol & ":" & CStr(.CellBackColor)
If .CellForeColor <> 0 And .ForeColor <> .CellForeColor Then xx.ForeColor = xx.ForeColor & vbTab & lRow & ":" & lCol & ":" & CStr(.CellForeColor)
If .CellFontBold <> .Font.Bold Then xx.FontBold = xx.FontBold & vbTab & lRow & ":" & lCol & ":" & CStr(.CellFontBold)
If .CellFontItalic <> .Font.Italic Then xx.FontItalic = xx.FontItalic & vbTab & lRow & ":" & lCol & ":" & CStr(.CellFontItalic)
If .CellFontName <> .Font.Name Then xx.FontName = xx.FontName & vbTab & lRow & ":" & lCol & ":" & CStr(.CellFontName)
If .CellFontSize <> .Font.Size Then xx.FontSize = xx.FontSize & vbTab & lRow & ":" & lCol & ":" & CStr(.CellFontSize)
If .CellTextStyle <> .TextStyle Then xx.TextStyle = xx.TextStyle & vbTab & lRow & ":" & lCol & ":" & CStr(.CellTextStyle)
Next lCol
Next lRow
End With
Set cSection = New clsSection
cSection.Key = "CellLayout"
cSection.Item("Alignment") = Mid$(xx.Alignment, 2)
cSection.Item("BackColor") = Mid$(xx.BackColor, 2)
cSection.Item("FontBold") = Mid$(xx.FontBold, 2)
cSection.Item("FontItalic") = Mid$(xx.FontItalic, 2)
cSection.Item("FontName") = Mid$(xx.FontName, 2)
cSection.Item("FontSize") = Mid$(xx.FontSize, 2)
cSection.Item("ForeColor") = Mid$(xx.ForeColor, 2)
cSection.Item("TextStyle") = Mid$(xx.TextStyle, 2)
m_cINI.Remove cSection.Key
m_cINI.AddSection cSection.Key, cSection
On Error GoTo 0
Exit Sub
SaveCellLayout_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure SaveCellLayout of
Class Module clsFlexSettings", vbCritical
End Sub
Private Function LoadData() As Boolean
Dim cSection As clsSection
Dim lRows As Long, lCols As Long
Dim lRow As Long, lCol As Long
Dim aData() As String, sData As String
On Error GoTo LoadData_Error
Set cSection = m_cINI.Section("Data")
lRows = CLng(cSection.Value("rows", "-1"))
lCols = CLng(cSection.Value("cols", "-1"))
If lCols = -1 Or lRows = -1 Then Exit Function
For lRow = 0 To lRows - 1
sData = cSection.Value("row:" & lRow, "")
If Len(sData) > 0 Then
aData = Split(sData, vbTab)
If UBound(aData) + 1 = lCols Then
For lCol = 0 To UBound(aData)
m_FG.TextMatrix(lRow, lCol) = aData(lCol)

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 34 of 44

Next lCol
End If
End If
Next lRow
LoadData = True
On Error GoTo 0
Exit Function
LoadData_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure LoadData of Class
Module clsFlexSettings", vbCritical
End Function
Private Function SaveData() As Boolean
Dim lRow As Long, lCol As Long
Dim cSection As clsSection
Dim sData As String
On Error GoTo SaveData_Error
Set cSection = New clsSection
cSection.Key = "Data"
cSection.Item("rows") = CStr(m_FG.Rows)
cSection.Item("cols") = CStr(m_FG.Cols)
With m_FG
For lRow = 0 To .Rows - 1
sData = ""
For lCol = 0 To .Cols - 1
sData = sData & vbTab & .TextMatrix(lRow, lCol)
Next lCol
cSection.Item("row:" & lRow) = Mid$(sData, 2)
Next lRow
End With
m_cINI.Remove cSection.Key
m_cINI.AddSection cSection.Key, cSection
SaveData = True
On Error GoTo 0
Exit Function
SaveData_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & vbLf & "On line: " & Erl & vbLf & "in procedure SaveData of Class
Module clsFlexSettings", vbCritical
End Function
Private Sub Class_Terminate()
Set m_FG = Nothing
Set m_cINI = Nothing
End Sub

Class Section:

'---------------------------------------------------------------------------------------
' Module : clsSection
' DateTime : 22-8-2003 09:49
' Author : Flyguy
' Purpose : To manipulate section within a INI file
'---------------------------------------------------------------------------------------
Option Explicit
Private m_sKey As String
Private m_cValues As Collection
Private m_cValueKeys As Collection
Public Property Let Key(sNewValue As String)
m_sKey = sNewValue
End Property
Public Property Get Key() As String
Key = m_sKey
End Property
Public Function Add(sKey As String, sValue As String) As Boolean
If Len(sKey) > 0 Then
' If replacing then first remove
Remove sKey
' Add the actual data
m_cValueKeys.Add sKey, sKey
m_cValues.Add sValue, sKey
Add = True
End If
End Function
Public Function Count() As Long
Count = m_cValueKeys.Count
End Function

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 35 of 44

Public Function DataLine(vntIndex As Variant) As String


DataLine = m_cValueKeys(vntIndex) & "=" & m_cValues(vntIndex)
End Function
Public Function Exists(sKey As String)
Dim i As Long
If Len(Trim$(sKey)) = 0 Then Exit Function
For i = 1 To m_cValueKeys.Count
If LCase$(sKey) = LCase$(m_cValueKeys(i)) Then
Exists = True
Exit For
End If
Next i
End Function
Public Function Remove(sKey As String)
If Exists(sKey) Then
m_cValueKeys.Remove sKey
m_cValues.Remove sKey
End If
End Function
Public Function Clear()
Set m_cValues = New Collection
Set m_cValueKeys = New Collection
End Function
Public Property Let Item(sKey As String, sValue As String)
If Exists(sKey) Then
m_cValueKeys.Remove sKey
m_cValues.Remove sKey
End If
m_cValues.Add sValue, sKey
m_cValueKeys.Add sKey, sKey
End Property
Public Property Get Item(sKey As String) As String
If Exists(sKey) Then Item = m_cValues(sKey)
End Property
Public Function ItemKeys() As String()
Dim i As Long
Dim aTemp() As String
If m_cValueKeys.Count > 0 Then
ReDim aTemp(m_cValueKeys.Count - 1)
For i = 1 To m_cValueKeys.Count
aTemp(i - 1) = m_cValueKeys(i)
Next i
End If
ItemKeys = aTemp
End Function
Public Function Value(sKey As String, Optional sDefault As String = "") As String
If Exists(sKey) Then
Value = m_cValues(sKey)
Else
Value = sDefault
End If
End Function
Private Sub Class_Initialize()
Set m_cValues = New Collection
Set m_cValueKeys = New Collection
End Sub
Private Sub Class_Terminate()
Set m_cValues = Nothing
Set m_cValueKeys = Nothing
End Sub

Sử dụng MSFlexGrid như control Calendar:

'---------------------------------------------------------------------------------------
' Module : Form1
' DateTime : 11-7-2004 00:28
' Author : Flyguy
' Purpose : Sample using FlexGrid as Month Calendar
'---------------------------------------------------------------------------------------
Option Explicit
Private m_lDate As Long ' The date we are working on
Private Sub Form_Load()
m_lDate = Date
DrawGrid m_lDate

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 36 of 44

End Sub
Private Sub Command1_Click()
m_lDate = DateAdd("m", -1, m_lDate)
DrawGrid m_lDate
End Sub
Private Sub Command2_Click()
m_lDate = DateAdd("m", 1, m_lDate)
DrawGrid m_lDate
End Sub
Private Sub Form_Resize()
' I really don't care about errors when resizing
On Error Resume Next
Command2.Left = Me.ScaleWidth - Command1.Left - Command2.Width
With MSFlexGrid1
.Left = Command1.Left
.Top = 2 * Command1.Top + Command2.Height
.Move .Left, .Top, Me.ScaleWidth - 2 * .Left, Me.ScaleHeight - .Top - .Left
End With
' Also update the grid interior
SizeGrid
End Sub
'---------------------------------------------------------------------------------------
' Procedure : MSFlexGrid1_DblClick
' DateTime : 10-7-2004 23:55
' Author : Flyguy
' Purpose : To enter some data in the clicked cell
'---------------------------------------------------------------------------------------
'
Private Sub MSFlexGrid1_DblClick()
Dim lRow As Long
Dim lCol As Long
Dim sText As String
With MSFlexGrid1
lRow = .MouseRow
lCol = .MouseCol
If lRow / 2 = lRow \ 2 Then lRow = lRow + 1
sText = InputBox(.TextMatrix(lRow - 1, lCol), , .TextMatrix(lRow, lCol))
If StrPtr(sText) <> 0 Then .TextMatrix(lRow, lCol) = sText
End With
End Sub
Private Sub MSFlexGrid1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
SetCellFocus
End Sub
Private Sub MSFlexGrid1_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
If Button = vbLeftButton Then SetCellFocus
End Sub
'---------------------------------------------------------------------------------------
' Procedure : DrawGrid
' DateTime : 11-7-2004 00:23
' Author : Flyguy
' Purpose : Draw the calendar for the given month
'---------------------------------------------------------------------------------------
'
Private Sub DrawGrid(ByVal theDate As Long)
Dim lFirstDate As Long
Dim lLastDate As Long
Dim lFirstCol As Long
Dim lCol As Long, lRow As Long, lRows As Long
Dim lDate As Long
Me.Caption = Format(theDate, "mmmm yyyy")
' Get the 1st and last day of the month
lFirstDate = DateSerial(Year(theDate), Month(theDate), 1)
lLastDate = DateSerial(Year(theDate), Month(theDate) + 1, 1) - 1
' The starting column
lFirstCol = Weekday(lFirstDate, vbUseSystemDayOfWeek) - 1
' Determine the number of weeks
lRows = DateDiff("ww", lFirstDate, lLastDate, vbUseSystemDayOfWeek) + 1
With MSFlexGrid1
' No borders etc to autosize nicely
.BorderStyle = flexBorderNone
.Appearance = flexFlat
.ScrollBars = flexScrollBarNone
' Just some color settings
.GridColor = vb3DFace
.BackColor = .GridColor

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 37 of 44

' No highlighting
.HighLight = flexHighlightNever
.FocusRect = flexFocusLight
' Enable texts to span multiple lines
.WordWrap = True
' Number of days in a week ;)
.Cols = 7
' For the date header
.Rows = lRows * 2
.Clear
lRow = 0
lCol = lFirstCol - 1
For lDate = lFirstDate To lLastDate
' Column and Row counters
lCol = lCol + 1
If lCol > 6 Then
lRow = lRow + 2
lCol = 0
End If
' Format the date header of the cell
.Col = lCol
.Row = lRow
.TextMatrix(lRow, lCol) = FormatDateTime(lDate, vbShortDate)
.CellAlignment = flexAlignRightTop
' Different color for weekend days
If Weekday(lDate, vbMonday) > 5 Then
.CellBackColor = RGB(239, 239, 239)
Else
.CellBackColor = vbWhite
End If
' Make it yellow when today
If lDate = Date Then .CellBackColor = vbYellow
' Format the data cell
.Row = lRow + 1
.CellBackColor = vbWhite
.CellAlignment = flexAlignLeftTop
.CellFontBold = True
' Different color for weekend days
If Weekday(lDate, vbMonday) > 5 Then
.CellBackColor = RGB(239, 239, 239)
Else
.CellBackColor = vbWhite
End If
' Make it yellow when today
If lDate = Date Then .CellBackColor = vbInfoBackground
Next lDate
' No fixed columns/rows
.FixedRows = 0
.FixedCols = 0
' Set the initial focus
.Col = lFirstCol
.Row = 1
SizeGrid
.Redraw = True
End With
End Sub
'---------------------------------------------------------------------------------------
' Procedure : SizeGrid
' DateTime : 11-7-2004 00:23
' Author : Flyguy
' Purpose : Resize the cells when the grid is resized
'---------------------------------------------------------------------------------------
'
Private Sub SizeGrid()
Dim lRowHeight As Long
Dim lRow As Long
' Don't care about resize errors
On Error Resume Next
With MSFlexGrid1
.Redraw = False
' Set the width of all columns
.ColWidth(-1) = Int(.Width / .Cols)
' Correct the width of last column
.ColWidth(.Cols - 1) = .ColWidth(.Cols - 1) + (.Width - .Cols * .ColWidth(.Cols - 1))
' Calculate the height of the data cells

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 38 of 44

lRowHeight = (.Height - (.Rows / 2) * .RowHeight(0)) / (.Rows / 2)


' Set the height of the data cells
For lRow = 1 To .Rows - 1 Step 2
.RowHeight(lRow) = lRowHeight
Next lRow
.Redraw = True
End With
End Sub
'---------------------------------------------------------------------------------------
' Procedure : SetCellFocus
' DateTime : 10-7-2004 23:56
' Author : Flyguy
' Purpose : Make sure to set the focus to the data part
'---------------------------------------------------------------------------------------
'
Private Sub SetCellFocus()
Dim lRow As Long
Dim lCol As Long
With MSFlexGrid1
lRow = .MouseRow
lCol = .MouseCol
If lRow >= 0 And lCol >= 0 Then
If lRow / 2 = lRow \ 2 Then lRow = lRow + 1
.Row = lRow
.Col = lCol
End If
End With
End Sub

Sử dụng phương thức FillStyle bạn có thể thay đổi các ô của một vùng với chỉ một câu lệnh, nhưng chúng ta luôn phải xem xét đến hàng đang được chọn (current selected row), thuộc tính cột (col), thuộc tính rowsel, và thuộc tính colsel. Chính vì vậy mà
Flyguy viết một hàm để làm điều này:

Option Explicit
Private Enum FGCellStyle
fgcsBackColor = 1
fgcsForeColor = 2
fgcsText = 3
fgcsTextStyle = 4
fgcsFontName = 5
fgcsFontBold = 6
fgcsFontItalic = 7
fgcsAllignment = 8
End Enum
Private Sub Form_Load()
With MSFlexGrid1
.Cols = 10
.Rows = 10
End With
FG_Cell MSFlexGrid1, fgcsBackColor, 1, 1, 7, 7, RGB(191, 191, 255)
FG_Cell MSFlexGrid1, fgcsBackColor, 3, 2, 7, 5, vbGreen
FG_Cell MSFlexGrid1, fgcsForeColor, 1, 4, 3, 6, vbRed
FG_Cell MSFlexGrid1, fgcsText, 1, 1, 5, 5, "Hello"
FG_Cell MSFlexGrid1, fgcsFontBold, 2, 3, 5, 6, True
FG_Cell MSFlexGrid1, fgcsAllignment, 2, 4, 3, 4, flexAlignRightCenter
FG_Cell MSFlexGrid1, fgcsFontName, 1, 3, 2, 5, "Arial"
FG_Cell MSFlexGrid1, fgcsTextStyle, 1, 1, 3, 3, flexTextRaised
End Sub
Private Sub FG_Cell(FG As MSFlexGrid, ByVal What As FGCellStyle, Row1 As Long, Col1 As Long, Row2 As Long, Col2 As Long, Value As Variant)
Dim PrevRowCol(3) As Long ' to store the actual settings
Dim PrevFillStyle As Integer ' to store the actual settings
With FG
.Redraw = False
' Store current settings
PrevRowCol(0) = .Row
PrevRowCol(1) = .Col
PrevRowCol(2) = .RowSel
PrevRowCol(3) = .ColSel
PrevFillStyle = .FillStyle
' Set the range
.FillStyle = flexFillRepeat
.Row = Row1
.Col = Col1
.RowSel = Row2
.ColSel = Col2

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 39 of 44

' Apply changes


Select Case What
Case fgcsBackColor
.CellBackColor = Value
Case fgcsForeColor
.CellForeColor = Value
Case fgcsText
.Text = Value
Case fgcsTextStyle
.CellTextStyle = Value
Case fgcsFontName
.CellFontName = Value
Case fgcsFontBold
.CellFontBold = Value
Case fgcsFontItalic
.CellFontItalic = Value
Case fgcsAllignment
.CellAlignment = Value
End Select
' Restore settings
.FillStyle = PrevFillStyle
.Row = PrevRowCol(0)
.Col = PrevRowCol(1)
.RowSel = PrevRowCol(2)
.ColSel = PrevRowCol(3)
.Redraw = True
End With
End Sub

Cập nhật hàm CompareValues cho account Numeric/Và giá trị ngày (Date values):

'---------------------------------------------------------------------------------------
Private Function CompareValues(ByRef sArray() As String, lIndex1 As Long, lIndex2 As Long, lNofColumns As Long, aColumns() As Long, aOrder() As Long)
Dim i As Long
Dim lCol As Long
Dim sValue1 As String, sValue2 As String
Dim dValue1 As Double, dValue2 As Double
Dim bNumeric As Boolean
For i = 1 To lNofColumns
lCol = aColumns(i)
If aOrder(i) = 1 Then
sValue1 = sArray(lIndex1, lCol)
sValue2 = sArray(lIndex2, lCol)
Else
sValue1 = sArray(lIndex2, lCol)
sValue2 = sArray(lIndex1, lCol)
End If
If IsDate(sValue1) And IsDate(sValue2) Then
dValue1 = CDate(sValue1)
dValue2 = CDate(sValue2)
bNumeric = True
ElseIf IsNumeric(sValue1) And IsNumeric(sValue2) Then
dValue1 = CDbl(sValue1)
dValue2 = CDbl(sValue2)
bNumeric = True
Else
bNumeric = False
End If
If bNumeric Then
If dValue1 < dValue2 Then
Exit For
ElseIf dValue1 > dValue2 Then
CompareValues = True
Exit For
End If
Else
If sValue1 < sValue2 Then
Exit For
ElseIf sValue1 > sValue2 Then
CompareValues = True
Exit For
End If
End If
Next i

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 40 of 44

End Function

Tạo bảng HTML từ MSFlexGrid :

'---------------------------
' Module : modFlexHTML
' DateTime : 7-4-2005
' Author : ComponentOne, adapted by Flyguy to be used with MSFlexGrid
' Purpose : Exporting MSFlexGrid to HTML
'---------------------------
Option Explicit

Private Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long

Private Const EXTRAWIDTH As Double = 1.2

'---------------------------
' Procedure : HTMLColor
' DateTime : 30-1-2004
' Author : ComponentOne
' Purpose : converts a VB color into HTML color code
'---------------------------
Private Function HTMLColor(ByVal lColor As Long) As String
Dim sTemp As String

' convert to hex


sTemp = Hex$(lColor)

' handle system colors


If Len(sTemp) > 6 Then
If Left$(sTemp, 1) = "8" Then
lColor = Val("&H" & Mid$(sTemp, 2))
lColor = GetSysColor(lColor)
sTemp = Hex$(lColor)
End If
End If

' build format

Xuất sang Excel dùng Automation:

'---------------------------------------------------------------------------------------
' Module : modFlexExcel
' DateTime : 6-7-2005
' Author : ArnoutV
' Purpose :
'---------------------------------------------------------------------------------------
Option Explicit
Private Declare Function OleTranslateColor Lib "OLEPRO32.DLL" (ByVal OLE_COLOR As Long, ByVal HPALETTE As Long, pcColorRef As Long) As Long
Public Sub Grid2Excel(myGrid As MSFlexGrid, sSheetName As String, Optional bCellLayout As Boolean = False, Optional bAutoSize As Boolean = False)
Dim xlApp As Excel.Application
Dim xw As Excel.Workbook
Dim iOrgSheets As Integer
Dim lColors() As Long, i As Long
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
Select Case Err.Number
Case 0
Case 429
On Error GoTo Grid2Excel_Error
Set xlApp = CreateObject("Excel.Application")
Case Else
GoTo Grid2Excel_Error
End Select
On Error GoTo Grid2Excel_Error
iOrgSheets = xlApp.SheetsInNewWorkbook
xlApp.SheetsInNewWorkbook = 1
'<< 7/3/2006, AdV, Bugfix Excel 95, 97
' http://support.microsoft.com/default.aspx?scid=kb;en-us;Q165435
On Error Resume Next
xlApp.DisplayAlerts = False
On Error GoTo Grid2Excel_Error
'>>

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 41 of 44

Set xw = xlApp.Workbooks.Add
xlApp.Visible = False
xlApp.ScreenUpdating = False
''''''''''''''''''''''''''''''''
' Excel colors
lColors = GetGridColors(myGrid)
For i = 0 To UBound(lColors)
xw.Colors(i + 1) = lColors(i)
Next i
Sheet2Excel xw.Worksheets(1), myGrid, sSheetName, bCellLayout, bAutoSize
' Restore settings
xlApp.SheetsInNewWorkbook = iOrgSheets
xlApp.ScreenUpdating = True
If Not xlApp.Visible Then xlApp.Visible = True
'<< 7/3/2006, AdV, Bugfix Excel 95, 97
On Error Resume Next
xlApp.DisplayAlerts = True
On Error GoTo Grid2Excel_Error
'>>
GoTo Grid2Excel_Finish
Grid2Excel_Error:
MsgBox "Error: " & Err.Number & " on line: " & Erl & vbLf & "Description: " & Err.Description & vbLf & "in procedure Grid2Excel of Form frmResults", vbCritical
Grid2Excel_Finish:
On Error Resume Next
Set xw = Nothing
Set xlApp = Nothing
On Error GoTo 0
End Sub
'---------------------------------------------------------------------------------------
' Procedure : Sheet2Excel
' DateTime : 6-7-2005
' Author : ArnoutV
' Purpose :
'---------------------------------------------------------------------------------------
Public Function Sheet2Excel(ExcelSheet As Excel.Worksheet, myFG As MSFlexGrid, sSheetName As String, bCellLayout As Boolean, bAutoSize As Boolean) As Boolean
Dim lRowIndex As Long, lColIndex As Long, lRow As Long, lCol As Long
Dim nofCols As Long, nofRows As Long
Dim nofFixedCols As Integer, nofFixedRows As Integer
Dim aTemp() As Variant
Dim lNofHiddenCols As Long, lNofHiddenRows As Long
Dim lNofHiddenRowsF As Long, lNofHiddenColsF As Long
Dim lBackColor As Long, lForeColor As Long
With ExcelSheet
DoEvents
If Len(sSheetName) > 0 Then
On Error Resume Next
.Name = ProperSheetName(sSheetName)
End If
End With
On Error GoTo Sheet2Excel_Error
With myFG
lNofHiddenCols = 0
For lColIndex = 0 To .Cols - 1
If .ColWidth(lColIndex) = 0 Then
If lColIndex < .FixedCols Then lNofHiddenColsF = lNofHiddenColsF + 1
lNofHiddenCols = lNofHiddenCols + 1
End If
Next lColIndex
End With
With myFG
lNofHiddenRows = 0
For lRowIndex = 0 To .Rows - 1
If .RowHeight(lRowIndex) = 0 Then
If lRowIndex < .FixedRows Then lNofHiddenRowsF = lNofHiddenRowsF + 1
lNofHiddenRows = lNofHiddenRows + 1
End If
Next lRowIndex
End With
nofCols = myFG.Cols - myFG.FixedCols - (lNofHiddenCols - lNofHiddenColsF)
nofRows = myFG.Rows - myFG.FixedRows - (lNofHiddenRows - lNofHiddenRowsF)
nofFixedCols = myFG.FixedCols - lNofHiddenColsF
nofFixedRows = myFG.FixedRows - lNofHiddenRowsF
If nofCols + nofFixedCols >= 255 Then
MsgBox "Sheet2Excel: " & nofFixedCols + nofCols & " columns specified." & vbCrLf & "The maximum number of colums Excel can handle is 255", vbExclamation
Exit Function

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 42 of 44

End If
With ExcelSheet
With myFG
ReDim aTemp(.Rows - 1 - lNofHiddenRows, .Cols - 1 - lNofHiddenCols)
lRowIndex = 0
For lRow = 0 To .Rows - 1
If .RowHeight(lRow) > 0 Then
lColIndex = 0
For lCol = 0 To .Cols - 1
If .ColWidth(lCol) > 0 Then
If IsNumber(.TextMatrix(lRow, lCol)) Then
aTemp(lRowIndex, lColIndex) = CDbl(.TextMatrix(lRow, lCol))
ElseIf IsDate(.TextMatrix(lRow, lCol)) Then
aTemp(lRowIndex, lColIndex) = CDate(.TextMatrix(lRow, lCol))
Else
aTemp(lRowIndex, lColIndex) = "'" & .TextMatrix(lRow, lCol)
End If
lColIndex = lColIndex + 1
End If
Next lCol
lRowIndex = lRowIndex + 1
End If
Next lRow
End With
lRowIndex = 1
lColIndex = 1
' Put the grid data in the excel sheet
.Range(.Cells(lRowIndex, lColIndex), .Cells(UBound(aTemp, 1) + lRowIndex, UBound(aTemp, 2) + lColIndex)).Value = aTemp
If bCellLayout Then
''''''''''''''''''''''''''
' Font, colors
lRowIndex = 0
For lRow = 0 To myFG.Rows - 1
If myFG.RowHeight(lRow) > 0 Then
lColIndex = 0
For lCol = 0 To myFG.Cols - 1
If myFG.ColWidth(lCol) > 0 Then
myFG.Row = lRow
myFG.Col = lCol
lBackColor = -1
If lCol > myFG.FixedCols - 1 And lRow > myFG.FixedRows - 1 Then
lBackColor = myFG.CellBackColor
If lBackColor = 0 Or lBackColor = myFG.BackColor Then lBackColor = -1
Else
lBackColor = TranslateColor(myFG.BackColorFixed) ' RGB(223, 223, 223)
End If
lForeColor = -1
If myFG.CellForeColor > 0 Then lForeColor = myFG.CellForeColor
With .Range(.Cells(lRowIndex + 1, lColIndex + 1), .Cells(lRowIndex + 1, lColIndex + 1))
If lForeColor <> -1 Then .Font.Color = lForeColor
If lBackColor <> -1 Then .Interior.Color = lBackColor
.Font.Bold = myFG.CellFontBold
.Font.Name = myFG.CellFontName
.Font.Size = myFG.CellFontSize
End With
lColIndex = lColIndex + 1
End If
Next lCol
On Error GoTo Sheet2Excel_Error
lRowIndex = lRowIndex + 1
End If
Next lRow
''''''''''''''''''''''''''
' Merging of columns in fixed rows
lRowIndex = 0
For lRow = 0 To myFG.FixedRows - 1
If myFG.RowHeight(lRow) > 0 Then
lRowIndex = lRowIndex + 1
lColIndex = myFG.FixedCols
If myFG.MergeRow(lRow) Then
For lCol = myFG.FixedCols To myFG.Cols - 2
If myFG.ColWidth(lCol) > 0 Then
lColIndex = lColIndex + 1
If myFG.ColWidth(lCol + 1) > 0 Then
If myFG.TextMatrix(lRow, lCol) = myFG.TextMatrix(lRow, lCol + 1) Then

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 43 of 44

.Range(.Cells(lRowIndex, lColIndex), .Cells(lRowIndex, lColIndex + 1)).MergeCells = True


End If
End If
End If
Next lCol
End If
End If
Next lRow
''''''''''''''''''''''''''
' Merging of rows in de fixed columns
lColIndex = 0
For lCol = 0 To myFG.FixedCols - 1
If myFG.ColWidth(lCol) > 0 Then
lColIndex = lColIndex + 1
If myFG.MergeCol(lCol) Then
lRowIndex = myFG.FixedRows
For lRow = myFG.FixedRows To myFG.Rows - 2
If myFG.RowHeight(lRow) > 0 Then
lRowIndex = lRowIndex + 1
If myFG.RowHeight(lRow + 1) > 0 Then
If myFG.TextMatrix(lRow, lCol) = myFG.TextMatrix(lRow + 1, lCol) Then
.Range(.Cells(lRowIndex, lColIndex), .Cells(lRowIndex + 1, lColIndex)).MergeCells = True
.Range(.Cells(lRowIndex, lColIndex), .Cells(lRowIndex + 1, lColIndex)).VerticalAlignment = xlCenter
End If
End If
End If
Next lRow
End If
End If
Next lCol
If bAutoSize Then .Range(.Columns(1), .Columns(myFG.Cols - lNofHiddenCols)).EntireColumn.AutoFit
Else
If nofFixedCols > 0 And bAutoSize Then
.Range(.Columns(1), .Columns(nofFixedCols)).EntireColumn.AutoFit
End If
End If
End With
Sheet2Excel = True
On Error GoTo 0
Exit Function
Sheet2Excel_Error:
MsgBox "Error: " & Err.Number & " on line: " & Erl & vbLf & "Description: " & Err.Description & vbLf & "in procedure Sheet2Excel of Form modFlexExcel", vbCritical
On Error GoTo 0
End Function
'---------------------------------------------------------------------------------------
' Procedure : ProperSheetName
' DateTime : 6-7-2005
' Author : ArnoutV
' Purpose :
'---------------------------------------------------------------------------------------
Private Function ProperSheetName(ByVal sName As String) As String
' Remove invalid characters
ProperSheetName = Replace$(sName, "\", "")
ProperSheetName = Replace$(ProperSheetName, "/", "")
ProperSheetName = Replace$(ProperSheetName, "[", "")
ProperSheetName = Replace$(ProperSheetName, "]", "")
ProperSheetName = Replace$(ProperSheetName, "?", "")
ProperSheetName = Replace$(ProperSheetName, "*", "")
ProperSheetName = Replace$(ProperSheetName, ":", "")
ProperSheetName = Replace$(ProperSheetName, Chr$(34), "")
' Max of 31 characters
ProperSheetName = Left$(Trim$(ProperSheetName), 31)
End Function
Private Function GetGridColors(myGrid As MSFlexGrid) As Long()
Dim cColor As Collection, lColor As Long
Dim lRow As Long, lCol As Long
Dim lColors() As Long
Set cColor = New Collection
With myGrid
AddColor cColor, TranslateColor(.BackColor)
AddColor cColor, TranslateColor(.BackColorFixed)
AddColor cColor, TranslateColor(.ForeColor)
AddColor cColor, TranslateColor(.ForeColorFixed)
For lRow = .FixedRows To .Rows - 1
For lCol = .FixedCols To .Cols - 1

Flyguy
CÁC THỦ TỤC LIÊN QUAN ĐẾN FLEXGR Page 44 of 44

.Col = lCol
.Row = lRow
lColor = .CellForeColor
If lColor > 0 And lColor <> .ForeColor Then AddColor cColor, TranslateColor(lColor)
lColor = .CellBackColor
If lColor > 0 And lColor <> .BackColor Then AddColor cColor, TranslateColor(lColor)
Next lCol
Next lRow
End With
' Maximum of 56 unique colors in Excel
If cColor.Count > 56 Then ReDim lColors(55) Else ReDim lColors(cColor.Count - 1)
For lRow = 0 To UBound(lColors)
lColors(lRow) = cColor(lRow + 1)
Next lRow
GetGridColors = lColors
End Function
Private Function AddColor(cColor As Collection, lColor As Long)
On Error Resume Next
cColor.Add lColor, "key" & lColor
End Function
Private Function TranslateColor(ByVal lColor As Long, Optional hPal As Long = 0) As Long
' Convert Automation color to Windows color
If OleTranslateColor(lColor, hPal, TranslateColor) Then TranslateColor = lColor
End Function
Private Function IsNumber(ByVal sValue As String) As Boolean
Dim dValue As Double
On Error Resume Next
dValue = CDbl(sValue)
IsNumber = (Err.Number = 0)
End Function

Các bạn có thể tham khảo tại đây:

Flyguy

Вам также может понравиться