Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Add Line Number function to existing code 1

Status
Not open for further replies.

lespaul

Programmer
Feb 4, 2002
7,083
US
I have a spread sheet that Dale123321 helped develop. It takes raw data from my Delphi application and prints a report for our accounting department to use for paying jurors. I now have to add a line number to the report and since Dale's coding skills in Excel far exceed mine, I would like a little assistance in creating and adding this function.

The report takes the raw data and reviews it for people who are not getting any payment and then removes them. Then it copies all the remaining information from the Data Sheet to the Voucher Report Sheet. Then for each group of 50 it adds a subtotal section and for the last group (which may have 1 - 50 members) it adds the subtotal. I was thinking of adding a LineNumber function to the subtotal function that would number each line in the subtotal group from 1 - 50 (or in the case of the last group 1 - whatever).

Here is all the existing code (some of it relevant to this problem and some not), if you can help and would like to see the entire spreadsheet, please email and I'll be happy to send it to you.

(I emailed Dale to get his help first, but he's out of the office until early August and I can't wait that long!!).

Code:
Option Explicit

Sub Generate_VoucherRpt()
Dim nUsedRows As Long

  ' Clear target area
  IncrementVoucherNumber (Worksheets("Data").Range("VoucherNumber"))
  Worksheets("VoucherReport").Activate
  Worksheets("VoucherReport").Range("A3:F65536").EntireRow.Delete
  Application.ScreenUpdating = False
  Worksheets("Data").Activate
  ' Eliminate zero-value rows
  DeleteZeroRows Intersect(ActiveSheet.UsedRange, Range("A2:G65536"))
  ' Copy formulas from row 2 as far as needed
  nUsedRows = ActiveSheet.UsedRange.Rows.Count
  Worksheets("VoucherReport").Activate
  Range("A2:G2").Copy Destination:=Range("A3:A" & nUsedRows)
  ' Pretty up with subtotals
  InsertSubtotals
  ' Terminate
  Worksheets("Criteria").Range("jurorlist").Formula = "= CSVLIST(Data!H2:H275)"
  
  Application.CutCopyMode = False
  Application.ScreenUpdating = True
End Sub

Sub InsertSubtotals()
Const ROWS_PER_GROUP = 50
Const FIRST_COL = 3 ' Column "C"
Const LAST_COL = 7 ' Column "G"
Const SUMFORMULA = "=SUBTOTAL(9,R[-50]C:R[-1]C)"

Dim sLastSubtotalFormula As String
Dim sTotalFormula As String
Dim nRows As Long
Dim nPrintRow As Long
Dim nLastGroupRows As Integer
Dim nGroups As Integer
Dim i As Integer
Dim nInsertionRow As Long
Dim rInsertionPoint As Range

  nPrintRow = 2
  nRows = ActiveSheet.UsedRange.Rows.Count - 1
  nGroups = Int((nRows - 1) / ROWS_PER_GROUP) + 1
  ' Loop thru all groups but the last:
  For i = 1 To nGroups - 1
    nInsertionRow = i * ROWS_PER_GROUP + i * 2
    Set rInsertionPoint = Cells(nInsertionRow, 1)
    With rInsertionPoint
      .EntireRow.Insert Shift:=xlDown
      .EntireRow.Insert Shift:=xlDown
      .Offset(-2, 1) = "  Subtotals"
      Range(.Offset(-2, FIRST_COL - 1), .Offset(-2, LAST_COL - 1)).FormulaR1C1 = SUMFORMULA
      .Offset(-2, 0).EntireRow.Font.Bold = True
    End With
    Worksheets("VoucherReport").PageSetup.PrintArea = "A" & CStr(nPrintRow) & ":H" & CStr(nInsertionRow)
    'Worksheets("VoucherReport").PrintOut Copies:=1, Collate:=True
    ActiveSheet.PageSetup.PrintArea = ""
    nPrintRow = nInsertionRow + 2
    IncrementVoucherNumber (Worksheets("Data").Range("VoucherNumber"))
  Next i
  ' Do last group
  nInsertionRow = nGroups * 2 + nRows
  nLastGroupRows = nRows - ((nGroups - 1) * ROWS_PER_GROUP)
  Set rInsertionPoint = Cells(nInsertionRow, 1)
  sLastSubtotalFormula = "=SUBTOTAL(9,R[-" & nLastGroupRows & "]C:R[-1]C)"
  sTotalFormula = "=SUBTOTAL(9,R[-" & nInsertionRow & "]C:R[-1]C)"
  With rInsertionPoint
    .EntireRow.Insert Shift:=xlDown
    .EntireRow.Insert Shift:=xlDown
    .EntireRow.Insert Shift:=xlDown
    .EntireRow.Insert Shift:=xlDown
    .Offset(-4, 0) = "  Subtotals"
    Range(.Offset(-4, FIRST_COL - 1), .Offset(-4, LAST_COL - 1)).FormulaR1C1 = sLastSubtotalFormula
    .Offset(-4, 0).EntireRow.Font.Bold = True
    .Offset(-2, 0) = "     Totals"
    Range(.Offset(-2, FIRST_COL - 1), .Offset(-2, LAST_COL - 1)).FormulaR1C1 = sTotalFormula
    .Offset(-2, 0).EntireRow.Font.Bold = True
    Worksheets("VoucherReport").PageSetup.PrintArea = "A" & CStr(nPrintRow) & ":H" & CStr(nInsertionRow)
    'Worksheets("VoucherReport").PrintOut Copies:=1, Collate:=True
    ActiveSheet.PageSetup.PrintArea = ""
  End With

  Set rInsertionPoint = Nothing
 End Sub

