RERThird
2015-10-20T16:25:38Z
We have a medical record program in which the lab data are stored in SQL Server tables.
Clinical laboratory data are programmatically screened to see if each value is less or greater than its normal limits. If greater, the cell value appears red. If less, it appears blue. This works fine with iGrid.

To print the contents of an iGrid table, we read the value of each of its cells and write the value to a corresponding cell in an Excel sheet. Excel is then used to print the contents of the sheet.

The problem is that the numeric data transfer from iGrid to Excel perfectly, but the color coding is lost.

The solution may be as simple as changing "value" to some other descriptor. If not, is there any way to read the cell color information at the time of reading a cell's numeric value so that the color information can be transferred to Excel.

Thank you very much.

Robert Robinson
RERThird
2015-10-20T16:59:58Z
I tried using iGrid1.CellForeColor(vRow, vCol) to read a cell's color, but the return is always -1.
RaymondC
2015-10-21T01:14:12Z
The CellForeColor property works properly for me. It's true that -1 is returned if the cell is using the default fore color value.

I think the problem may be with how you are initially assigning the grid cells with the desired fore color. How are you setting the color?
RERThird
2015-10-21T01:53:29Z
Thank you very much for your reply.
I understand that the default is -1 and the problem may be with either the initial color setting or the setting that is based on the limit check.

The code snippet for the limit check is as follows:

Private Sub iGrid1_CellDynamicFormatting(ByVal lRow As Long, ByVal lCol As Long, ByVal vValue As Variant, oForeColor As Long, oBackColor As Long, oFont As Object)
    Dim iStart, iEnd As Integer
    Dim i As Integer
    Dim lowLimit, highLimit As String
    Dim strTemp1 As String
    
    For i = 2 To 15
        strTemp1 = iGrid2.CellValue(lRow, lCol)
        'strTemp1 = "|65|90|"
        iStart = InStr(1, strTemp1, "|") + 1
        If iStart < 1 Then Exit Sub
        iEnd = InStr(iStart, strTemp1, "|")
        If iEnd < 1 Then Exit Sub
        lowLimit = Mid(strTemp1, iStart, iEnd - iStart)
        iStart = InStr(2, strTemp1, "|") + 1
        If iStart < 1 Then Exit Sub
        iEnd = InStr(iStart, strTemp1, "|")
        If iEnd < 1 Then Exit Sub
        highLimit = Mid(strTemp1, iStart, iEnd - iStart)
        If vValue < Val(lowLimit) Then
           oForeColor = vbBlue
           iGrid3.CellValue(lRow, lCol) = vbBlue
        End If
        If vValue > Val(highLimit) Then
           oForeColor = vbRed
           iGrid3.CellValue(lRow, lCol) = vbRed
           End If
   Next i
   Exit Sub

End Sub
Clinical laboratory test normal limits are specific to individual labs and to specific analytic techniques. They change from time to time and thus the limits must be included with each test result. oForeColor sets the cell ForeColor to vbBlue if the result is below the normal limit and to VbRed if it is above the normal limit. The use of iGrid3 is a temporary kludge which keeps track of any ForeColor changes.

The following is the code snippet to print an iGrid table with any ForeColor changes:

Private Sub PrintPB_DblClick(Cancel As Integer)

Dim oXLApp As Object
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
Dim txtRng As Range
Dim filePath As String
Dim strText1 As String
Dim vRow, vCol As Variant

filePath = "C:\Users\" & Environ$("UserName") & "\Documents\"

241 Set oXLApp = CreateObject("Excel.Application")
242 oXLApp.Visible = False

Set wb = Workbooks.Open(filePath & "PrintiGrid.xlsx")

244 Set ws = wb.Worksheets(1)
ws.PageSetup.LeftHeader = "&20" & TempVars!GlobalNametitle
ws.PageSetup.CenterHeader = ""
ws.PageSetup.RightHeader = "&20" & TempVars!stringTableName
ws.PageSetup.LeftFooter = "&12 &D  &B&ITime:&I&B&T"
ws.PageSetup.RightFooter = "&12 &P"

ws.Cells.ClearContents

