Yes, this works. Thank you.
But this is not very convenient. From my point of view, the "ComboButtonValue = FlexComboButtonValuePressed" operator should automatically put the user into edit mode.
Printable View
Hi!
2 questions, just to see if i'm doing it wrong or fine xD
1.- Best way to know what column is sorted the grid?
Actually i'm doing:
And using the columnordered variable for something.Code:For I = 0 To vbGrid.Cols - 1
If vbGrid.ColSortArrow(I) <> FlexSortArrowNone Then
ColumnOrdered= I
Exit For
End If
Next I
It's ok? there is a better way ?
aaand
2.- the best way to control the columns?
i mean, for example in a combobox, i use .itemdata(x) to control the right index of the value.
in the Grid, actually i'm filling the columns statically: vbgrid.additem xx & vbtab & yy & vbtab & zz , etc...
Is there a way to tell the grid that column 1 is "date1", where date1 is a field of my recordset ?.
this will be perfect, because then i can insert a column in the middle of the grid, without changing all the additem.. and maybe i can use the grid without the textmatrix property ? something like : vbrid.colindex("date1"). row or something like that ?
Maybe what i'm looking for is the .colkey prop ?
Thanks in advance !
Thanks!
Krool,
why do you always check flags before changing them? These two program blocks are equal:
Code:If (.Fields(iCol).Attributes And &H20) = &H20 Then ' adFldIsNullable
If (VBFlexGridColsInfo(iCol + PropFixedCols).State And CLIS_NULLABLE) = 0 Then VBFlexGridColsInfo(iCol + PropFixedCols).State = VBFlexGridColsInfo(iCol + PropFixedCols).State Or CLIS_NULLABLE
Else
If (VBFlexGridColsInfo(iCol + PropFixedCols).State And CLIS_NULLABLE) = CLIS_NULLABLE Then VBFlexGridColsInfo(iCol + PropFixedCols).State = VBFlexGridColsInfo(iCol + PropFixedCols).State And Not CLIS_NULLABLE
End If
You do it everywhere.Code:If (.Fields(iCol).Attributes And &H20) = &H20 Then ' adFldIsNullable
VBFlexGridColsInfo(iCol + PropFixedCols).State = VBFlexGridColsInfo(iCol + PropFixedCols).State Or CLIS_NULLABLE
Else
VBFlexGridColsInfo(iCol + PropFixedCols).State = VBFlexGridColsInfo(iCol + PropFixedCols).State And Not CLIS_NULLABLE
End If
Wrong description for the ColFormat property: "Returns/sets the format used to display numeric values."
Why only numeric? This is an example of LCase formatting using the ColFormat property.
Code:VBFlexGrid1.ColFormat(1) = "<"
It seems that EditMaxLength property doesn't work. WinXP SP3.
Attachment 188100Code:Private Sub Command1_Click()
With VBFlexGrid1
.Text = ""
.EditMaxLength = 3
End With
End Sub
Am I understand right that if I want to limit the text length in all cells of a column, I need to get into the edit mode for each of them? Doesn't sound obvious. Can you change it?
From my poin of view, for the ComboButtonValue property it is better to StartEdit within the property sub.
For the EditMaxLength property (if you can't change it) the error message will be convenient.
I'm trying to create a full-fledget reference documentation for the VBFlexGrid. It will be ready in three month or so. I hope this will also solve some of the problems like that.
ColHidden. Readable edition.
Code:Public Property Let ColHidden(ByVal Index As Long, ByVal NeedToHide As Boolean)
If (Index > -1) And (Index < PropCols) Then
With VBFlexGridColsInfo(Index)
.State = IIf(NeedToHide, (.State Or CLIS_HIDDEN), (.State And Not CLIS_HIDDEN))
End With
ElseIf Index = -1 Then
Dim i As Long
For i = 0 To (PropCols - 1)
With VBFlexGridColsInfo(i)
.State = IIf(NeedToHide, (.State Or CLIS_HIDDEN), (.State And Not CLIS_HIDDEN))
End With
Next
Else
Err.Raise Number:=30010, Description:="Invalid Col value"
End If
If Not ((Index < VBFlexGridExtendLastCol) And (VBFlexGridExtendLastCol > -1)) Then
VBFlexGridExtendLastCol = GetExtendLastCol()
End If
Dim RCP As TROWCOLPARAMS
With RCP
.Mask = RCPM_LEFTCOL
.Flags = RCPF_CHECKLEFTCOL Or RCPF_SETSCROLLBARS Or RCPF_FORCEREDRAW
.LeftCol = VBFlexGridLeftCol
Call SetRowColParams(RCP)
End With
End Property
This means "hide all columns":
Code:VBFlexGrid1.ColHidden(-1) = True
Nouyana,
I appreciate your comments and reports. But if you want to help please focus on real issues and not on cosmetic. Also I thank you for your documentation offer, but we do not need to pollute this thread now with tiny advises.
The ability of using (-1) for Col* properties was not obvious for me and I'm assure, for many others . You had never mentioned about it (or I had never seen it) before. I noticed it completly by accident after I rewrote your code. But I heard you. I apologize for my disrespectful statement about "readable edition". I considered it as a sort of professional joke. Sorry for that. Attachment 188109
Update released.
Fixed args Text1 and Text2 in the CompareText event from As Long to As String. :eek:
Thanks to NBechtloff who made it possible to modify the type lib in VBFLXGRD16.OCX so it could be re-compiled with "binary compatibility".
These defaults should be equal, shouldn't they?
Code:Private Sub Command2_Click()
With VBFlexGrid1 ' DEFAULTS:
Debug.Print .ColIsVisible(.Col) ' FlexVisibilityPartialOK
Debug.Print .ColsVisible() ' FlexVisibilityCompleteOnly
End With
End Sub
Private Sub Command1_Click()
With VBFlexGrid1 ' DEFAULTS:
Debug.Print .RowIsVisible(.Row) ' FlexVisibilityPartialOK
Debug.Print .RowsVisible() ' FlexVisibilityCompleteOnly
End With
End Sub
Hi again.
Where an how is the best way to validate an input?
I mean, i want a cell / col that only allows numbers.
following your example, i used:
Code:Private Sub Gr1_EditSetupStyle(dwStyle As Long, dwExStyle As Long)
Const ES_NUMBER As Long = &H2000
Select Case Gr1.EditCol
Case 3 'solo numeros
dwStyle = dwStyle Or ES_NUMBER
End Select
End Sub
But with this, i can't enter decimals ('.' or ',')
Maybe I must check all the keypress at cell ?, is there another Constant that allows numbers and decimals ?
Thanks!
Edit:
Solved this way (I accept better ways to do it xD):
Code:
Private Sub Gr1_EditKeyPress(KeyChar As Integer)
If InStr("all the keys of the columns i want to check", Gr1.ColKey(Gr1.EditCol)) >= 1 Then
If Not (KeyChar >= vbKeyA And KeyChar <= vbKeyZ) And Not (KeyChar >= 97 And KeyChar <= 122) Then
Else
KeyChar = 0
End If
End If
End Sub
Try this one. The only problem is you can't use the Backspace to delete something.
Code:Private Type LIMITINPUTSTRUCT
cbSize As Long
dwMask As Long
dwFlags As Long
hInst As Long
pszFilter As Long
pszTitle As Long
pszMessage As Long
hIcon As Long
hwndNotify As Long
iTimeout As Long
cxTipWidth As Long
End Type
' Read more about the SHLimitInputEditWithFlags function here:
' https://www.vbforums.com/showthread.php?895398-VB6-Undocumented-API-SHLimitInputEditWithFlags-Easy-input-filtering
Private Declare Function SHLimitInputEditWithFlags _
Lib "shell32" _
Alias "#754" (ByVal hWndEdit As Long, _
Limits As LIMITINPUTSTRUCT) As Long
Private Sub Gr1_EditSetupWindow(BackColor As stdole.OLE_COLOR, _
ForeColor As stdole.OLE_COLOR)
' the hWndEdit is already created in this event
Select Case Gr1.EditCol
Case 3 'solo numeros
If Not LimitInput("0123456789,.", Gr1.hWndEdit) Then Debug.Print "Something went wrong"
End Select
End Sub
Private Sub Gr1_ValidateEdit(Cancel As Boolean)
If Not IsNumeric(Gr1.EditText) Then
Cancel = True
MsgBox "Only numeric values are allowed"
End If
End Sub
'-----------------------------------------------------------------------------
' Function LimitInput
' Descr : Limits user input using string filter. Returns False on fault
' Args : sFilter (String) - the string of allowed acaracters
' hWndEdit (Long) - Gr1.hWndEdit
'-----------------------------------------------------------------------------
Private Function LimitInput(ByRef sFilter As String, _
ByVal hWndEdit As Long) As Boolean
Const TITLE = "Bad character"
Const MESSAGE = "This character is not allowed"
Static FLTR As String
Dim hr As Long
Dim lerr As Long
Dim Limits As LIMITINPUTSTRUCT
FLTR = sFilter
With Limits
.cbSize = Len(Limits)
.dwMask = 379 '= LIM_FILTER + LIM_FLAGS + LIM_HINST + LIM_ICON + LIM_MESSAGE + LIM_TIMEOUT + LIM_TITLE
.hInst = App.hInstance
.dwFlags = 4096 '= LIF_KEEPCLIPBOARD + LIF_PASTESTOP
.pszTitle = StrPtr(TITLE)
.pszMessage = StrPtr(MESSAGE)
.hIcon = 2 '= TTI_WARNING
.iTimeout = 10000
.dwFlags = .dwFlags Or &H200 ' LIF_HIDETIPONVALID
If LenB(FLTR) Then
.pszFilter = StrPtr(FLTR)
.dwFlags = .dwFlags And Not &H2 ' LIF_CATEGORYFILTER
Else
.dwFlags = .dwFlags Or &H2 ' LIF_CATEGORYFILTER
.pszFilter = 32 ' LICF_CNTRL
End If
End With
hr = SHLimitInputEditWithFlags(hWndEdit, Limits)
lerr = Err.LastDllError
LimitInput = Not (CBool(lerr) Or CBool(hr))
End Function
Update released.
The sources for the VBFlexGrid control are now x64 aware. Which means it can be imported into twinBASIC "as-is" and run under the x64 compiler.
The same logic. Inconvenient for me.
ColResizable and RowResizable are restrictive only properties. I mean:
- you can AllowUserResizing for all Cols(or Rows) except those for which ColResizable=False (or RowResizable=False);
- but you can not DisallowUserResizing for all Cols(or Rows) except those for which ColResizable=True (or RowResizable=True)
Speed test. 10 000 rows.
VBFlexGrid1_Compare = 3199 ms (BubbleSort) Attachment 188205 FIXED. Update 1.6.24 released
MSHFlexGrid1_Compare = 61 ms Attachment 188206
VBFlexGrid1_CompareText = 10 ms. Brilliant! Attachment 188204
Code:Private Sub MSHFlexGrid1_Compare(ByVal Row1 As Long, _
ByVal Row2 As Long, _
Cmp As Integer)
Dim Text1 As String
Dim Text2 As String
With MSHFlexGrid1
Text1 = .TextMatrix(Row1, .Col)
Text2 = .TextMatrix(Row2, .Col)
End With
Dim Lng1 As Long: Lng1 = CLng(Right$(Text1, Len(Text1) - 5&))
Dim Lng2 As Long: Lng2 = CLng(Right$(Text2, Len(Text2) - 5&))
Cmp = Sgn(Lng2 - Lng1)
End Sub
Private Sub VBFlexGrid1_Compare(ByVal Row1 As Long, _
ByVal Row2 As Long, _
ByVal Col As Long, _
Cmp As Long)
Dim Text1 As String
Dim Text2 As String
With VBFlexGrid1
Text1 = .TextMatrix(Row1, Col)
Text2 = .TextMatrix(Row2, Col)
End With
Dim Lng1 As Long: Lng1 = CLng(Right$(Text1, Len(Text1) - 5&))
Dim Lng2 As Long: Lng2 = CLng(Right$(Text2, Len(Text2) - 5&))
Cmp = Sgn(Lng2 - Lng1)
End Sub
Private Sub VBFlexGrid1_CompareText(ByVal Text1 As String, _
ByVal Text2 As String, _
ByVal Col As Long, _
Cmp As Long)
Dim Lng1 As Long: Lng1 = CLng(Right$(Text1, Len(Text1) - 5&))
Dim Lng2 As Long: Lng2 = CLng(Right$(Text2, Len(Text2) - 5&))
Cmp = Sgn(Lng2 - Lng1)
End Sub
Yahoo! Attachment 188214
VBFlexGrid1_Compare = 34 ms
Yes, but we can sort using colors or other cell formats!
Thank you, Krool!
I consider it not as "inversing", but as default value and exceptions. All your formatting properties are done in this way: there is a default value for the column and exceptions for individual cells.
For me, this problem is more about working with rows rather than columns. Let's imagine, that the user should only change the height of frozen rows. In order to implement this, you will have to go through all the rows of the table and set the RowResizable=False. You should keep this property in mind every time you add new rows. Now imagine that at some point you want to allow user to change the height of the rows.
Let's complicate things a bit and remember that you have the FlexDataSource property. What happens to the amount of memory consumed in this case?
What do we need the RowsPerPage and ColsPerPage properties for? I assume that they are useful to determine the number of scrollable rows and columns when miving right or down. But what about moving up and left?
Krool, can you add an optional "Direction" parameter to the RowsPerPage and ColsPerPage properties? I assume it should have the enum of three constants:
- PreviousPage
- CurrentPage (default)
- NextPage
Is there any difference between "RowHidden = False" and "RowHeight = -1"?
Strange issue when writing the contents of a cell to SQL.
I have a grid that I've changed from MSFlexGrid to VBFlexGrid. Everything is working fine, except I'm getting 'Multiple-step OLE DB Operation failed', with updating a SQL record with the contents of the grid. The code worked fine when a MSFlexgrid. I normally get this error when trying to write too much information into a SQL field.
The grid is a simple 6 row, 3 column grid. The third column is blank, and never populated with text, but if I do
.fields("Test") = grdMain.textmatrix(2,2)
I get the error. The LEN of cell(2,2) is 0. If I hover over the field it shows as "". If I assign it to a temporary string as below I get the same error
sTmp = grdmain.textmatrix(2,2)
.fields("Test") = sTmp
This throws the same error, but sTmp shows as "" and len of 0, and if I Msgbox it, shows as a blank message.
the SQL Field 'Test' is an nvarchar(150).
Strangely the below line of code works:
.fields("Test") = IIf(grdMain.TextMatrix(2,2) = "", "", grdMain.TextMatrix(2, 2))
This implies that it knows the cell as no information, so evaluates to "", but if this is the case I should be able to write the cell straight to SQL.
Very confusing.
Any pointers would be much appreciated. By the way using version 1.5 of the grid.
Thanks
Lee.
Probably the reason is in the vbNullString value. This code works differently on MSFlexGrid and VBFlexGrid:
Try to use this code:Code:With VBFlexGrid1
.Cols = .Cols + 1
Debug.Print StrPtr(.TextMatrix(1, .Cols - 1))
End With
Code:sTmp = grdmain.textmatrix(2, 2)
.fields("Test") = IIf(LenB(sTmp) = 0&, "", sTmp)
There is a bug in the ColWidthMin property.
EDITED: The answer is here.
Code:With VBFlexGrid1
.ColWidthMin = 500
.ColWidth(1) = 10
Debug.Print .ColWidth(1) ' The result is 495, not 500
End With
The same with RowHeightMax, RowHeightMin and ColWidthMax
EDITED: The answer is here.
Code:With VBFlexGrid1
.RowHeightMax = 500
.RowHeight(1) = 600
Debug.Print .RowHeight(1) ' The result is 495, not 500
End With
Code:With VBFlexGrid1
.RowHeightMin = 500
.RowHeight(1) = 10
Debug.Print .RowHeight(1) ' The result is 495, not 500
End With
Code:With VBFlexGrid1
.ColWidthMax = 500
.ColWidth(1) = 600
Debug.Print .ColWidth(1) ' The result is 495, not 500
End With
@Krool, it's possible to create Tooltips with more than 1 line ?
This:
VbGrid.ToolTipText = "Color Verde = 'Tiene Horas extras'" & vbCrLf & "Color Rojo = 'Falta Fichaje'"
doesn't work.
Thanks!
I guess the unit is twips. The unit for the given properties is pixel. A pixel is 15 twips. So if you set the property to a value other than a multiple of 15 (ratio twips/pixel) the property returns the next integer in twips. You set a height to 500 twips, that results in 33 pixel, that results in 495 twips.
greetings seniorchef
Krool's answer:
https://www.vbforums.com/showthread....=1#post5610477
The Reason parameter in the ComboBeforeDropDown event is always FlexComboDropDownReasonInitialize. No matter if it was dropped down by mouse or keyboard or by code like the below one. By the way, what does the FlexComboDropDownReasonInitialize mean?
Code:Private Sub Command1_Click()
With VBFlexGrid1
.Cell(FlexCellComboCue, .FixedRows, 1, .Rows - 1) = FlexComboCueDropDown
.ColComboMode(1) = FlexComboModeDropDown
.ColComboItems(1) = "Bob|Jack|Ivan"
.Cell(FlexCellText, .FixedRows, 1, .Rows - 1) = "Bob"
.StartEdit 1, 1
.ComboButtonValue = FlexComboButtonValuePressed
.EditText = "Jack"
.CommitEdit
End With
End Sub
Private Sub VBFlexGrid1_ComboBeforeDropDown( _
ByVal Reason As FlexComboDropDownReasonConstants, _
Cancel As Boolean)
Debug.Print "Reason: "; Reason ' THIS ALWAYS RETURNS 1.
End Sub
FlexComboDropDownReasonInitialize is when the drop-down list (or calendar) automatically shows upon the .StartEdit.
This is the only way to suppress behavior by checking Reason for FlexComboDropDownReasonInitialize in the ComboBeforeDropDown event. This way it is possible to prevent auto drop-down.
The following scenarios for FlexComboDropDownReasonInitialize:
1. Edit reason is one of the ComboCue* reasons.
2. The combo mode is "DropDown" (not "Editable")
3. The combo mode is "Calendar" AND the edit control has ES_READONLY.
The ComboBeforeDropDown event not fires when I DblClick the TextBox or press F2 (ComboMode = *Editable):
Code:Private Sub Command1_Click()
With VBFlexGrid1
.Cell(FlexCellComboCue, .FixedRows, 1, .Rows - 1) = FlexComboCueDropDown
.ColComboMode(1) = FlexComboModeEditable
.ColComboItems(1) = "Bob|Jack|Ivan"
.Cell(FlexCellText, .FixedRows, 1, .Rows - 1) = "Bob"
.StartEdit 1, 1 ' Reason = 0.
.ComboButtonValue = FlexComboButtonValuePressed
.EditText = "Jack"
.CommitEdit
End With
End Sub
Private Sub VBFlexGrid1_ComboBeforeDropDown( _
ByVal Reason As FlexComboDropDownReasonConstants, _
Cancel As Boolean)
Debug.Print "Reason: "; Reason
End Sub
Why the StartEdit method should automatically show the drop-down list (or calendar)? Are we in too much trouble because of this? We have to track two events at once: BeforeEdit and ComboBeforeDropDown, because we should pass the FlexEditReasonComboCue* from the BeforeEdit to the ComboBeforeDropDown event. Am I right?
That's standard behavior. For an Editable combo box the edit control is "priority". Because you normally just text edit, the drop-down list is a "plus".
On the other hand the mode "DropDown" the edit control is locked, thus you can only pick an item from the drop-down list. And here it is convenient to automatically drop it down.
I should press F4 three times:
- The first one it will be *ReasonInitialize
- On the second one the drop-down list will be closed
- And only after the third time I press F4 it will cause the *ReasonKeyboard.
Not "to close", but "to open it again". The same as with F4.
Nothing happens.
Yes, but we usually don't work that way with ComboBoxes.
I'm talking about the StartEdit method. "Standard" ComboBox don't have this method. You are trying to "suppress" showing the drop-down list when this method is called by code. So the question is: why it should show this list? If you want, you can show it using the ComboButtonValue.
Maybe I need an example of using the *Initialize reason. The example where EditReason will not work.
Hi,
Using the WantReturn property in combination with the LeaveEdit event I can move the focus to the next cell that the user is allowed to edit when they press the Enter key.
Is it also possible to catch the Tab-key to create the same behavior?
I thought to do this via the EditKeyPress event, but can't get it to work.
Thanks,
Erwin
Can anyone explain me how to draw a Button? I know almost nothing about WinAPI, but I've tried:
Code:Private Sub VBFlexGrid1_ComboButtonOwnerDraw(ByVal Row As Long, _
ByVal Col As Long, _
Cancel As Boolean, _
ByVal CtlType As Long, _
ByVal ItemAction As Long, _
ByVal ItemState As Long, _
ByVal hDC As Long, _
ByVal Left As Long, _
ByVal Top As Long, _
ByVal Right As Long, _
ByVal Bottom As Long)
Dim hWndButton As Long
hWndButton = CreateWindowEx(0&, "BUTTON", "Basic", WS_CHILD, _
Left, Top, Right - Left, Bottom - Top, hDC, _
0&, App.hInstance, ByVal 0&)
ShowWindow hWndButton, SW_NORMAL
End Sub
Private Sub Command1_Click()
With VBFlexGrid1
.ComboButtonDrawMode = FlexComboButtonDrawModeOwnerDraw
.CellComboCue = FlexComboCueButton
End With
End Sub
What values may have CtlType, ItemAction and ItemState params in the ComboButtonOwnerDraw event?
@Krool
A bug in ComboCalendarMinDate/ComboCalendarMaxDate properties.
Attachment 188291Code:With VBFlexGrid1
.Cell(FlexCellComboCue, .FixedRows, 1, .Rows - 1, 1) = FlexComboCueDropDown
.ComboMode = FlexComboModeCalendar
.ComboCalendarMaxDate = Date + 31
.ComboCalendarMinDate = Date - 31
End With
PS.
I've written more than 160 pages of documentation. I'm moving alphabetically and I'm now only on the letter "C". You've got dozens of bugs here. Maybe I'm not a $100 to everyone's liking, but I'm doing a big job for the community. If you keep ignoring my messages, I won't bother you anymore.