Function DeleteZeroRows(ARange As Range) As Long
Dim rWorkingRange As Range
Dim rTestRange As Range
Dim nCountDeletes As Long
Dim nFirstRow As Long
Dim nLastRow As Long
Dim nFirstCol As Integer
Dim nLastCol As Integer
Dim nRow As Long
Dim nNewLastRow As Long
  
  Set rWorkingRange = ARange
  nFirstRow = rWorkingRange.Row
  nLastRow = rWorkingRange.Rows.Count + nFirstRow - 1
  nFirstCol = rWorkingRange.Column
  nLastCol = rWorkingRange.Columns.Count + nFirstCol - 1
  'Scan rows and delete where all zero
  For nRow = nLastRow To nFirstRow Step -1
    Set rTestRange = Range(Cells(nRow, nFirstCol), Cells(nRow, nLastCol))
    If SumText(rTestRange) = 0 Then
      rTestRange.EntireRow.Delete
      nCountDeletes = nCountDeletes + 1
    End If
  Next nRow
  'Wrap it up
  DeleteZeroRows = nCountDeletes
  Set rTestRange = Nothing
  Set rWorkingRange = Nothing
End Function

Function SumText(ARange As Range) As Double
Dim c As Range
  For Each c In ARange
    If IsNumeric(c.Text) Then
      SumText = SumText + c.Text
    End If
  Next c
End Function
Sub IncrementVoucherNumber(VoucherNumber As String)
' Assumes VoucherNumber format: nn-nnn-nnnnnn
Dim nSerial As Long
  nSerial = Right(VoucherNumber, 6)
  VoucherNumber = Left(VoucherNumber, 7) & (nSerial + 1)
  Worksheets("Data").Range("VoucherNumber") = VoucherNumber
End Sub
Function CSVList(ARange As Range) As String
Dim c As Range
  For Each c In ARange
    If c.Text <> &quot;&quot; Then
      If CSVList = &quot;&quot; Then
        CSVList = c.Text
      Else
        CSVList = CSVList + &quot;,&quot; + c.Text
      End If
    End If
  Next c
End Function

Leslie
landrews@metrocourt.state.nm.us

There are 10 types of people in the world -
those who understand binary
and
those who don't!
 