ws.Cells(1, 1) = "Date"
ws.Cells(1, 2) = "NA+"
ws.Cells(1, 3) = "K+"
ws.Cells(1, 4) = "CL-"
ws.Cells(1, 5) = "CO2"
ws.Cells(1, 6) = "BUN"
ws.Cells(1, 7) = "Crea"
ws.Cells(1, 😎 = "Glu"
ws.Cells(1, 9) = "Calc"
ws.Cells(1, 10) = "TP"
ws.Cells(1, 11) = "Alb"
ws.Cells(1, 12) = "AlkPhos"
ws.Cells(1, 13) = "AST"
ws.Cells(1, 14) = "ALT"
ws.Cells(1, 15) = "Bili"

Dim ret As Integer

For vRow = 1 To iGrid1.RowCount
    For vCol = 1 To iGrid1.ColCount
        strText1 = iGrid1.CellValue(vRow, vCol)
        ws.Cells(vRow + 1, vCol).value = strText1
        If iGrid3.CellValue(vRow, vCol) = vbBlue Then
            ws.Cells(vRow + 1, vCol).Font.Color = vbBlue
        End If
        If iGrid3.CellValue(vRow, vCol) = vbRed Then
            ws.Cells(vRow + 1, vCol).Font.Color = vbRed
        End If
    Next vCol
Next vRow
ws.PrintOut
wb.Saved = True

wb.Close
oXLApp.Quit
Set oXLApp = Nothing

End Sub
Thank you again.

Robert Robinson
RaymondC
2015-10-21T02:17:09Z
I did a quick test and sure enough when you set the oForeColor parameter in the CellDynamicFormatting event, the CellForeColor property will return -1. It must be due to how that event is handled internally by iGrid.

Instead of setting the oForeColor value, you could set the CellForeColor property using the lRow and lCol values, i.e. replace "oForeColor = vbBlue" with "iGrid1.CellForeColor(lRow,lCol)= vbBlue."

I tested this and it works but it caused a visual glitch on the grid where two strings appeared on top of each other. Simply moving the mouse over the cell cleared up the display glitch. Maybe this display glitch is only on my system and you won't get it but if so then another solution is simply to loop through the cells after the grid is populated and assign the fore color as desired in you own procedure and don't use the CellDynamicFormatting event.
RERThird
2015-10-21T03:54:07Z
Hi Raymond,

Thank you very much for your reply.
I will try iGrid1.CellForeColor(1Row,1Col)= vbBlue

If the two strings glitch is present, I will probably use the current procedure which involves saving the color information in a hidden iGrid3.

Robert Robinson

Igor/10Tec
2015-10-21T07:41:36Z
The CellForeColor property is a property the developer uses to SET the foreground color of a cell and later READ it if required, but this does not mean that the assigned value will be used "as is" to draw the cell's text. First, its type is OLE_COLOR, and we can assign such special values as vbActiveTitleBar (&H80000002) or even CLR_NONE (-1) to use the grid's foreground color (what is stored in the iGrid.ForeColor property). Second, this value can be overwritten dynamically in the CellDynamicFormatting event. That's why this property returns not what you expected.

We are talking about the EFFECTIVE foreground color. I understand the nature of the problem, and to solve it, iGrid should provide you with a new read-only property that retrieves this effective value. Let's call this property 'CellEffectiveForeColor'. I've noted this suggestion for the future updates, but the question is how to solve the problem now using the existing object model.

I would not use any solution based on setting the CellForeColor property explicitly for all grid cells as it may work slowly if your grid will have thousands of rows. Dynamic formatting is the right tool to solve such a task without performance degrade. To avoid using a mirror grid, I would put the formatting algorithm from the current CellDynamicFormatting event handler into a function and use it in the printing routine too. The function could look like this:

Private Sub GetForeColorForValue(ByVal vValue As Variant, ByRef oForeColor As Long)
    Dim iStart, iEnd As Integer
    Dim lowLimit, highLimit As String
    Dim strTemp1 As String
    
    For i = 2 To 15
        strTemp1 = iGrid2.CellValue(lRow, lCol)
        'strTemp1 = "|65|90|"
        iStart = InStr(1, strTemp1, "|") + 1
        If iStart < 1 Then Exit Sub
        iEnd = InStr(iStart, strTemp1, "|")
        If iEnd < 1 Then Exit Sub
        lowLimit = Mid(strTemp1, iStart, iEnd - iStart)
        iStart = InStr(2, strTemp1, "|") + 1
        If iStart < 1 Then Exit Sub
        iEnd = InStr(iStart, strTemp1, "|")
        If iEnd < 1 Then Exit Sub
        highLimit = Mid(strTemp1, iStart, iEnd - iStart)
        If vValue < Val(lowLimit) Then
           oForeColor = vbBlue
        End If
        If vValue > Val(highLimit) Then
           oForeColor = vbRed
        End If
    Next i
End Sub

And you would call it this way in iGrid1_CellDynamicFormatting:

Private Sub iGrid1_CellDynamicFormatting(ByVal lRow As Long, ByVal lCol As Long, ByVal vValue As Variant, oForeColor As Long, oBackColor As Long, oFont As Object)
    GetForeColorForValue vValue, oForeColor
End Sub

And a similar way in the printing routine.

****************************

As for me, this color formatting algorithm looks enough strange. My questions regarding it are the following:

1) Why do we need this loop for i from 2 to 15? Do we really need it? Or did you show us only a part of the bigger real algorithm?

2) Why don't use the VB Split function  to parse your strings like "|65|90|"? It would simplify your code, and it would work faster.

3) And I if I understand the structure of your app properly, iGrid1 is used for the visual representation on the screen, but iGrid2 stores the limits, right? Are they stored as string values using the template "|<lowLimit>|<highLimit>|"? If so, can you parse them before your visual grid iGrid1 is displayed? This would increase the performance a lot as the parsing algorithm would not be executed to parse the same cell values again and again. And what about to store these values in a 2-dimensional array in memory? Or in 2 arrays, aLowLimits(,) and aHighLimits(,)? It would get the best performance.
RERThird
2015-10-21T18:46:56Z
Hi Igor,

Thank you very much for your excellent discussion.
We are looking forward to the availability of 'CellEffectiveForeColor' and, in the meantime, will follow your recommendations.

To answer your questions:

The tabular data consist of multiple profiles and, separately, individual test results.
For example, a Chemistry Metabolic Profile includes 14 results on one row like: Sodium, Potassium, Chloride and others. They all have the same date.The 2 to 15 loop processes the lab received date and the 14 results in the Chemistry Metabolic Profile that were processed on that same date.

Split Function is probably the best way to unpack the limit strings.

iGrid1 shows the data, iGrid2 contains the limits, and iGrid3 is used for handling the color definitions. iGrid2 and iGrid3 are hidden.
The problems with the limits are that they are date and laboratory specific and thus must be included with each laboratory test result.

Thank you again.

Robert Robinson




Igor/10Tec
2015-12-01T15:21:08Z
Well, the CellEffectiveForeColor/CellEffectiveBackColor properties are available now in iGrid ActiveX 6 as built-in members.