Attachment 195693Attachment 195694
The foreground color is blended very well. Could you also blend the background? Thank you so much!
Printable View
Attachment 195693Attachment 195694
The foreground color is blended very well. Could you also blend the background? Thank you so much!
How should that work / look like ?
The cells with values 99.97, 99.96, and 99.98 have been marked with a pink background, but when I select an area that includes these cells, I cannot distinguish which cells have been highlighted with a pink background.
Add the UseBackColorSel property. When set to False, the color of the selected cell will be a blend of BackColor and SelBackColor.
fengzhongxia,
you can achieve what you need by a "workaround".
Continue to use .UseForeColorSel = False and then apply a 4x4 pixel solid color picture to a cell and set the .CellPictureAlignment = FlexPictureAlignmentStretch for fast "fill" of the background.
The picture is then effectively over the selected back color. See below example of the purple picture with a cyan fore color. Beneath a cell with red fore color and no custom background.
Attachment 195695
Only problem is when you still need a real picture in that cell. But this could also be circumvented when using ColImageList..
This method you've mentioned meets my requirements perfectly. Thank you so much, expert!
Update released.
Just noticed that in vsFlexGrid the cell "flooding" is not the whole cell background like here but has a padding in the size of the focus rect.
So the original cell back color or selected back color is still visible.
I kinda like this more and updated it now. That's also how it works in Excel with the solid bars.
Attachment 195698
Thinks!Very Good!
Hello Krool!
Thank you very much for providing the great VBCCR control.
1. The VBFlexGrid.ColPosition property is currently 'write-only'. Could it be changed to 'read/write'?
2. Is it possible to drag columns to a specified position (like 'ListView' or 'VSFlexGrid', allowing columns to be dragged to a specific position)? This would be more convenient because sometimes users need to adjust columns to their preferred positions.
3. If I want to click a column header to sort the column data in ascending or descending order, how should I set it up?
I hope to get your help, thank you very much!
1. The .ColPosition is indeed write-only. Will check it, thanks. But what's the reason you need to read it ? It's the same value as you input as index ? The vsFlexGrid and MSFlexGrid also are write-only.
2. Use the .DragCol function. Below a snippet which allows to re-arrange columns and rows when you press the alt key and left mouse button.
3. Use also the BeforeMouseDown event and set the .ColSortArrow and .ColSort properties and then you may use .Sort = FlexSortUseColSort for individual column sortings. You will figure it out for sure.Code:Private Sub VBFlexGrid1_BeforeMouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single, Cancel As Boolean)
With VBFlexGrid1
If Button = vbLeftButton And (Shift And vbAltMask) = vbAltMask Then
.HitTest X, Y
If .HitResult = FlexHitResultCell Then
If .HitCol < .FixedCols And .HitRow >= .FixedRows Then
VBFlexGrid1.RowPosition(.HitRow) = VBFlexGrid1.DragRow(.HitRow)
Cancel = True
ElseIf .HitCol >= .FixedCols And .HitRow < .FixedRows Then
VBFlexGrid1.ColPosition(.HitCol) = VBFlexGrid1.DragCol(.HitCol)
Cancel = True
End If
End If
End If
End With
End Sub
You can also set .RowSortArrows if you have multiple fixed rows and want the sort arrows other than fixed row 0.
I want to say thank you to Krool because of this control (and the other ones), it is helping a lot in being able to program in VB6 in 2026.
All the new functions of this grid that allow editing are of great help.
VbFlexGrid supposrts CellOwnerDraw, like VBFlexGrid1.CellOwnerDraw(row, col) = True?
I asked CoPilot about the possibility of using different character styles in the same cell, as well as the possibility of using lowercase and uppercase letters, such as underlining or bold. CoPilot gave me this answer:
Excellent, Fabrizio — this is **your thing**: VB6, VBFlexGrid, owner-draw, total control of the cell.
I'll answer you in a **technical, empirical, and immediately operational** way, just the way you like it.
---
# ? How does `CellOwnerDraw(row, column) = True` work in VBFlexGrid
When you set:
```vb
VBFlexGrid1.CellOwnerDraw(row, column) = True
```
You're telling the control:
> "For this cell, **don't draw anything**.
> Call me in the `OwnerDrawCell` event and I'll do it."
This is a complete override of cell rendering.
---
# ? What you need to do after activating it
You need to handle the event:
```vb
Private Sub VBFlexGrid1_OwnerDrawCell(ByVal Row As Long, _
ByVal Col As Long, _
ByVal hDC As Long, _
ByVal Left As Long, _
ByVal Top As Long, _
ByVal Right As Long, _
ByVal Bottom As Long, _
ByVal DrawState As OwnerDrawStateConstants)
```
Here you have:
- the hDC to draw on
- the cell's rectangle
- the state (selected, focused, etc.)
And you can use any GDI API: `FillRect`, `TextOut`, `DrawText`, `BitBlt`, etc.
---
# ? Minimal and working example
Gray background and red text designs:
```vb
Private Sub VBFlexGrid1_OwnerDrawCell(Row As Long, Col As Long, _
hDC As Long, Left As Long, Top As Long, _
Right As Long, Bottom As Long, _
DrawState As OwnerDrawStateConstants)
Dim rc As RECT
rc.Left = Left
rc.Top = Top
rc.Right = Right
rc.Bottom = Bottom
' Background
FillRect hDC, rc, CreateSolidBrush(RGB(230, 230, 230))
' Text
SetTextColor hDC, RGB(200, 0, 0)
DrawText hDC, VBFlexGrid1.TextMatrix(Row, Col), -1, rc, DT_LEFT Or DT_VCENTER Or DT_SINGLELINE
End Sub
```
---
# ? Important Note
`CellOwnerDraw` must be set before the cell is drawn, so:
- in `Form_Load`
- or immediately after filling the grid
- or dynamically before a `Refresh`
---
# ? Want to do something more advanced?
I can help you:
- draw **icons** or **images** in the cell
- create **progress bars**, **badges**, **status indicators**
- manage **hover**, **selection**, **focus**
- implement **symmetric cell rendering** with centralized logic (in line with your style)
Tell me what you want to achieve and I'll prepare a clean, symmetric, and benchmark-safe code block.
That's all... CoPilot "guessed" that this was possible and pointed me to VbFlexGrid and the instructions on GitHub from Krool (!!!)
CoPilot evidently has a lot of imagination :D:D
Update released.
The drop-down calendar (FlexComboModeCalendar) will now resize upon WM_THEMECHANGED/WM_STYLECHANGED.
This allows to change theme/styles for the calendar on the EditSetupWindow event. (window created but not yet visible)
WM_THEMECHANGED for the obvious reason when someone dares to try to make a dark mode and needs the visual styles changed per code.
Or for the more common reason (WM_STYLECHANGED) when somebody needs to apply MCS_NOTODAY or so manually on the EditSetupWindow event.
Update released.
Usage of SetBkColor for the DrawFocusRect API so that it can work accurately.
This is especially visible when using dark mode colors. Just compare the focus rect below. Top is now after the update and bottom how it was before or is in a MSFlexGrid.
Attachment 196120
Dear Krol, an observation: By having the tabindex at 0 or another control (it can be commad Button, or another control) the DrawFocusRect property in the vbflexgrid disappears when the form is loaded..., however, componentone's FlexGrid does meet those characteristics.
Attachment 196173
When a form contains two tables, clicking the middle position between the two columns in the image causes the mouse cursor to jump immediately to the upper section.
When you click on the upper table, it scrolls up by a small amount; when you click on the lower table, it scrolls up by a large amount.
This issue does not occur when there is only one table in the form.
The problem disappears after setting the Windows display scale to 100%. How can I resolve this? Thank you very much!
VBFlexGridDemo
https://www.kdocs.cn/l/cdNXvTmjgRSE
Attachment 196185
This issue only occurs after moving the window to the position shown in the illustration and then clicking; it does not occur at the default window position.
When you include a new control "SplitContainer" you can not just blindly run the demo without checking the code.
For example. I changed "VBFlexGrid1" into "SplitContainer1" in the Form_Resize event and then the problems disappeared..
Code:Private Sub Form_Resize()
Dim Width As Single, Height As Single
Width = Me.ScaleWidth - SplitContainer1.Left - Me.ScaleX(8, vbPixels, Me.ScaleMode)
Height = Me.ScaleHeight - (PicturePanel.Height) - Me.ScaleY(8, vbPixels, Me.ScaleMode)
If Width > 0 Then SplitContainer1.Width = Width
If Height > 0 Then SplitContainer1.Height = Height
End Sub
Hi Krool, I need the old version of your VBFlexGrid.ctl user control because I’d like to release a portable version of the app I’m developing (a freeware interactive first-aid simulator). I’m unable to integrate the newer controls with DataBinding into the project. Where canJ find it? Thank in advance.
Thanks for your reply, sir. It should be an issue with the new control. I'll check it again.
Thanks Krool for your kind and prompt reply. I downloaded the set of files from GitHub and, after OLEGuids.tlb, integrated them into a new project in this order: 2 .bas > 2.cls > .CT; then saved and closed VB6. But if I try to launch the app, even without any VBgrid, or if I try to draw one on the form, I alwayes get an error at this point:
Private PropDataSource As MSDATASRC.DataSource, PropDataMember As MSDATASRC.DataMember, PropRecordset As Object
Asking the AI "WHY?", its answer is: to fix this issue use the oldest version, without DataBinding, of Krool User Control (I use the simplest functions of your grid).
Ok, you got an AI answer and that mislead me..
So, either make a reference to msdatsrc.tlb that is in C:\Windows\SysWOW64
Or set the compilation constant ImplementDataSource to False in the .ctl file.
Code:#Const ImplementDataSource = False ' True = Required: msdatsrc.tlb
Dear Krool,
I solved all problems doing with VB6.0 a new GRID User Control which meets my needs. It's light but enough powerfull for any simple app.
Thanks for you kindness and for your valuable contribution to community
Hello. I don't know if this issue was at some point mentioned, but the MSHFlexGrid, unlike the MSFlexGrid, doesn't fire the SelChange event when the Col and Row properties are changed programmatically. The event only fires with user interaction. VBFlexGrid goes back to MSFlexGrid behavior of firing the event.
The vsFlexGrid from ComponentOne also fires the SelChange event when changing Row/Col properties
Setting the .Row/.Col will fire the SelChange, but also the .Select method fires the SelChange event.
So I think the vbFlexGrid behaves like expected
The issue is that other components that need to access cell properties need to change the current cell to access them. And the client program can have code in the SelChange event. In the best case it causes only a performance issue, but in other cases it can make the program to behave wrongly, like it was a recent case where I had put in the event code this:
I forgot about that code, and after using that component (that is a FlexGrid exporter to Excel that I'll soon post in the Codebank) I saw that the cell format that I saw in Excel for that particular grid report (unlike other ones that were OK) was always of column 0. I didn't realize why until with further debugging I found that code in the SelChange event procesure.Code:HandleSelChange GridName
Private Sub HandleSelChange(nGrd As VBFlexGrid)
Static s As Boolean
If (Not s) And (nGrd.Row > 0) And (nGrd.MouseRow > 0) Then
s = True
nGrd.Row = nGrd.RowSel
nGrd.Col = 0
nGrd.ColSel = nGrd.Cols - 1
s = False
End If
End Sub
But it is already solved, not only in my client program where I've put a flag, but also in my exporter.
I attach the code that allows to suspend third party controls events here.
This was made by Claude AI with my help and assistance in testing things and copying to it the definitions it wanted from the VB6 Object Browser, and also pushing it a bit because at some point it had said "there is no way to do that" (it was to find some Event IDs from VB6 code). But I responded that "If TLBINF32.DLL can do that why we can't?". And it could...
About whether it is better to raise the events or not, I think both options have advantages and disadvantages, so I don't have an opinion.
OK, now I have an idea for you to consider: not to raise the SelChange event while Redraw is False.
When Redraws goes to False, the selection state is stored, and when it returns to True, the event is triggered if the selection has changed.
PS: just thinking how it could be best handled, not that I need that now.
Or a compatibility flag/ property
Looks like VBFlexGrid implements a Cell property similar to ComponentOne VSFlexGrid's Cell property. Should be able to use this to get/set Cell properties without changing the selection/raising the SelChange event.
For anyone used to the ComponentOne VSFlexGrid, I notice a difference in the Cell property behaviour - Krool's VBFlexGrid requires the FillStyle property to be set to FlexFillStyleRepeat in order to change the property of multiple cells in a range using the Cell property. VSFlexGrid does not require this (the FillStyle is ignored and the property change is always applied to all cells in the range). Not a big deal, just something to be aware of if switching from the VSFlexGrid to VBFlexGrid.
I meant "not a big deal" in the sense that there is a simple one-liner workaround, but if 100% compatibility (or near 100% compatibility) is a goal of this control, then yes, the behaviour should match. Pretty simple change if Krool's interested in matching VSFlexGrid behaviour (3 lines to save and restore the FillStyle property around the change operation):
The bigger issue (for me at least) preventing migration to VBFlexGrid is that there's no OwnerDraw property...I do a lot of custom drawing in my VSFlexGrid cells.Code:Public Property Let Cell(ByVal Setting As FlexCellSettings, Optional ByVal Row As Long = -1, Optional ByVal Col As Long = -1, Optional ByVal RowSel As Long = -1, Optional ByVal ColSel As Long = -1, ByVal Value As Variant)
If (Row < -1 Or Row > (PropRows - 1)) Or (Col < -1 Or Col > (PropCols - 1)) Or (RowSel < -1 Or RowSel > (PropRows - 1)) Or (ColSel < -1 Or ColSel > (PropCols - 1)) Then Err.Raise Number:=381, Description:="Subscript out of range"
Dim OldRow As Long, OldCol As Long, OldRowSel As Long, OldColSel As Long, OldNoRedraw As Boolean, OldFillStyle As FlexFillStyleConstants
OldRow = VBFlexGridRow
OldCol = VBFlexGridCol
OldRowSel = VBFlexGridRowSel
OldColSel = VBFlexGridColSel
OldNoRedraw = VBFlexGridNoRedraw
If Row > -1 Then VBFlexGridRow = Row
If Col > -1 Then VBFlexGridCol = Col
If RowSel > -1 Then VBFlexGridRowSel = RowSel Else VBFlexGridRowSel = VBFlexGridRow
If ColSel > -1 Then VBFlexGridColSel = ColSel Else VBFlexGridColSel = VBFlexGridCol
VBFlexGridNoRedraw = True
VBFlexGridIndirectCellRef.InProc = True
VBFlexGridIndirectCellRef.SetRCP = False
On Error GoTo Cancel
' Make sure we always perform operation across entire range of cells to match VSFlexGrid behaviour by forcing grid into FlexFilleStyleRepeatMode
OldFillStyle = PropFillStyle
PropFillStyle = FlexFillStyleRepeat
Select Case Setting
Case FlexCellText
Me.Text = Value
Case FlexCellClip
Me.Clip = Value
Case FlexCellTextStyle
Me.CellTextStyle = Value
Case FlexCellAlignment
Me.CellAlignment = Value
Case FlexCellPicture
Me.CellPicture = Value
Case FlexCellPictureAlignment
Me.CellPictureAlignment = Value
Case FlexCellBackColor
Me.CellBackColor = Value
Case FlexCellForeColor
Me.CellForeColor = Value
Case FlexCellToolTipText
Me.CellToolTipText = Value
Case FlexCellComboCue
Me.CellComboCue = Value
Case FlexCellChecked
Me.CellChecked = Value
Case FlexCellFloodPercent
Me.CellFloodPercent = Value
Case FlexCellFloodColor
Me.CellFloodColor = Value
Case FlexCellFontName
Me.CellFontName = Value
Case FlexCellFontSize
Me.CellFontSize = Value
Case FlexCellFontBold
Me.CellFontBold = Value
Case FlexCellFontItalic
Me.CellFontItalic = Value
Case FlexCellFontStrikeThrough
Me.CellFontStrikeThrough = Value
Case FlexCellFontUnderline
Me.CellFontUnderline = Value
Case FlexCellFontCharset
Me.CellFontCharset = Value
Case FlexCellLeft
Err.Raise Number:=383, Description:="Property is read-only"
Case FlexCellTop
Err.Raise Number:=383, Description:="Property is read-only"
Case FlexCellWidth
Err.Raise Number:=383, Description:="Property is read-only"
Case FlexCellHeight
Err.Raise Number:=383, Description:="Property is read-only"
Case FlexCellSort
Me.Sort = Value
Case FlexCellTextDisplay
Err.Raise Number:=383, Description:="Property is read-only"
Case FlexCellTextHidden
Err.Raise Number:=383, Description:="Property is read-only"
Case FlexCellHasCustomFormatting
Me.CellHasCustomFormatting = Value
Case FlexCellHasTag
Me.CellHasTag = Value
Case FlexCellTag
Me.CellTag = Value
Case Else
Err.Raise 380
End Select
Cancel:
PropFillStyle = OldFillStyle ' Restore FillStyle property to what it was before this method was called
VBFlexGridRow = OldRow
VBFlexGridCol = OldCol
VBFlexGridRowSel = OldRowSel
VBFlexGridColSel = OldColSel
VBFlexGridNoRedraw = OldNoRedraw
VBFlexGridIndirectCellRef.InProc = False
If Err.Number = 0 Then
If VBFlexGridIndirectCellRef.SetRCP = False Then
Call RedrawGrid
Else
Dim RCP As TROWCOLPARAMS
LSet RCP = VBFlexGridIndirectCellRef.RCP
VBFlexGridIndirectCellRef.SetRCP = False
Call SetRowColParams(RCP)
End If
Else
Err.Raise Number:=Err.Number, Description:=Err.Description
End If
End Property
It's not a goal to have 100% compatibility against vsFlexGrid. Sometimes I actively decided against being compatible. This is a lot of the time so for the in-built cell editing functionality.
It's just a nice to have. For the Cell property in question. I found it more logic to consider the FillStyle property as the Cell just simulates for a certain selection range. But I am open for discussion.
OwnerDraw for cells... What do you need to draw what cannot be drawn in-built ? In theory it shall be easy to provide such an event / property.
EDIT: After second thought it maybe makes sense to use FillStyle repeat for the Cell property. Because that's a good way to ignore settings and since when you don't need repeat, you just don't pass a sel range..
Update released.
The Cell property now overwrites the FillStyle property.
It's either FlexFillStyleRepeat for a selection or else FlexFillStyleSingle.
Included the SaveArray function to write data into a variant (UseColDataType = True) or else string (default) array.
It's significantly faster for an Excel export or copying into another VBFlexGrid control.
Included new enum FlexArrayOrderConstants which is either 0 - FlexRowMajor or 1 - FlexColumnMajor.
The SaveArray function defaults to FlexColumnMajor to be in sync with the LoadArray function.
Example for a fast excel export. (similar efficient as a .CopyFromRecordset into an Excel Worksheet)
When UseColDataType is False then Excel treats everything as strings and then dates are not interpreted as date but as text.
Example for a full copy into another VBFlexGrid control. (inclusive fixed cells which are excluded when omitting Row and Col)Code:With VBFlexGrid1
.ColDataType(0) = vbLong
.ColDataType(1) = vbDate
.ColDataType(2) = vbDouble
' and so on ...
WS.Cells(1, 1).Resize(.Rows, .Cols).Value = .SaveArray(FlexRowMajor, Row:=0, Col:=0, UseColDataType:=True)
End With
Code:VBFlexGrid2.LoadArray VBFlexGrid1.SaveArray(Row:=0, Col:=0), Row:=0, Col:=0
Updated released
Bugfix in the SaveArray function when ExcludeHidden is True.
Furthermore:
When type conversion failed (UseColDataType = True) the variant item is now 'Null'.
It keeps being 'Empty' when the cell is vbNullString to protect the type conversion from false error.
This enables to distinguish between "no value" and "error value" and is the most interoperable approach.
ADO data types are now recognized as well as these are compatible with the numbering to the intrinsic data types.
Update released.
Included the Row/ColPositionFromNonHidden and Row/ColNonHiddenPosition read-only property, which maps between real index and non-hidden mapped position.
Included Rows/ColsNonHidden read-only property.
This allows to conviently loop through all non-hidden columns.
Or another use-case is when looping through an array (for example .SaveArray with ExcludeHidden = True) and then accessing column properties based on the array index.Code:Dim i As Long
For i = 0 To VBFlexGrid1.ColsNonHidden - 1
Debug.Print VBFlexGrid1.ColPositionFromNonHidden(i)
Next i
Excel export sample included into the demo project.