If you can identify which lines want line numbers based on something about the data (i.e. column &quot;C&quot; non-blank and not containing &quot;total&quot; or some such description), then it should be possible to add a call (just before data extraction) to a routine that would insert a new column &quot;A&quot; (if that's where you want it) and update the appropriate cells with your line numbers.

In any case, what's needed here is not your code, but a description (with examples) of the state of the worksheet immediately prior to the data extraction.

You didn't include the code that actually calls the CSVList function, so I can't tell how the range is defined, but the line numbers are added by inserting a column, that part of the code may need attention.
 
Here is a link to the existing spreadsheet:


(I hope it opens!)

All I need to do is on the Voucher Report, add a column number 1 - 50 through the first subtotal, number 1 - 50 from the first subtotal to the 2nd subtotal, and number 1 - 22 (in this instance, it may be 1 - 35, 1 - 48, etc) for the last set of jurors.

The CSVList function is used to populate a cell on the Criteria page to pass back to my Delphi application to do an insert query where the juror number is in the list.

I have already added the column and updated the subtotals section (not on the above link though) to move the formulas to the correct column. But now I need to fill in A2 - A52 with 1 - 50, A54 - A104 with 1 - 50, and A106 - the end with 1 - whatever.

Hope this makes sense!

Leslie
 
Leslie, I don't have time to work on this now, but you really should be able to do it yourself. Just loop thru the cells in column &quot;A&quot; and where there is a vendor name (and not &quot;Vendor&quot;), just add one to a counter as you go and poke the counter into the cell. when the counter gets to 50, set it back to zero.

Let me know how you do. If you can't get it, perhaps I will have some time tonight.
 
I'll keep working on it and post back with any advances! Thanks for your time.

leslie
 
Ok, I've come up with some thoughts if someone can help me implement them:

In the following piece of code (from the Sub InsertSubtotals above) I have my starting row (nPrintRow) and the ending Row (nInsertionRow) for each section to print. If I can loop through those rows and set the A column equal to a counter then I should be able to get the correct Line Number in Column A. (Additions and pseudo-code in blue)


Code:
Dim j as integer
Dim counter as integer

Code:
  nPrintRow = 2
  nRows = ActiveSheet.UsedRange.Rows.Count - 1
  nGroups = Int((nRows - 1) / ROWS_PER_GROUP) + 1
  ' Loop thru all groups but the last:
  For i = 1 To nGroups - 1
Code:
  counter = 1
Code:
nInsertionRow = i * ROWS_PER_GROUP + i * 2
Code:
For j = nPrintRow to nInsertionRow
Code:
set cellA & Cstr(j) = counter
  increment(counter)

The bolded sections are the ones I'm trying to get to work. Any help appreciated!

Thanks,
Leslie


Leslie
landrews@metrocourt.state.nm.us

There are 10 types of people in the world -
those who understand binary
and
those who don't!
 
Leslie, rather than trying to make a major change to a working routine, it is usually much easier and safer to insert a call to a new routine and put all of the new code in the new routine.

Here is a set-up along the lines I was trying to describe:
[blue]
Code:
Option Explicit

Sub MyMainProcess()
[green]
Code:
  '
  ' code to set up Voucher Report
  '
[/color]
Code:
  Call InsertLineNumbers
[green]
Code:
  '
  ' code to copy to .csv file
  '
[/color]
Code:
End Sub

Sub InsertLineNumbers()
Dim c As Range
Dim nLineNum As Integer
  Columns(&quot;A&quot;).Insert
  nLineNum = 0
  For Each c In Intersect(ActiveSheet.UsedRange, Range(&quot;C:C&quot;))
    If c.Offset(0, -1) <> &quot;Subtotals&quot; Then
      If c.Offset(0, -1) <> &quot;Totals&quot; Then
        If Not IsEmpty(c) Then
          nLineNum = nLineNum + 1
          c.Offset(0, -2) = nLineNum
        End If
      End If
    End If
    If nLineNum >= 50 Then
      nLineNum = 0
    End If
  Next c
End Sub
[/color]

I was guessing as to the column numbers involved. Also, your constants &quot;Subtotals&quot; and &quot;Totals&quot; appear to have some leading and/or trailing spaces, so adjust the code accordingly.
 
That works great! (except for....)

It puts the 1 in my title line instead on the first person in the list. I've tried fiddling around with the offsets, but couldn't quite get it.

I'm leaving for the day, but I'll check in from home or tomorrow morning.
Thanks for the help.

Leslie
 
It should be a simple matter to test for a starting row:
Code:
  For Each c In Intersect(ActiveSheet.UsedRange, Range(&quot;C:C&quot;))
[blue]
Code:
    If c.Row > 2 Then
[green]
Code:
' <--- Adjust starting row as necessary
[/color][/color]
Code:
      If c.Offset(0, -1) <> &quot;Subtotals&quot; Then
        If c.Offset(0, -1) <> &quot;Totals&quot; Then
          If Not IsEmpty(c) Then
            nLineNum = nLineNum + 1
            c.Offset(0, -2) = nLineNum
          End If
        End If
      End If
      If nLineNum >= 50 Then
        nLineNum = 0
      End If
[blue]
Code:
    End If
[/color]
Code:
  Next c
[/color]

 
Thanks! That did it!

Now, another question. In the DeleteZeroRows function, the idea is to go through all the rows in the Data Sheet and if the person has juror hours = 0 and juror pay = 0 and juror miles = 0 and juror mileagepay = 0 then remove them from the datasheet so that they do not appear on the Voucher Report.

The Voucher Report cells reference the Data Sheet:

Code:
VoucherReport!B2=Data!A2&CHAR(10)&&quot;    &quot;&Data!B2&CHAR(10)&&quot;    &quot;&Data!C2

For the first time yesterday, the first person on the datasheet met the requirements to be deleted, which then caused all the formulas in the first row on the Vouchersheet to be replaced with #REF! (this row is used to copy the formula to the correct number of rows).

Code:
Range(&quot;A2:G2&quot;).Copy Destination:=Range(&quot;A3:A&quot; & nUsedRows)

I can't copy the rows before the DeleteZeroRows, because I don't know how many rows I'm going to need until the zero rows are deleted.

Any ideas on how I can make sure the correct formula gets pasted so I don't have rows and rows of #REF!

Thanks,
Leslie


Leslie
landrews@metrocourt.state.nm.us

There are 10 types of people in the world -
those who understand binary
and
those who don't!
 
First, I'm surprised, my code addendum worked. As I was thinking about this last night, it seemed to me that the &quot;fix&quot; was only good for the first page. You probably would be better off to test for some data in the header row(s) to inhibit the numbering routine for that line.

Second, that is always a problem (keeping formulas on a sheet when deleting and inserting rows and/or columns). Seems to me that after you get the data in place (on the Voucher Report) you need to Copy and PasteSpecial/values to avoid that problem. Then go thru the data and delete the zero rows. Finally massage the data by inserting lines, subtotal formulas total formulas, row numbers, etc. after the sheet structure data has stabilized.
 
Since I'm adding the Line number before doing the subtotals, it works fine. It runs 1 - 50 then again 1 - 50 then 1 - 23. Then I insert the subtotal sections, set the print area and print the specific pages.

Here's the whole process:

Transfer data from Delphi to data sheet in excel
Delete any existing information from VoucherReport (A3:F65536)
Delete zero rows from data sheet (Row A2 deleted, screws up formulas on VoucherReport)
Count used rows on datasheet
copy formula VoucherReport!A2:F2 to A3 to used rows (copies screwed up formula 150+ times)
Add Line Numbers
Calculate number of groups (only 50 per printed section)
for each group
Insert Subtotal Rows
Set print area
Print

So is there a way that I can store the formula in my code and copy it from there rather than from the existing cells?


Leslie
landrews@metrocourt.state.nm.us

There are 10 types of people in the world -
those who understand binary
and
those who don't!
 
You didn't actually tell me what the formulas are or how many columns are involved, but here is a generic way to save all of the formulas from a row in a worksheet and restore them later.
[blue]
Code:
Option Explicit

Sub demo()
Dim SavedFormulas As Collection

  Set SavedFormulas = New Collection
  SaveFormulas 2, SavedFormulas
  Range(&quot;A2:G2&quot;).Clear
  MsgBox &quot;Note that row is cleared&quot;
  
  RestoreFormulas 2, SavedFormulas
  Set SavedFormulas = Nothing
  MsgBox &quot;Note that the formulas have been restored&quot;

End Sub

Sub SaveFormulas(RowNumber As Long, Formulas As Collection)
Dim nLastColumn As Integer
Dim nCol As Integer
  With ActiveSheet.UsedRange
    nLastColumn = .Columns.Count + .Column - 1
  End With
  For nCol = 1 To nLastColumn
     Formulas.Add Cells(RowNumber, nCol).Formula
  Next nCol
End Sub

Sub RestoreFormulas(RowNumber As Long, Formulas As Collection)
Dim i As Integer
  For i = 1 To Formulas.Count
    Cells(RowNumber, i).Formula = Formulas.Item(i)
  Next i
End Sub
[/color]

 
I'll play around with these today. Thanks for all your help, would have taken me weeks to get this done! (wish I could give more than 1 star - you deserve 3!)

leslie


Leslie
landrews@metrocourt.state.nm.us

There are 10 types of people in the world -
those who understand binary
and
those who don't!
 
Thank you for that. A good way to express your appreciation would be to make a donation to Tek-Tips!

(I don't work for Tek-Tips. I'm just a member like you. My only &quot;pay&quot; is the star and the satisfication from having helped someone.)
 
If my financial situation allowed, I would be more than happy to, but unfortunately I'm drowning in debt!

Les
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top