The Microsoft FlexGrid (MSFlexGrid) control displays and operates on tabular data. It allows complete flexibility to sort, merge, and format tables containing strings and pictures.
You can put text, a picture, or both, in any cell of an MSFlexGrid. The Row and Col properties specify the current cell in an MSFlexGrid. You can specify the current cell in code, or the user can change it at run time using the mouse or the arrow keys. The Text property references the contents of the current cell.
If the text in a cell is too long to display in the cell, and the WordWrap property is set to True, the text wraps to the next line within the same cell. To display the wrapped text, you may need to increase the cells column width (ColWidth property) or row height (RowHeight property).
The following example demonstrates how to create a registration-free instance of the Microsoft Flex Grid Control using my OLE Container (OLECON.INC) to host it, how to fill rows and columns using an ADO recordset, how to connect to the events fired by the control (see the Click event for an example of how to sort the rows when the user clicks a row header), and how to set the default font for all the cells.
Registration-free means that you don't need to register the control to be able to use it. To use this registration-free version, you must copy Msflxgrd.ocx in the application folder, as if it was an standard DLL.
For using a registered version of the control, change the following code in the example:
' Create a registration-free instance of the MSHFlexGrid control
LOCAL cp AS OC_CREATEPARAMS
cp.clsid = $CLSID_MSFlexGrid
cp.riid = $IID_IMSFlexGrid
cp.szLicKey = $RTLKEY_MSFlexGrid
cp.szLibName = EXE.Path$ & "Msflxgrd.ocx"
hGrid = CreateWindowEx(0, $OC_CLASSNAME, "", _
%WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP, _
0, 0, 0, 0, CB.HNDL, %IDC_GRID, GetModuleHandle(BYVAL %NULL), cp)
to:
' Create an instance of the control
hGrid = CreateWindowEx(0, $OC_CLASSNAME, _
"MSFlexGridLib.MSFlexGrid.1;RTLKEY:" & $RTLKEY_MSFlexGrid, _
%WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP, 0, 0, 0, 0, hWnd, %IDC_GRID, GetModuleHandle(BYVAL %NULL), BYVAL %NULL)
Full example code (DDT version)
' ########################################################################################
' Microsoft Flex Grid Control Demo
' See the Click event for an example of how to sort the rows when the user clicks a row header.
' ########################################################################################
#COMPILE EXE
#DIM ALL
#INCLUDE ONCE "ADO.INC"
#INCLUDE ONCE "MSFLXGRD.INC"
#INCLUDE ONCE "OLECON.INC"
%IDC_GRID = 1001 ' // Grid's identifier
GLOBAL hGrid AS DWORD ' // Grid's handle
' ========================================================================================
' Main
' ========================================================================================
FUNCTION WINMAIN (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG
LOCAL hDlg AS DWORD
' Required: Initialize the Ole Container
OC_WinInit
DIALOG NEW 0, "Microsoft FlexGrid Control", , , 530, 346, %WS_OVERLAPPED OR %WS_THICKFRAME OR %WS_SYSMENU OR _
%WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_VISIBLE OR %DS_CENTER TO hDlg
' For icon from resource, instead use something like, LoadIcon(hInst, "APPICON")
DIALOG SEND hDlg, %WM_SETICON, %ICON_SMALL, LoadIcon(%NULL, BYVAL %IDI_APPLICATION)
DIALOG SEND hDlg, %WM_SETICON, %ICON_BIG, LoadIcon(%NULL, BYVAL %IDI_APPLICATION)
' We need to forward the messages to the control for keyboard handling
' and for that we need a message pump, so the dialog must be modeless.
DIALOG SHOW MODELESS hDlg, CALL DlgProc
' Message handler loop
LOCAL uMsg AS tagMsg
WHILE GetMessage(uMsg, %NULL, 0, 0)
IF ISFALSE OC_ForwardMessage(GetFocus, uMsg) THEN
IF IsDialogMessage(hDlg, uMsg) = 0 THEN
TranslateMessage uMsg
DispatchMessage uMsg
END IF
END IF
WEND
END FUNCTION
' ========================================================================================
' ========================================================================================
' Main Dialog procedure
' ========================================================================================
CALLBACK FUNCTION DlgProc() AS LONG
LOCAL hr AS LONG ' // HRESULT code
LOCAL rc AS RECT ' // RECT structure
LOCAL pGrid AS IMSFlexGrid ' // IMSFlexGrid interface reference
STATIC pEvents AS DMSFlexGridEventsImpl ' // Events interface
SELECT CASE CB.MSG
CASE %WM_INITDIALOG
' Create a registration-free instance of the MSFlexGrid control
LOCAL cp AS OC_CREATEPARAMS
cp.clsid = $CLSID_MSFlexGrid
cp.riid = $IID_IMSFlexGrid
cp.szLicKey = $RTLKEY_MSFlexGrid
cp.szLibName = EXE.Path$ & "Msflxgrd.ocx"
hGrid = CreateWindowEx(0, $OC_CLASSNAME, "", _
%WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP, _
0, 0, 0, 0, CB.HNDL, %IDC_GRID, GetModuleHandle(BYVAL %NULL), cp)
' Get a reference to the Grid control
pGrid = OC_GetDispatch(hGrid)
IF ISOBJECT(pGrid) THEN
' Create an ADO connection object
LOCAL pCon AS ADOConnection
pCon = NEWCOM "ADODB.Connection"
IF ISOBJECT(pCon) THEN
' Connection string - Remember to change the path of the Data Source if needed
LOCAL ConStr AS STRING
ConStr = UCODE$("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & EXE.Path$ & "NWIND.mdb")
' Set the connection string
pCon.ConnectionString = ConStr
' Open the connection
pCon.Open
IF OBJRESULT = %S_OK THEN
' Create an ADO recordset object
LOCAL pRec AS ADORecordset
pRec = NEWCOM "ADODB.Recordset"
IF ISOBJECT(pRec) THEN
' Open the recordset
LOCAL SqlStr AS STRING
SqlStr = "SELECT * FROM Customers"
pRec.Open SqlStr, pCon, %adOpenKeyset, %adLockOptimistic, %adCmdText
' Move to the last record
pRec.MoveLast
' Set the number of grid rows and columns
pGrid.Rows = pRec.RecordCount + 1
pGrid.Cols = 12
' Set the headers
pGrid.TextMatrix(0, 1) = UCODE$("Customer ID")
pGrid.TextMatrix(0, 2) = UCODE$("Company Name")
pGrid.TextMatrix(0, 3) = UCODE$("Contact Name")
pGrid.TextMatrix(0, 4) = UCODE$("Contact Title")
pGrid.TextMatrix(0, 5) = UCODE$("Address")
pGrid.TextMatrix(0, 6) = UCODE$("City")
pGrid.TextMatrix(0, 7) = UCODE$("Region")
pGrid.TextMatrix(0, 8) = UCODE$("Postal Code")
pGrid.TextMatrix(0, 9) = UCODE$("Country")
pGrid.TextMatrix(0, 10) = UCODE$("Phone")
pGrid.TextMatrix(0, 11) = UCODE$("Fax")
' Change the width of the columns (measures are in twips)
pGrid.ColWidth( 0) = 500
pGrid.ColWidth( 1) = 1400
pGrid.ColWidth( 2) = 3000
pGrid.ColWidth( 3) = 2000
pGrid.ColWidth( 4) = 2000
pGrid.ColWidth( 5) = 3000
pGrid.ColWidth( 6) = 1500
pGrid.ColWidth( 7) = 800
pGrid.ColWidth( 8) = 1300
pGrid.ColWidth( 9) = 1200
pGrid.ColWidth(10) = 1500
pGrid.ColWidth(11) = 1500
' Allow to resize columns
pGrid.AllowUserResizing = %flexResizeColumns
' Set the default font for all the cells
LOCAL pFont AS IDispatch
hr = OleCreateFontDisp("Verdana", 8, %FW_BOLD, %ANSI_CHARSET, 0, 0, 0, pFont)
IF ISOBJECT(pFont) THEN
pGrid.putref_Font = pFont
pFont = NOTHING
END IF
' Change the foreground and background colors
pGrid.ForeColor = %BLACK
pGrid.BackColor = RGB(255,255,235)
' Move to the first record
pRec.MoveFirst
' Parse the recordset and fill the grid
LOCAL row AS LONG
LOCAL vRes AS VARIANT
row = 1
WHILE NOT pRec.EOF
'Select the row
pGrid.Row = row
' Set the content of cell 1
pGrid.Col = 1
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("CustomerID")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 2
pGrid.Col = 2
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("CompanyName")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 3
pGrid.Col = 3
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("ContactName")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 4
pGrid.Col = 4
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("ContactTitle")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 5
pGrid.Col = 5
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("Address")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 6
pGrid.Col = 6
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("City")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 7
pGrid.Col = 7
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("Region")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 8
pGrid.Col = 8
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("PostalCode")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 9
pGrid.Col = 9
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("Country")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 10
pGrid.Col = 10
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("Phone")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Set the content of cell 11
pGrid.Col = 11
pGrid.CellAlignment = %flexAlignLeftCenter
vRes = pRec.Collect("Fax")
pGrid.Text = UCODE$(VARIANT$(vRes))
' Fetch the next row
pRec.MoveNext
' Increment the counter
INCR row
WEND
' Select the first cell
pGrid.Row = 1
pGrid.Col = 1
' Close and release the recordset
pRec.Close
pRec = NOTHING
END IF
END IF
' Close and release the connection
pCon.Close
pCon = NOTHING
END IF
' Connect to the events fired by the control
pEvents = CLASS "CDMSFlexGridEvents"
EVENTS FROM pGrid CALL pEvents
pGrid = NOTHING
END IF
CASE %WM_SIZE
' Resize the grid
IF CB.WPARAM <> %SIZE_MINIMIZED THEN
GetClientRect CB.HNDL, rc
MoveWindow GetDlgItem(CB.HNDL, %IDC_GRID), 0, 0, (rc.nRight - rc.nLeft), (rc.nBottom - rc.nTop), %TRUE
END IF
CASE %WM_COMMAND
SELECT CASE CB.CTL
CASE %IDOK
IF CB.CTLMSG = %BN_CLICKED THEN
END IF
CASE %IDCANCEL
IF CB.CTLMSG = %BN_CLICKED THEN DIALOG END CB.HNDL, 0
END SELECT
' --> Note: Both WM_SYSCOMMAND and WM_DESTROY are required with this control <--
CASE %WM_SYSCOMMAND
' Capture this message and send a %WM_CLOSE message,
' or the program may remain in memory
IF (CBWPARAM AND &HFFF0) = %SC_CLOSE THEN
DIALOG SEND CB.HNDL, %WM_CLOSE, 0, 0
END IF
CASE %WM_DESTROY
' Disconnect events and quit
EVENTS END pEvents
PostQuitMessage 0
END SELECT
END FUNCTION
' ========================================================================================
' ########################################################################################
' Class CDMSFlexGridEvents
' Interface name = DMSFlexGridEvents
' IID = {609602E0-531B-11CF-91F6-C2863C385E30}
' Event interface for Microsoft FlexGrid Control
' Attributes = 4112 [&H1010] [Hidden] [Dispatchable]
' ########################################################################################
CLASS CDMSFlexGridEvents GUID$("{82AFC6E9-56AF-43AD-8516-BDD81DECCF98}") AS EVENT
INTERFACE DMSFlexGridEventsImpl GUID$("{609602E0-531B-11CF-91F6-C2863C385E30}") AS EVENT
INHERIT IDispatch
' =====================================================================================
METHOD Click <-600>
LOCAL pGrid AS IMSFlexGrid ' // IMSFlexGrid interface reference
LOCAL row AS LONG ' // Row clicked
OutputDebugString FUNCNAME$
' Get a reference to the Grid control
pGrid = OC_GetDispatch(hGrid)
IF ISOBJECT(pGrid) THEN
row = pGrid.MouseRow
IF row = 0 THEN ' // User has clicked the header row
' Sort rows in ascending order
pGrid.Sort = %flexSortGenericAscending
pGrid = NOTHING
END IF
END IF
END METHOD
' =====================================================================================
' =====================================================================================
METHOD KeyDown <-602> ( _
BYREF KeyCode AS INTEGER _ ' [1] *KeyCode /* *VT_I2 <Integer> */
, BYVAL iShift AS INTEGER _ ' [0] Shift /* VT_I2 <Integer> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD DblClick <-601>
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD KeyPress <-603> ( _
BYREF KeyAscii AS INTEGER _ ' [1] *KeyAscii /* *VT_I2 <Integer> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD KeyUp <-604> ( _
BYREF KeyCode AS INTEGER _ ' [1] *KeyCode /* *VT_I2 <Integer> */
, BYVAL iShift AS INTEGER _ ' [0] Shift /* VT_I2 <Integer> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD MouseDown <-605> ( _
BYVAL iButton AS INTEGER _ ' [0] Button /* VT_I2 <Integer> */
, BYVAL iShift AS INTEGER _ ' [0] Shift /* VT_I2 <Integer> */
, BYVAL x AS LONG _ ' [0] x /* OLE_XPOS_PIXELS <alias> <VT_I4> */
, BYVAL y AS LONG _ ' [0] y /* OLE_YPOS_PIXELS <alias> <VT_I4> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD MouseMove <-606> ( _
BYVAL iButton AS INTEGER _ ' [0] Button /* VT_I2 <Integer> */
, BYVAL iShift AS INTEGER _ ' [0] Shift /* VT_I2 <Integer> */
, BYVAL x AS LONG _ ' [0] x /* OLE_XPOS_PIXELS <alias> <VT_I4> */
, BYVAL y AS LONG _ ' [0] y /* OLE_YPOS_PIXELS <alias> <VT_I4> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD MouseUp <-607> ( _
BYVAL iButton AS INTEGER _ ' [0] Button /* VT_I2 <Integer> */
, BYVAL iShift AS INTEGER _ ' [0] Shift /* VT_I2 <Integer> */
, BYVAL x AS LONG _ ' [0] x /* OLE_XPOS_PIXELS <alias> <VT_I4> */
, BYVAL y AS LONG _ ' [0] y /* OLE_YPOS_PIXELS <alias> <VT_I4> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD SelChange <69>
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD RowColChange <70>
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD EnterCell <71>
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD LeaveCell <72>
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD Scroll <73>
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD Compare <74> ( _
BYVAL Row1 AS LONG _ ' [0] Row1 /* VT_I4 <Long> */
, BYVAL Row2 AS LONG _ ' [0] Row2 /* VT_I4 <Long> */
, BYREF Cmp AS INTEGER _ ' [1] *Cmp /* *VT_I2 <Integer> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD OLEStartDrag <1550> ( _
BYREF pData AS IVBDataObject _ ' [2] [in][out] **Data /* **DataObject <coclass> */
, BYREF AllowedEffects AS LONG _ ' [1] [in][out] *AllowedEffects /* *VT_I4 <Long> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD OLEGiveFeedback <1551> ( _
BYREF Effect AS LONG _ ' [1] [in][out] *Effect /* *VT_I4 <Long> */
, BYREF DefaultCursors AS INTEGER _ ' [1] [in][out] *DefaultCursors /* *VT_BOOL <Integer> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD OLESetData <1552> ( _
BYREF pData AS IVBDataObject _ ' [2] [in][out] **Data /* **DataObject <coclass> */
, BYREF DataFormat AS INTEGER _ ' [1] [in][out] *DataFormat /* *VT_I2 <Integer> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD OLECompleteDrag <1553> ( _
BYREF Effect AS LONG _ ' [1] [in][out] *Effect /* *VT_I4 <Long> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD OLEDragOver <1554> ( _
BYREF pData AS IVBDataObject _ ' [2] [in][out] **Data /* **DataObject <coclass> */
, BYREF Effect AS LONG _ ' [1] [in][out] *Effect /* *VT_I4 <Long> */
, BYREF iButton AS INTEGER _ ' [1] [in][out] *Button /* *VT_I2 <Integer> */
, BYREF iShift AS INTEGER _ ' [1] [in][out] *Shift /* *VT_I2 <Integer> */
, BYREF x AS SINGLE _ ' [1] [in][out] *x /* *VT_R4 <Single> */
, BYREF y AS SINGLE _ ' [1] [in][out] *y /* *VT_R4 <Single> */
, BYREF State AS INTEGER _ ' [1] [in][out] *State /* *VT_I2 <Integer> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
' =====================================================================================
METHOD OLEDragDrop <1555> ( _
BYREF pData AS IVBDataObject _ ' [2] [in][out] **Data /* **DataObject <coclass> */
, BYREF Effect AS LONG _ ' [1] [in][out] *Effect /* *VT_I4 <Long> */
, BYREF iButton AS INTEGER _ ' [1] [in][out] *Button /* *VT_I2 <Integer> */
, BYREF iShift AS INTEGER _ ' [1] [in][out] *Shift /* *VT_I2 <Integer> */
, BYREF x AS SINGLE _ ' [1] [in][out] *x /* *VT_R4 <Single> */
, BYREF y AS SINGLE _ ' [1] [in][out] *y /* *VT_R4 <Single> */
) ' VOID
' *** Insert your code here ***
OutputDebugString FUNCNAME$
END METHOD
' =====================================================================================
END INTERFACE
END CLASS
' ========================================================================================
This is a great job..Thanks @José Roca. I know it is too late to ask such a question but it is an urgent one :)
I tried to insert a picture into the MSFlexgrid control but I could not formulate how to use the 'IPictureDisp' to set 'putref_CellPicture' property. I tried using LoadImage but in vain
Help.. :D
The following function, included in the Ole2Utils.inc file of my headers, creates an IPictureDisp object:
' ========================================================================================
' Creates a standard IPictureDisp object.
' ========================================================================================
FUNCTION OleCreatePictureDisp ( _
BYVAL hPicHandle AS DWORD, _ ' __in Handle of the icon or bitmap
BYVAL picType AS DWORD, _ ' __in Picture type: %PICTYPE_BITMAP or %PICTYPE_ICON
BYVAL fOwn AS INTEGER, _ ' __in %TRUE or %FALSE
BYREF pPicture AS IDispatch _ ' __out The picture object
) AS LONG ' HRESULT
LOCAL tpd AS PICTDESC
LOCAL riid AS GUID
riid = $IID_IDispatch
IF hPicHandle = 0 THEN FUNCTION = %E_POINTER : EXIT FUNCTION
SELECT CASE picType
CASE %PICTYPE_BITMAP ' Bitmap
tpd.hbitmap = hPicHandle
CASE %PICTYPE_ICON ' Icon
tpd.hicon = hPicHandle
CASE ELSE
FUNCTION = %E_INVALIDARG
EXIT FUNCTION
END SELECT
tpd.cbSizeOfStruct = SIZEOF(PICTDESC)
tpd.picType = picType
IF fOwn THEN fOwn = -1
FUNCTION = OleCreatePictureIndirect(tpd, riid, fOwn, pPicture)
END FUNCTION
' ========================================================================================
Thanks for your prompt reply..
Based on it, is this the right code to load a picture in a MSFlexgrid cell?
' Get a reference to the Grid control
pGrid = OC_GetDispatch(hGrid)
.
.
.
.
LOCAL hbmp AS LONG
LOCAL ImgPath as string
ImgPath=EXE.PATH$ & "Beany.bmp"
hBmp=LoadImage(%NULL, ImgPath, %IMAGE_Bitmap, 256, 256,0)
'I am not really sure of the code
DIM p AS LONG PTR
pGrid.putref_CellPicture =OleCreatePictureDisp(hBmp,%PICTYPE_ICON,%TRUE,@p)
DIM pPicture AS IPictureDisp
OleCreatePictureDisp(hBmp, %PICTYPE_BITMAP, %TRUE, pPicture)
pGrid.putref_CellPicture(pPicture)
It worked.. Thanks for your generosity
Here is the result