Ownerdrawn items

With ownerdrawn items M!Table provides a way to custom paint cells, column headers, column header groups, row headers and the table corner.
To custom paint an item, first of all declare it as ownerdrawn with MTblSetOwnerDrawnItem . Once an item is ownerdrawn, every time when it must be painted MTM_DrawItem is sent to the table. On this message call MTblGetOwnerDrawnItem to get required information in an instance of fcMTblODI and paint whatever you want.




Types and function parameters

Type constant

Affected item(s)

Function parameter

Function parameter


A cell

Column handle

Row number


The header and the cells of a column

Column handle



A column header

Column handle



A column header group

Table handle

Column header group ID


The header and the cells of a row

Table handle

Row number


A row header

Table handle

Row number


The corner

Table handle


Hints and tips

M!Table also sends MTM_DrawItem when you print a table with MTblPrint. In this case the fcMTblODI instance variable Printing is TRUE.
Keep in mind that printers normally have another resolution ( dots per inch ) than the screen. fcMTblODI has specific instance variables to handle this problem, namely YResFactor and XResFactor, e.g.


Screen resolution

Printer resolution



96 DPI

300 DPI

3.125 ( 300 / 96 )


96 DPI

600 DPI

6.25 ( 600 / 96 )

To get the same sizes and/or positions as on the screen, use the following formulas:
Font Size Printer = Font Size Screen * YResFactor
Pixels X Printer = Pixels X Screen * XResFactor
Pixels Y Printer = Pixels Y Screen * YResFactor

The item rectangle ( instance variables Left, Top, Right and Bottom ) and the leadings ( instance variables XLeading and YLeading ) are already in printer units, so don't multiply them with the resolution factors!

Furthermore, please note that drawing (semi-) transparent images with the MImgDraw functions does not work as on the screen. The transparent parts appear black!
To avoid this, call MImgStripOpacity to strip the transparency with the desired background color before drawing.

Drawing into the column and/or row line area
The item rectangle doesn't include the column and/or row line area. If you want to paint into the column line area, simply add 1 to fcMTblODI.Right. If you want to paint into the row line area, simply add 1 to fcMTblODI.Bottom, e.g:

On MTM_DrawItem
  ! Let's paint a blue background and "remove" the column and row line
  Set nColor = COLOR_Blue
  Set nBrush = CreateSolidBrush( nColor )
  Set nOldBrush = SelectObject( odi.DC, nBrush )
  Call FillRect( odi.DC, odi.Left, odi.Top, odi.Right + 1, odi.Bottom + 1, nBrush )
  Call SelectObject( odi.DC, nOldBrush )
  Call DeleteObject( nBrush )

Please note that you can't "remove" lines that way when the table is printed because in the printout the grid lines are always painted according to the value of fcMTblPrintParams.GridType after the custom painting is done.

Normally, you don't have to concern about selections because MTM_DrawItem is sent before M!Table inverts the selected rows and/or columns.

But if selection colors are used ( see MTblSetSelectionColors or Extended selections ), M!Table doesn't invert the selected rows and/or columns, but draws them with the defined selection colors.
If you want to reflect selections in your ownerdrawn items, you have to determine the correct text and background color.
Check if the fcMTblODI instance variable Selected is TRUE and if selection colors are used. If so, use the selection colors, e.g.:
Call MTblGetEffCellTextColor( odi.HWndParam, odi.NParam, nTextColor )
Call MTblGetEffCellBackColor( odi.HWndParam, odi.NParam, nBackColor )
If odi.Selected And Not odi.Printing
  Call MTblGetSelectionColors( hWndTbl, nSelTextColor, nSelBackColor )
  If nSelTextColor != MTBL_COLOR_UNDEF
    Set nTextColor = nSelTextColor
  If nSelBackColor != MTBL_COLOR_UNDEF
    Set nBackColor = nSelBackColor

Automatic sizing
To ensure a proper automatic sizing for your ownerdrawn items ( e.g. if you call MTblAutoSizeColumn ), you should return appropriate values on MTM_QueryBestCellWidth and/or MTM_QueryBestColHdrWidth. Let's say you have an ownerdrawn cell in which you draw a rectangle with a width of 200 pixels, then you should do something like this:
On MTM_QueryBestCellWidth
  If MTblIsOwnerDrawnItem( SalNumberToWindowHandle( wParam ), lParam, MTBL_ODI_CELL )
    Return 210 ! 10 pixels margin
    Return 0 ! Not ownerdrawn, let M!Table determine the best width


Created with the Personal Edition of HelpNDoc: Produce electronic books easily