Results 1 to 13 of 13

Thread: [RESOLVED] Sharing the horror of my Excel report export code

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2006
    Location
    USA
    Posts
    476

    Resolved [RESOLVED] Sharing the horror of my Excel report export code

    This code accepts a sql string as a parameter and it downloads the necessary data, throws it into an Excel sheet, then draws three graphs based on the data it has just downloaded. The requirement is for the report to look just like its old Access counterpart, hence a lot of hard-coding has to take place.

    Any way to improve this = much appreciated. I'm ready for the absolute worst of criticisms.

    Thank you.

    VB Code:
    1. Public Sub CreateExcelWS(strSQL As String)
    2.  
    3.     Call LoadCaption(True)
    4.  
    5.     ' Checks connection to SQL Server; there should be a connection already
    6.     ' but if there isn't it creates one; if the connection is closed (should
    7.     ' not be) then it opens it.
    8.     Call CheckConnection
    9.    
    10.     Dim objRSArray() As ADODB.Recordset
    11.     Dim objRS As ADODB.Recordset
    12.     Dim xlApp As Object
    13.     Dim xlBook As Object
    14.     Dim xlSheet As Object
    15.     Dim xlChartArray(3) As Object
    16.     Dim i As Integer
    17.     Dim strSource(3) As String
    18.     Dim strParameter As String
    19.     Dim strSproc() As String
    20.     Dim StartPosition(3) As Integer
    21.    
    22.     ' Checks to see if there is already an instance of Excel; if there is
    23.     ' then the current one is used, if not then a new one is created.
    24.     If IsExcelInstalled = True And IsExcelRunning = False Then
    25.         Set xlApp = CreateObject("Excel.Application")
    26.     Else
    27.         Set xlApp = GetObject(, "Excel.Application")
    28.     End If
    29.    
    30.     ' Instantiates Excel objects
    31.     Set xlBook = xlApp.Workbooks.Add
    32.     Set xlSheet = xlBook.ActiveSheet
    33.     xlSheet.Name = "Sheet 1"
    34.    
    35.     ' Calls UnpackString() function and assigns the output to the strSproc array
    36.     strSproc = UnpackString("SELECT SQLObject FROM tblReports WHERE ReportName = 'Weekly Summary'")
    37.        
    38.     ' Calls the DeriveWhereClause function and assigns the output to strParameter
    39.     strParameter = DeriveWhereClause
    40.    
    41.     ' Sets up the strSource array using the strSproc array
    42.     For i = 0 To UBound(strSproc)
    43.         strSource(i) = "EXEC " & strSproc(i) & " @Filter = " & "'" & strParameter & "'"
    44.     Next i
    45.    
    46.     ReDim objRSArray(UBound(strSproc))
    47.     ' Instantiates and opens the members of the recordset array and
    48.     ' sets the cursorlocation property so that we can use the
    49.     ' recordcount property later on.
    50.     For i = 0 To UBound(strSproc)
    51.         Set objRSArray(i) = New ADODB.Recordset
    52.         objRSArray(i).CursorLocation = adUseClient
    53.         objRSArray(i).Open strSource(i), cnConn, adOpenForwardOnly, adLockReadOnly, adCmdText
    54.     Next i
    55.    
    56.    
    57.     ' Initializes StartPosition(1) and moves data to Excel; starting position
    58.     ' is determined by sizes of recordsets
    59.     ' First chart
    60.     StartPosition(1) = 4
    61.     Call MoveDataExcel(objRSArray(0), xlSheet, StartPosition(1))
    62.     ' Second chart
    63.     StartPosition(2) = StartPosition(1) + 2 + objRSArray(0).RecordCount
    64.     Call MoveDataExcel(objRSArray(1), xlSheet, StartPosition(2))
    65.     ' Third chart
    66.     StartPosition(3) = StartPosition(2) + 2 + objRSArray(1).RecordCount
    67.     Call MoveDataExcel(objRSArray(2), xlSheet, StartPosition(3))
    68.    
    69.     ' Instantiates chart objects and adds them to the Excel spreadsheet
    70.     For i = 1 To 3
    71.         Set xlChartArray(i) = xlApp.Charts.Add
    72.         Call CreateXLChart(xlSheet, xlChartArray(i), StartPosition(i), xlColumnStacked, "Sheet 1")
    73.     Next i
    74.    
    75.     ' Moves the charts to an appropriate position and sizes them
    76.     Call MoveXLCharts(xlSheet, 1, 30, 1, 500, 300)
    77.     Call MoveXLCharts(xlSheet, 2, 340, 1, 500, 300)
    78.     Call MoveXLCharts(xlSheet, 3, 650, 1, 500, 300)
    79.    
    80.     ' Custom format the first chart
    81.     With xlSheet.ChartObjects(1).Chart
    82.         .Axes(xlCategory, xlPrimary).CategoryType = xlCategoryScale
    83.         .PlotArea.ClearFormats
    84.         .HasTitle = True
    85.         .HasLegend = False
    86.         .ChartTitle.Characters.Text = "Applications Received"
    87.         .ChartTitle.Font.Size = 8
    88.         .Axes(xlValue).TickLabels.Font.Size = 9
    89.         .HasDataTable = True
    90.         With .DataTable
    91.             .ShowLegendKey = True
    92.             .Font.Size = 9
    93.         End With
    94.         ' Changes 'Other Protection' series color to red
    95.         .SeriesCollection(4).Interior.ColorIndex = 6
    96.         ' Changes 'Term' series color to light green
    97.         .SeriesCollection(3).Interior.ColorIndex = 24
    98.         ' Changes 'MLI' series color to bluey-purple
    99.         .SeriesCollection(2).Interior.ColorIndex = 22
    100.         ' Changes 'PTA' series color to pale yellow
    101.         .SeriesCollection(5).Interior.ColorIndex = 3
    102.         ' Changes 'Low Touch' series color to white
    103.         .SeriesCollection(6).Interior.ColorIndex = 2
    104.         ' Removes the prop total series from the graph but not
    105.         ' from the data table
    106.         With .SeriesCollection(1)
    107.             .ChartType = xlLine
    108.             .Border.Weight = xlThin
    109.             .Border.LineStyle = xlNone
    110.         End With
    111.     End With
    112.    
    113.     ' Custom format the second chart
    114.     With xlSheet.ChartObjects(2).Chart
    115.         .Axes(xlCategory, xlPrimary).CategoryType = xlCategoryScale
    116.         .PlotArea.ClearFormats
    117.         .HasTitle = True
    118.         .HasLegend = False
    119.         .ChartTitle.Characters.Text = "Cases Accepted - UW Decision Made"
    120.         .ChartTitle.Font.Size = 8
    121.         .Axes(xlValue).TickLabels.Font.Size = 9
    122.         .HasDataTable = True
    123.         .DataTable.ShowLegendKey = True
    124.         .DataTable.Font.Size = 9
    125.     End With
    126.    
    127.     ' Custom format the third chart
    128.     With xlSheet.ChartObjects(3).Chart
    129.         .Axes(xlCategory, xlPrimary).CategoryType = xlCategoryScale
    130.         .PlotArea.ClearFormats
    131.         .HasTitle = True
    132.         .HasLegend = False
    133.         .ChartTitle.Characters.Text = "Applications Issued"
    134.         .ChartTitle.Font.Size = 8
    135.         .Axes(xlValue).TickLabels.Font.Size = 9
    136.         .HasDataTable = True
    137.         With .DataTable
    138.             .ShowLegendKey = True
    139.             .Font.Size = 9
    140.         End With
    141.         .SeriesCollection(3).Interior.ColorIndex = 6
    142.         .SeriesCollection(4).Interior.ColorIndex = 3
    143.         .SeriesCollection(5).Interior.ColorIndex = 2
    144.         .SeriesCollection(6).Interior.ColorIndex = 15
    145.     End With
    146.    
    147.     ' Grab the rundate off the server since we need it for the
    148.     ' report title 'as at' value
    149.     Dim strDate As String
    150.     Set objRS = cnConn.Execute("SELECT RunDate FROM DateRanges")
    151.     strDate = objRS.Fields(0).Value
    152.    
    153.     ' Set up report titles
    154.     Call CreateReportTitles(xlSheet, "A1:E2", xlGeneral, "NB Protection Volumes As At: " & strDate, 12)
    155.     Call CreateReportTitles(xlSheet, "F1:J1", 4, GetgVarPrimInfoValue(), 8)
    156.     Call CreateReportTitles(xlSheet, "F2:J2", 4, AdditionalInfo(GetgVarAddInfoType(), GetgVarAddInfoValue()), 8)
    157.    
    158.     ' Sets up page margins and forces the data all onto one page.
    159.     With xlSheet.PageSetup
    160.         .LeftMargin = 0.4
    161.         .RightMargin = 0.4
    162.         .Zoom = False
    163.         .FitToPagesTall = 1
    164.         .FitToPagesWide = 1
    165.     End With
    166.    
    167.     ' Cells in the given range will have a white font
    168.     xlSheet.Range("A4:I60").Font.ColorIndex = 2
    169.    
    170.     ' Makes Excel visible
    171.     xlApp.Visible = True
    172.    
    173.     Call LoadCaption(False)
    174.    
    175.     ' Destroy objects
    176.     For i = 0 To UBound(strSproc)
    177.         objRSArray(i).Close
    178.         Set objRSArray(i) = Nothing
    179.     Next i
    180.     Set objRS = Nothing
    181.     Set xlChartArray(0) = Nothing
    182.     Set xlApp = Nothing
    183.     Set xlBook = Nothing
    184.     Set xlSheet = Nothing
    185. End Sub

    UnpackString takes the comma-delimited list of three stored procedures that are the sources for the three graphs and presents them in a way that VB can deal with them:

    VB Code:
    1. Public Function UnpackString(strVal As String)
    2.    
    3.     Dim rst As ADODB.Recordset
    4.     Dim strArray() As String
    5.     Dim intMemCount As Integer
    6.    
    7.     Set rst = New ADODB.Recordset
    8.     rst.Open strVal, cnConn, adOpenForwardOnly, adLockReadOnly, adCmdText
    9.    
    10.     strArray = Split(rst.GetString, ",")
    11.     intMemCount = UBound(strArray)
    12.  
    13.     ' CleanString cuts off the unwanted gremlin character at the end
    14.     strArray(intMemCount) = CleanString(strArray(intMemCount))
    15.     UnpackString = strArray
    16.  
    17.     rst.Close
    18.     Set rst = Nothing
    19.    
    20. End Function

    MoveDataExcel:

    VB Code:
    1. Public Sub MoveDataExcel(rstExport As ADODB.Recordset, xlSheet As Object, intStartLine As Integer)
    2.  
    3.     Dim i As Integer
    4.     For i = 0 To rstExport.Fields.Count - 1
    5.         xlSheet.Cells(intStartLine, i + 1).Value = rstExport.Fields(i).Name
    6.     Next i
    7.    
    8.     xlSheet.Range("A" & intStartLine + 1).CopyFromRecordset rstExport
    9.    
    10. End Sub

    MoveXLCharts:

    VB Code:
    1. Public Sub MoveXLCharts(xlSheet As Object, chartNum As Integer, _
    2.     Top, Left, Width, Height As Integer)
    3.  
    4.     With xlSheet
    5.         With .ChartObjects(chartNum)
    6.             .Top = Top
    7.             .Left = Left
    8.             .Width = Width
    9.             .Height = Height
    10.         End With
    11.     End With
    12.    
    13. End Sub

  2. #2
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Sharing the horror of my Excel report export code

    I'll go in reverse order again!

    In MoveXLCharts, you havent set data types for some of the parameters, and you do not need both 'With' blocks - just one will do it.
    VB Code:
    1. Public Sub MoveXLCharts(xlSheet As Object, chartNum As Integer, _
    2.                         Top [b]As Integer[/b], Left [b]As Integer[/b], Width [b]As Integer[/b], Height As Integer)
    3.  
    4.     With xlSheet.ChartObjects(chartNum)
    5.       .Top = Top
    6. ...
    I think UnpackString and MoveDataExcel are fine.

    And now on to CreateExcelWS...

    You have declared strSource with a specific number of elements, and fill it based on an array which comes from another function (UnpackString). If the amount of data returned ever increases, you will get an error. I would use a dynamic array instead (as you have for strSproc), and ReDim it to the UBound of the other array.

    I notice that you have declared your Excel related variables "as Object", so I presume you are using Late Binding. If this is the case, you need to declare all of the constants you use (such as xlLine and xlThin). If you haven't done this already, I would recommend using the module that is linked from post #13 of my Excel tutorial.

    When working with Excel you should avoid the use of ActiveAnything and Selection, as they can cause errors seemingly randomly (depending on what the user is doing at the time). Here is an amended version which will not have any problems:
    VB Code:
    1. Set xlSheet = xlBook[b].Sheets(1)[/b]

    In the sections "Custom format the ? chart", you repeat a large chunk of identical code for all three - so that could be in a loop, eg:
    VB Code:
    1. 'Set common formats for the charts
    2.     For i = 1 To 3
    3.       With xlSheet.ChartObjects(i).Chart
    4.           .Axes(xlCategory, xlPrimary).CategoryType = xlCategoryScale
    5.           .PlotArea.ClearFormats
    6.           .HasTitle = True
    7.           .HasLegend = False
    8.           .ChartTitle.Font.Size = 8
    9.           .Axes(xlValue).TickLabels.Font.Size = 9
    10.           .HasDataTable = True
    11.           .DataTable.ShowLegendKey = True
    12.           .DataTable.Font.Size = 9
    13.       End With
    14.     Next i
    15.  
    16.     ' Custom format the first chart
    17.     With xlSheet.ChartObjects(1).Chart
    18.         .ChartTitle.Characters.Text = "Applications Received"
    19.         ' Changes 'Other Protection' series color to red
    20.         .SeriesCollection(4).Interior.ColorIndex = 6
    21.         ' Changes 'Term' series color to light green
    22.         .SeriesCollection(3).Interior.ColorIndex = 24
    23.         ' Changes 'MLI' series color to bluey-purple
    24.         .SeriesCollection(2).Interior.ColorIndex = 22
    25.         ' Changes 'PTA' series color to pale yellow
    26.         .SeriesCollection(5).Interior.ColorIndex = 3
    27.         ' Changes 'Low Touch' series color to white
    28.         .SeriesCollection(6).Interior.ColorIndex = 2
    29.         ' Removes the prop total series from the graph but not
    30.         ' from the data table
    31.         With .SeriesCollection(1)
    32.             .ChartType = xlLine
    33.             .Border.Weight = xlThin
    34.             .Border.LineStyle = xlNone
    35.         End With
    36.     End With
    37.    
    38.     ' Custom format the second chart
    39.     With xlSheet.ChartObjects(2).Chart
    40.         .ChartTitle.Characters.Text = "Cases Accepted - UW Decision Made"
    41.     End With
    42.    
    43.     ' Custom format the third chart
    44.     With xlSheet.ChartObjects(3).Chart
    45.         .ChartTitle.Characters.Text = "Applications Issued"
    46.         .SeriesCollection(3).Interior.ColorIndex = 6
    47.         .SeriesCollection(4).Interior.ColorIndex = 3
    48.         .SeriesCollection(5).Interior.ColorIndex = 2
    49.         .SeriesCollection(6).Interior.ColorIndex = 15
    50.     End With

    For opening the recordset near the end, you use cnConn.Execute.. I would prefer to use the objRS.Open method (for consistency at least), but it will work either way. Note that you do not .Close it when you are finished with it - and you need to.


    The DeriveWhereClause function is a bit of a "black box", I'm surprised to not see any parameters to it - but I guess that depends on what it does (if it is based on values from controls, it makes sense).

    You also haven't shown us CreateXLChart (I hope you are setting the location in it!), or CreateReportTitles.

  3. #3

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2006
    Location
    USA
    Posts
    476

    Re: Sharing the horror of my Excel report export code

    Quote Originally Posted by si_the_geek
    I'll go in reverse order again!

    In MoveXLCharts, you havent set data types for some of the parameters, and you do not need both 'With' blocks - just one will do it.
    VB Code:
    1. Public Sub MoveXLCharts(xlSheet As Object, chartNum As Integer, _
    2.                         Top [b]As Integer[/b], Left [b]As Integer[/b], Width [b]As Integer[/b], Height As Integer)
    3.  
    4.     With xlSheet.ChartObjects(chartNum)
    5.       .Top = Top
    6. ...
    I think UnpackString and MoveDataExcel are fine.
    Hehehe, dumb me...I thought that if I gave it a list of parameters and just specified the last one as an integer it would assume that they were all integers. Doh!

    And now on to CreateExcelWS...

    You have declared strSource with a specific number of elements, and fill it based on an array which comes from another function (UnpackString). If the amount of data returned ever increases, you will get an error. I would use a dynamic array instead (as you have for strSproc), and ReDim it to the UBound of the other array.
    Good idea.

    I notice that you have declared your Excel related variables "as Object", so I presume you are using Late Binding. If this is the case, you need to declare all of the constants you use (such as xlLine and xlThin). If you haven't done this already, I would recommend using the module that is linked from post #13 of my Excel tutorial.
    Yep, I'm using late binding as recommended by many on this board. There's an entire module in the project that contains nothing but Excel constants that I downloaded from Microsoft's site.

    When working with Excel you should avoid the use of ActiveAnything and Selection, as they can cause errors seemingly randomly (depending on what the user is doing at the time). Here is an amended version which will not have any problems:
    VB Code:
    1. Set xlSheet = xlBook[b].Sheets(1)[/b]
    Yeah, I don't like Active or Selection but I don't know the Excel object model that well. I'll research those and take them out but it might take a while; we've got about a dozen custom Excel subs similar to this one. We have two kinds of reports...reports presented as just a spreadsheet of data and reports with graphs and other chunks of data scattered around. The spreadsheet types are handled by a single sub; all the others have their own custom subs.


    In the sections "Custom format the ? chart", you repeat a large chunk of identical code for all three - so that could be in a loop, eg:
    VB Code:
    1. 'Set common formats for the charts
    2.     For i = 1 To 3
    3.       With xlSheet.ChartObjects(i).Chart
    4.           .Axes(xlCategory, xlPrimary).CategoryType = xlCategoryScale
    5.           .PlotArea.ClearFormats
    6.           .HasTitle = True
    7.           .HasLegend = False
    8.           .ChartTitle.Font.Size = 8
    9.           .Axes(xlValue).TickLabels.Font.Size = 9
    10.           .HasDataTable = True
    11.           .DataTable.ShowLegendKey = True
    12.           .DataTable.Font.Size = 9
    13.       End With
    14.     Next i
    15.  
    16.     ' Custom format the first chart
    17.     With xlSheet.ChartObjects(1).Chart
    18.         .ChartTitle.Characters.Text = "Applications Received"
    19.         ' Changes 'Other Protection' series color to red
    20.         .SeriesCollection(4).Interior.ColorIndex = 6
    21.         ' Changes 'Term' series color to light green
    22.         .SeriesCollection(3).Interior.ColorIndex = 24
    23.         ' Changes 'MLI' series color to bluey-purple
    24.         .SeriesCollection(2).Interior.ColorIndex = 22
    25.         ' Changes 'PTA' series color to pale yellow
    26.         .SeriesCollection(5).Interior.ColorIndex = 3
    27.         ' Changes 'Low Touch' series color to white
    28.         .SeriesCollection(6).Interior.ColorIndex = 2
    29.         ' Removes the prop total series from the graph but not
    30.         ' from the data table
    31.         With .SeriesCollection(1)
    32.             .ChartType = xlLine
    33.             .Border.Weight = xlThin
    34.             .Border.LineStyle = xlNone
    35.         End With
    36.     End With
    37.    
    38.     ' Custom format the second chart
    39.     With xlSheet.ChartObjects(2).Chart
    40.         .ChartTitle.Characters.Text = "Cases Accepted - UW Decision Made"
    41.     End With
    42.    
    43.     ' Custom format the third chart
    44.     With xlSheet.ChartObjects(3).Chart
    45.         .ChartTitle.Characters.Text = "Applications Issued"
    46.         .SeriesCollection(3).Interior.ColorIndex = 6
    47.         .SeriesCollection(4).Interior.ColorIndex = 3
    48.         .SeriesCollection(5).Interior.ColorIndex = 2
    49.         .SeriesCollection(6).Interior.ColorIndex = 15
    50.     End With

    For opening the recordset near the end, you use cnConn.Execute.. I would prefer to use the objRS.Open method (for consistency at least), but it will work either way. Note that you do not .Close it when you are finished with it - and you need to.
    Cool, thanks.

    The DeriveWhereClause function is a bit of a "black box", I'm surprised to not see any parameters to it - but I guess that depends on what it does (if it is based on values from controls, it makes sense).
    The DeriveWhereClause() function doesn't use parameters; it gets its information from global variables that grab the selections the users make on the form; it's actually fed by a couple of other functions that build the SQL strings that the program uses. I could post those at another date so you can recoil in horror!

    You also haven't shown us CreateXLChart (I hope you are setting the location in it!), or CreateReportTitles.
    I didn't show those cos I didn't think they were overly important but I can post them tomorrow if you like. CreateXLChart does define the report's location.

    This is actually fun...I'm learning a ton.

  4. #4
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Sharing the horror of my Excel report export code

    Quote Originally Posted by disruptivehair
    Hehehe, dumb me...I thought that if I gave it a list of parameters and just specified the last one as an integer it would assume that they were all integers. Doh!
    That's a common misconception about "Classic" VB - other languages allow you to specify one data type for a group of variables/parameters, but for VB you have to specify each one. If you don't, they are declared as Variant.

    Yeah, I don't like Active or Selection but I don't know the Excel object model that well. I'll research those and take them out but it might take a while;
    Well there's only the one in this sub, so hopefully it wont take you too long for the others.

    The DeriveWhereClause() function doesn't use parameters; it gets its information from global variables that grab the selections the users make on the form; it's actually fed by a couple of other functions that build the SQL strings that the program uses. I could post those at another date so you can recoil in horror!
    That sounds painful!

    I didn't show those cos I didn't think they were overly important but I can post them tomorrow if you like. CreateXLChart does define the report's location.
    Feel free, I'll tear them apart too!

    This is actually fun...I'm learning a ton.
    Good stuff

    It's nice to have a focus on "how to improve" every now and then, rather than getting things done ASAP, or just learning enough of something to get it working.

  5. #5

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2006
    Location
    USA
    Posts
    476

    Re: Sharing the horror of my Excel report export code

    Quote Originally Posted by si_the_geek
    You also haven't shown us CreateXLChart (I hope you are setting the location in it!), or CreateReportTitles.
    CreateXLChart:

    VB Code:
    1. Public Sub CreateXLChart(xlSheetF As Object, xlChartF As Object, RowNum As Integer, _
    2.     ChartType As String, ReportName As String)
    3.        
    4.         With xlChartF
    5.             .ChartType = ChartType
    6.             .SetSourceData xlSheetF.Cells(RowNum, 1).CurrentRegion
    7.             .PlotBy = xlColumns
    8.             .Location Where:=xlLocationAsObject, Name:=ReportName
    9.         End With
    10.    
    11. End Sub

    CreateReportTitles:

    VB Code:
    1. Public Sub CreateReportTitles(xlSheetF As Object, strRange As String, hAlign As Variant, _
    2.     strVal As String, fSize As Integer)
    3.    
    4.     With xlSheetF
    5.         With .Range(strRange)
    6.             .HorizontalAlignment = hAlign
    7.             .VerticalAlignment = xlCenter
    8.             .WrapText = True
    9.             .MergeCells = True
    10.             .Value = strVal
    11.             .Font.Bold = True
    12.             .Font.Size = fSize
    13.         End With
    14.     End With
    15. End Sub

  6. #6

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2006
    Location
    USA
    Posts
    476

    It's broken!

    I broke my code!

    VB Code:
    1. Public Sub CreateExcelWSBROKEN(strsql As String)
    2.  
    3.     Call LoadCaption(True)
    4.     Call CheckConnection
    5.    
    6.     Dim objRSArray() As ADODB.Recordset
    7.     Dim objRS As ADODB.Recordset
    8.    
    9.     Dim xlApp As Object
    10.     Dim xlBook As Object
    11.     Dim xlSheet As Object
    12.     Dim xlChartArray() As Object
    13.    
    14.     Dim i As Integer
    15.     Dim strSource() As String
    16.     Dim strParameter As String
    17.     Dim strSproc() As String
    18.     Dim StartPosition() As Integer
    19.    
    20.     ' Checks to see if Excel is installed and if there is already an
    21.     ' instance of it; if there is then the current instance is used,
    22.     ' if not a new one is created.  If Excel is not installed an
    23.     ' error is displayed.
    24.     If IsExcelInstalled = True And IsExcelRunning = False Then
    25.         Set xlApp = CreateObject("Excel.Application")
    26.     Else
    27.         Set xlApp = GetObject(, "Excel.Application")
    28.     End If
    29.    
    30.     ' Instantiates Excel objects
    31.     Set xlBook = xlApp.Workbooks.Add
    32.     'Set xlSheet = xlBook.Sheets(1)
    33.     Set xlSheet = xlBook.ActiveSheet
    34.     'xlSheet.Name = Left$(GetgVarReportSelected(), 30)
    35.     xlSheet.Name = "Sheet 1"
    36.    
    37.     ' Calls UnpackString() function and assigns the output to the strSproc array
    38.     strSproc = UnpackString("SELECT SQLObject FROM tblReports WHERE ReportName = 'Weekly Summary'")
    39.    
    40.     ' Calls the DeriveWhereClause() function and assigns the output to strParameter
    41.     strParameter = DeriveWhereClause()
    42.    
    43.     ReDim strSource(UBound(strSproc))
    44.    
    45.     ' Sets up strSource array using the strSproc array
    46.     For i = 0 To UBound(strSproc)
    47.         strSource(i) = "EXEC " & strSproc(i) & " @Filter = " & "'" & strParameter & "'"
    48.     Next i
    49.    
    50.     ReDim objRSArray(UBound(strSproc))
    51.    
    52.     ' Instantiates and opens the members of the recordset array and sets the
    53.     ' cursorlocation property so that we can use the recordcount property later on.
    54.     For i = 0 To UBound(strSproc)
    55.         Set objRSArray(i) = New ADODB.Recordset
    56.         objRSArray(i).CursorLocation = adUseClient
    57.         objRSArray(i).Open strSource(i), cnConn, adOpenForwardOnly, adLockReadOnly, adCmdText
    58.     Next i
    59.    
    60.     ' Redims and initializes StartPosition() and moves data to Excel; starting position
    61.     ' is determined by sizes of recordsets
    62.     ReDim StartPosition(UBound(objRSArray))
    63.    
    64.     ' First chart
    65.     StartPosition(0) = 4
    66.     Call MoveDataExcel(objRSArray(0), xlSheet, StartPosition(0))
    67.     ' Second chart
    68.     StartPosition(1) = StartPosition(0) + 2 + objRSArray(0).RecordCount
    69.     Call MoveDataExcel(objRSArray(1), xlSheet, StartPosition(1))
    70.     ' Third chart
    71.     StartPosition(2) = StartPosition(1) + 2 + objRSArray(1).RecordCount
    72.     Call MoveDataExcel(objRSArray(2), xlSheet, StartPosition(2))
    73.    
    74.     ReDim xlChartArray(UBound(objRSArray))
    75.    
    76.     ' Redims and initializes xlChartArray() and adds them to the Excel worksheet
    77. '    For i = 0 To UBound(xlChartArray)
    78. '        Set xlChartArray(i) = xlApp.Charts.Add
    79. '        Call CreateXLChart(xlSheet, xlChartArray(i), StartPosition(i), xlColumnStacked, "Sheet 1")
    80. '    Next i
    81.    
    82.     For i = 0 To UBound(xlChartArray)
    83.         Set xlChartArray(i) = xlApp.Charts.Add
    84.     Next i
    85. [COLOR=DarkRed][B]    Call CreateXLChart(xlSheet, xlChartArray(0), StartPosition(0), xlColumnStacked, "WS")[/B][/COLOR]
    86.         xlApp.Visible = True
    87.  
    88.     Exit Sub
    89.    
    90.     ' Moves the charts to an appropriate location and sizes them
    91.     Call MoveXLCharts(xlSheet, 0, 30, 1, 500, 300)
    92.     Call MoveXLCharts(xlSheet, 1, 340, 1, 500, 300)
    93.     Call MoveXLCharts(xlSheet, 2, 650, 1, 500, 300)
    94.    
    95.  
    96.    
    97.     Set xlApp = Nothing
    98.     Set xlBook = Nothing
    99.     Set xlSheet = Nothing
    100.     Erase objRSArray
    101.     Erase xlChartArray
    102.     Erase StartPosition
    103.     Erase strSource
    104.     Erase strSproc
    105.    
    106. End Sub

    It bombs out on the bolded line and highlights the location line in CreateXLChart:

    VB Code:
    1. Public Sub CreateXLChart(xlSheetF As Object, xlChartF As Object, RowNum As Integer, _
    2.     ChartType As String, ReportName As String)
    3.        
    4.         With xlChartF
    5.             .ChartType = ChartType
    6.             .SetSourceData xlSheetF.Cells(RowNum, 1).CurrentRegion
    7.             .PlotBy = xlColumns
    8.             [COLOR=DarkRed][B].Location Where:=xlLocationAsObject, Name:=ReportName[/B][/COLOR]
    9.         End With
    10.    
    11. End Sub

    The error is:

    'Run-time error '1004':

    Application-defined or object-defined error'

    The original code I posted works but this code doesn't. I've been pounding my head on the desk for an hour trying different things. First thing I did was check that all the SQL strings are running correctly and returning data, since normally when I see an error 1004 it's because I tried to pass Excel a data set that's too small or empty.

  7. #7
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Sharing the horror of my Excel report export code

    CreateXLChart is fine, and the only thing in CreateReportTitles is that you could use a single With block (like with MoveXLCharts).


    The current problem seems to be that you have changed "Sheet 1" to "WS". I presume it would be best to use xlSheet.Name instead of a fixed string (that way any changes to the name in the rest of the code are irrelevant).

    I can also see another potential problem - in the calls to MoveXLCharts you have changed the numbering from 1+ to 0+, which may well be an issue as ChartObjects (in MoveXLCharts) is a collection (1 based) rather than an array (0 based). How annoying!

  8. #8

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2006
    Location
    USA
    Posts
    476

    Re: Sharing the horror of my Excel report export code

    Quote Originally Posted by si_the_geek
    CreateXLChart is fine, and the only thing in CreateReportTitles is that you could use a single With block (like with MoveXLCharts).


    The current problem seems to be that you have changed "Sheet 1" to "WS". I presume it would be best to use xlSheet.Name instead of a fixed string (that way any changes to the name in the rest of the code are irrelevant).

    I can also see another potential problem - in the calls to MoveXLCharts you have changed the numbering from 1+ to 0+, which may well be an issue as ChartObjects (in MoveXLCharts) is a collection (1 based) rather than an array (0 based). How annoying!
    The prob is that when I instantiate the chart object it's creating three new charts as brand-new worksheets in the app! Eeeeek!

  9. #9
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Sharing the horror of my Excel report export code

    As both code samples are the same up to that point (apart from the array indexes), the only possible thing I can see is that the name is getting confused somehow.. all I can suggest is to either hard-code it to the same name as at the top of the code, or use the 'dynamic' version I described, eg:
    VB Code:
    1. Call CreateXLChart(xlSheet, xlChartArray(0), StartPosition(0), xlColumnStacked, [u]"Sheet 1"[/u])
    2.     Call CreateXLChart(xlSheet, xlChartArray(0), StartPosition(0), xlColumnStacked, [u]xlSheet.Name[/u])  '(no quotes)
    ..if neither of those work, I'd recommend starting a new thread about it in the Office Development forum - as something is wrong.

  10. #10

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2006
    Location
    USA
    Posts
    476

    Re: Sharing the horror of my Excel report export code

    Quote Originally Posted by si_the_geek
    As both code samples are the same up to that point (apart from the array indexes), the only possible thing I can see is that the name is getting confused somehow.. all I can suggest is to either hard-code it to the same name as at the top of the code, or use the 'dynamic' version I described, eg:
    VB Code:
    1. Call CreateXLChart(xlSheet, xlChartArray(0), StartPosition(0), xlColumnStacked, [u]"Sheet 1"[/u])
    2.     Call CreateXLChart(xlSheet, xlChartArray(0), StartPosition(0), xlColumnStacked, [u]xlSheet.Name[/u])  '(no quotes)
    ..if neither of those work, I'd recommend starting a new thread about it in the Office Development forum - as something is wrong.
    Thanks si, I'll try that; I'm sure it's something I'm doing since the old sub still works.

  11. #11

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2006
    Location
    USA
    Posts
    476

    Re: Sharing the horror of my Excel report export code

    OK si, how does this look?

    VB Code:
    1. Public Sub CreateExcelWS(strSQL As String)
    2.  
    3.     ' Sets loading caption on on the CriteriaSelection form and checks the
    4.     ' connection to the SQL Server
    5.     Call LoadCaption(True)
    6.     Call CheckConnection
    7.    
    8.     ' ADO recordset array and Excel objects
    9.     Dim objRSArray() As ADODB.Recordset
    10.     Dim xlApp As Object
    11.     Dim xlBook As Object
    12.     Dim xlSheet As Object
    13.     Dim xlChartArray() As Object
    14.    
    15.     ' Variables
    16.     Dim i As Integer
    17.     Dim strSource() As String
    18.     Dim strSproc() As String
    19.     Dim StartPosition() As Integer
    20.     Dim strReportName As String
    21.    
    22.     ' Checks to see if Excel is installed and if there is an instance of it;
    23.     ' if there is an instance the sub uses the current one, if there isn't
    24.     ' then the sub creates one.
    25.     If IsExcelInstalled = True And IsExcelRunning = False Then
    26.         Set xlApp = CreateObject("Excel.Application")
    27.     Else
    28.         Set xlApp = GetObject(, "Excel.Application")
    29.     End If
    30.    
    31.     ' Instantiate Excel objects
    32.     Set xlBook = xlApp.Workbooks.Add
    33.     Set xlSheet = xlBook.Sheets(1)
    34.     strReportName = Left$(GetgVarReportSelected(), 30)
    35.     xlSheet.Name = strReportName
    36.    
    37.     ' Calls UnpackString() function and assigns the output to the strSproc array
    38.     strSproc = UnpackString("SELECT SQLObject FROM tblReports WHERE ReportName = 'Weekly Summary'")
    39.    
    40.     ' Sizes the strSource array to be the same size as strSproc
    41.     ' The strSource array holds the SQL strings that will grab the data from the server
    42.     ReDim strSource(UBound(strSproc))
    43.     For i = 0 To UBound(strSproc)
    44.         strSource(i) = "EXEC " & strSproc(i) & " @Filter = " & "'" & DeriveWhereClause() & "'"
    45.     Next i
    46.    
    47.     ' Sets up the ADO recordsets (same number as there are names of stored procedures) and
    48.     ' uses the members of strSource() to open them
    49.     ReDim objRSArray(UBound(strSproc))
    50.     For i = 0 To UBound(objRSArray)
    51.         Set objRSArray(i) = New ADODB.Recordset
    52.         objRSArray(i).CursorLocation = adUseClient
    53.         objRSArray(i).Open strSource(i), cnConn, adOpenForwardOnly, adLockReadOnly, adCmdText
    54.     Next i
    55.    
    56.     ' StartPosition() starts at row 4 and uses the sizes of the data sets and values of
    57.     ' other members of StartPosition() to determine where to place the data.  The MoveDataExcel()
    58.     ' sub actually places the data onto the Excel spreadsheet.
    59.     ReDim StartPosition(UBound(objRSArray))
    60.     StartPosition(0) = 4
    61.     Call MoveDataExcel(objRSArray(0), xlSheet, StartPosition(0))
    62.     StartPosition(1) = StartPosition(0) + 2 + objRSArray(0).RecordCount
    63.     Call MoveDataExcel(objRSArray(1), xlSheet, StartPosition(1))
    64.     StartPosition(2) = StartPosition(1) + 2 + objRSArray(1).RecordCount
    65.     Call MoveDataExcel(objRSArray(2), xlSheet, StartPosition(2))
    66.    
    67.     For i = 0 To UBound(objRSArray)
    68.         objRSArray(i).Close
    69.     Next i
    70.    
    71.     ' Redimensions xlChartArray() array, instantiates chart objects, and adds them to the
    72.     ' Excel spreadsheet
    73.     ReDim xlChartArray(UBound(objRSArray))
    74.     For i = 0 To UBound(xlChartArray)
    75.         Set xlChartArray(i) = xlApp.Charts.Add
    76.         Call CreateXLChart(xlSheet, xlChartArray(i), StartPosition(i), xlColumnStacked, strReportName)
    77.     Next i
    78.    
    79.     Call MoveXLCharts(xlSheet, 1, 30, 1, 500, 300)
    80.     Call MoveXLCharts(xlSheet, 2, 340, 1, 500, 300)
    81.     Call MoveXLCharts(xlSheet, 3, 650, 1, 500, 300)
    82.    
    83.     ' Each chart is a bit different but this loop performs all the actions that are
    84.     ' done to each chart
    85.     For i = 0 To UBound(xlChartArray)
    86.         With xlSheet.ChartObjects(i + 1).Chart
    87.             .Axes(xlCategory, xlPrimary).CategoryType = xlCategoryScale
    88.             .PlotArea.ClearFormats
    89.             .HasTitle = True
    90.             .HasLegend = False
    91.             .Axes(xlValue).TickLabels.Font.Size = 9
    92.             .HasDataTable = True
    93.             With .DataTable
    94.                 .ShowLegendKey = True
    95.                 .Font.Size = 9
    96.             End With
    97.         End With
    98.     Next i
    99.    
    100.     With xlSheet
    101.         With .ChartObjects(1).Chart
    102.             .ChartTitle.Characters.Text = "Applications Received"
    103.             .ChartTitle.Font.Size = 8
    104.             .SeriesCollection(4).Interior.ColorIndex = 6
    105.             .SeriesCollection(3).Interior.ColorIndex = 24
    106.             .SeriesCollection(2).Interior.ColorIndex = 22
    107.             .SeriesCollection(5).Interior.ColorIndex = 3
    108.             .SeriesCollection(6).Interior.ColorIndex = 2
    109.             With .SeriesCollection(1)
    110.                 .ChartType = xlLine
    111.                 .Border.Weight = xlThin
    112.                 .Border.LineStyle = xlNone
    113.             End With
    114.         End With
    115.         With .ChartObjects(2).Chart
    116.             .ChartTitle.Characters.Text = "Cases Accepted - UW Decision Made"
    117.             .ChartTitle.Font.Size = 8
    118.         End With
    119.         With .ChartObjects(3).Chart
    120.             .ChartTitle.Characters.Text = "Applications Issued"
    121.             .ChartTitle.Font.Size = 8
    122.             .SeriesCollection(3).Interior.ColorIndex = 6
    123.             .SeriesCollection(4).Interior.ColorIndex = 3
    124.             .SeriesCollection(5).Interior.ColorIndex = 2
    125.             .SeriesCollection(6).Interior.ColorIndex = 15
    126.         End With
    127.     End With
    128.    
    129.     Call CreateReportTitles(xlSheet, "A1:E2", xlGeneral, "NB Protection Volumes As At: " & GetRunDate, 12)
    130.     Call CreateReportTitles(xlSheet, "F1:J1", 4, GetgVarPrimInfoValue(), 8)
    131.     Call CreateReportTitles(xlSheet, "F2:J2", 4, AdditionalInfo(GetgVarAddInfoType(), GetgVarAddInfoValue()), 8)
    132.        
    133.     With xlSheet.PageSetup
    134.         .LeftMargin = 0.4
    135.         .RightMargin = 0.4
    136.         .Zoom = False
    137.         .FitToPagesTall = 1
    138.         .FitToPagesWide = 1
    139.     End With
    140.        
    141.     xlSheet.Range("A4:I60").Font.ColorIndex = 2
    142.    
    143.        
    144.     ' Sets caption on CriteriaSelection back to blank
    145.     Call LoadCaption(False)
    146.     xlApp.Visible = True
    147.    
    148.    
    149.     ' Destroy objects
    150.     Set xlApp = Nothing
    151.     Set xlBook = Nothing
    152.     Set xlSheet = Nothing
    153.     Erase objRSArray
    154.     Erase xlChartArray
    155.        
    156. End Sub

  12. #12
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Sharing the horror of my Excel report export code

    That all looks ok to me.

    Am I right in assuming that the problem is fixed now?

  13. #13

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2006
    Location
    USA
    Posts
    476

    Re: Sharing the horror of my Excel report export code

    Quote Originally Posted by si_the_geek
    That all looks ok to me.

    Am I right in assuming that the problem is fixed now?
    Yep, it's all working great now!

    I'd rep you but the system won't let me.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width