In Excel 2007, I have a worksheet that only contains data in a only few cells (well within one page wide/tall). For illustration, say the worksheet only contains data in cell A1. How can I use VBA to determine the number of columns that fit in a single printed page? Said another way, how can I determine the column furthest to the right in which I could add data and NOT cause an additional sheet to print. A couple of additional comments:
I am not setting a print area. If I were, then I'd just use the same
range...but I'm not.
I can't use UsedRange, because the used range is much smaller than
what actually fits in the width/height of a printed page.
I can't use ActiveWindow.VisibleRange because it isn't limited to a
single page width/height.
I've searched and searched, but cannot find a solution to accomplish this seemingly simple task. I mostly found scenarios that involved UsedRange, VisibleRange, and the print area, but those don't help me.
EDIT
Here's the final version of the function I'm using, which is a slight tweak of the selected answer.
Public Function GetLastColumnBeforeVPageBreak( _
ByRef ws As Worksheet, _
ByVal aVPageBreakNum As Long) As Long
Dim isMod As Boolean
isMod = False
On Error GoTo ErrorHandler
GetLastColumnBeforeVPageBreak = ws.VPageBreaks(aVPageBreakNum).Location.Column - 1
' If necessary, delete the last column with dummy data and reset UsedRange.
If isMod Then
ws.Cells(ws.Rows.Count, ws.Columns.Count).EntireColumn.Delete
r = ws.UsedRange.Rows.Count
End If
Exit Function
ErrorHandler:
If Err.Number = 9 Then
' Subscript out of range.
' Ensure there is more than one page by putting something in last cell.
isMod = True
ws.Cells(ws.Rows.Count, ws.Columns.Count).Value = 1
Err.Clear
Resume
Else
Err.Raise Err.Number
End If
End Function
I was sure there was a worksheet property around page breaks so I hit F2 in the IDE to open the object browser and searched on pagebreak. A little bit of F1'ing showed there is a Worksheets(1).VPageBreaks(1).Location property that returns a range object. The left side of the range aligns with the 1st vertical page break so:
LastColOnP1 = Worksheets(1).VPageBreaks(1).Location.Column - 1
will give you a variable containing the number of the last column that will print on page 1 of your 1st sheet.
Or within a procedure:
Sub FindFirstVPageBreak()
Dim LastColOnP1 As Long
With ActiveSheet
'Ensure there is more than one page by puting something in last column
.Cells(1, .Columns.Count) = 1
LastColOnP1 = .VPageBreaks(1).Location.Column - 1
'Delete the last column to allow UsedRange to be reset
.Cells(1, .Columns.Count).EntireColumn.Delete
End With
'Save to workbook to commit the reset UsedRange
If Not ActiveWorkbook.ReadOnly Then
ActiveWorkbook.Save 'assumes workbook has been saved previously.
End If
End Sub
You can use Columns(x).ColumnWidth to calculate (iif column contains data). See http://EzineArticles.com/7305778 for a much more detailed solution.
Related
I have been trying to get this to work, but I couldn't so far, and after searching I couldn't quite find a solution online either, so here it goes.
I have 3 sheets I'm using.
"wsPunting" (The one where the value changes)
"wsDetail" (The Sheet with complete data of everything)
"wsData" (The Sheet where I store certain data that I grab with macros)
Now, what I'm trying to do, is that when a Value changes in cell B2 in wsPunting (B2 is Data Validation made with a macro, not sure if this is valuable info, but better put it in here just in case), I filter my data in wsDetail, grab Column "O3:O", Remove Duplicates, and Assign that into a Data Validation in Cell B5 in wsPunting.
I got this to work already when I had <20 values entered. Now, when I pasted the actual Data that I was going to use in wsDetail, I kept getting "Type Mismatch" on the Intersect.
I've tried a few things already that I though might perhaps fix it, but I just can't seem to find it.
Private Sub Worksheet_Change(ByVal Target As Range)
Application.ScreenUpdating = False
On Error GoTo Booboo
Dim rngFSU As Range
Dim vFSU As Range
Dim wsPunting As Worksheet, wsData As Worksheet, wsDetail As Worksheet
Set wsPunting = ActiveWorkbook.Sheets("Puntingsblad")
Set wsData = ActiveWorkbook.Sheets("Data")
Set wsDetail = ActiveWorkbook.Sheets("Detail")
Set rngFSU = wsPunting.Range("$B$2")
Set vFSU = wsPunting.Range(Target.Address)
'The next line is where it keep dropping the error
If Not Intersect(rngFSU, vFSU) Then
wsDetail.Range("A2", wsDetail.Range("A3").SpecialCells(xlCellTypeLastCell)).AutoFilter Field:=1, Criteria1:=Range("B2").Value
wsDetail.Range("O3", wsDetail.Range("O3").SpecialCells(xlCellTypeLastCell)).Copy
wsData.Range("B2").PasteSpecial xlPasteValues
wsData.Range("B2", wsData.Range("B1").End(xlDown)).RemoveDuplicates Columns:=Array(1)
With wsPunting.Range("B5").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Formula1:="=Data!" & wsData.Range("B2", wsData.Range("B1").End(xlDown)).Address
.IgnoreBlank = True
End With
wsDetail.Range("A2", wsDetail.Range("A3").SpecialCells(xlCellTypeLastCell)).AutoFilter Field:=1
End If
Booboo:
MsgBox err.Description
End Sub
This is actually my last resort, concidering I usually try fixing it myself to learn faster. But I've been stuck on this one for so long already, I just can't anymore atm.
Cheers in advance.
If Not Intersect(rngFSU, vFSU) Then
Intersect(rngFSU, vFSU) is an object of type Range, you are trying to cast it into a boolean.
This leads to an error. I understand that you want to check if there is no intersection, in which case the Range returned by Intersect is Nothing. So try this:
If Intersect(rngFSU, vFSU) Is Nothing Then
The Problem
Assume that the active cell contains a formula based on the INDEX function:
=INDEX(myrange, x,y)
I would like to build a macro that locates the value found value by INDEX and moves the focus there, that is a macro changing the active cell to:
Range("myrange").Cells(x,y)
Doing the job without macros (slow but it works)
Apart from trivially moving the selection to myrange and manually counting x rows y and columns, one can:
Copy and paste the formula in another cell as follows:
=CELL("address", INDEX(myrange, x,y))
(that shows the address of the cell matched by INDEX).
Copy the result of the formula above.
Hit F5, Ctrl-V, Enter (paste the copied address in the GoTo dialog).
You are now located on the very cell found by the INDEX function.
Now the challenge is to automate these steps (or similar ones) with a macro.
Tentative macros (not working)
Tentative 1
WorksheetFunction.CELL("address", ActiveCell.Formula)
It doesn't work since CELL for some reason is not part of the members of WorksheetFunction.
Tentative 2
This method involves parsing the INDEX-formula.
Sub GoToIndex()
Dim form As String, rng As String, row As String, col As String
form = ActiveCell.Formula
form = Split(form, "(")(1)
rng = Split(form, ",")(0)
row = Split(form, ",")(1)
col = Split(Split(form, ",")(2), ")")(0)
Range(rng).Cells(row, CInt(col)).Select
End Sub
This method actually works, but only for a simple case, where the main INDEX-formula has no nested subformulas.
Note
Obviously in a real case myrange, x and ycan be both simple values, such as =INDEX(A1:D10, 1,1), or values returned from complex expressions. Typically x, y are the results of a MATCH function.
EDIT
It was discovered that some solutions do not work when myrange is located on a sheet different from that hosting =INDEX(myrange ...).
They are common practice in financial reporting, where some sheets have the main statements whose entries are recalled from others via an INDEX+MATCH formula.
Unfortunately it is just when the found value is located on a "far" report out of sight that you need more the jump-to-the-cell function.
The task could be done in one line much simpler than any other method:
Sub GoToIndex()
Application.Evaluate(ActiveCell.Formula).Select
End Sub
Application.Evaluate(ActiveCell.Formula) returns a range object from which the CELL function gets properties when called from sheets.
EDIT
For navigating from another sheet you should first activate the target sheet:
Option Explicit
Sub GoToIndex()
Dim r As Range
Set r = Application.Evaluate(ActiveCell.Formula)
r.Worksheet.Activate
r.Select
End Sub
Add error handling for a general case:
Option Explicit
Sub GoToIndex()
Dim r As Range
On Error Resume Next ' errors off
Set r = Application.Evaluate(ActiveCell.Formula) ' will work only if the result is a range
On Error GoTo 0 ' errors on
If Not (r Is Nothing) Then
r.Worksheet.Activate
r.Select
End If
End Sub
There are several approaches to select the cell that a formula refers to...
Assume the active cell contains: =INDEX(myrange,x,y).
From the Worksheet, you could try any of these:
Copy the formula from the formula bar and paste into the name box (to the left of the formula bar)
Define the formula as a name, say A. Then type A into the Goto box or (name box)
Insert hyperlink > Existing File or Web page > Address: #INDEX(myrange,x,y)
Adapt the formula to make it a hyperlink: =HYPERLINK("#INDEX(myrange,x,y)")
Or from the VBA editor, either of these should do the trick:
Application.Goto Activecell.FormulaR1C1
Range(Activecell.Formula).Select
Additional Note:
If the cell contains a formula that refers to relative references such as =INDEX(A:A,ROW(),1) the last of these would need some tweaking. (Also see: Excel Evaluate formula error). To allow for this you could try:
Range(Evaluate("cell(""address""," & Mid(ActiveCell.Formula, 2) & ")")).Select
This problem doesn't seem to occur with R1C1 references used in Application.Goto or:
ThisWorkbook.FollowHyperlink "#" & mid(ActiveCell.FormulaR1C1,2)
You could use the MATCH() worksheet function or the VBA FIND() method.
EDIT#1
As you correctly pointed out, INDEX will return a value that may appear many times within the range, but INDEX will always return a value from some fixed spot, say
=INDEX(A1:K100,3,7)
will always give the value in cell G3 so the address is "builtin" to the formula
If, however, we have something like:
=INDEX(A1:K100,Z100,Z101)
Then we would require a macro to parse the formula and evaluate the arguments.
Both #lori_m and #V.B. gave brilliant solutions in their own way almost in parallel.
Very difficult for me to choose the closing answer, but V.B. even created Dropbox test file, so...
Here I just steal the best from parts from them.
'Move to cell found by Index()
Sub GoToIndex()
On Error GoTo ErrorHandler
Application.Goto ActiveCell.FormulaR1C1 ' will work only if the result is a range
Exit Sub
ErrorHandler:
MsgBox ("Active cell does not evaluate to a range")
End Sub
I associated this "jump" macro with CTRL-j and it works like a charm.
If you use balance sheet like worksheets (where INDEX-formulas, selecting entries from other sheets, are very common), I really suggest you to try it.
I am trying to make a macro that will go through a whole workbook and count the number of days a employee worked. The sheets have the work broken out in days so all T have to find is the days that are not zero. I have tried to use COUNTIF(A11:A12,">0") and I get the error Expected : list separator or ). I am using a For Each loop to work through the sheets. I would like to put all the information on a new sheet at the end of the workbook with the name of the employee and the days worked. I am very new to visual basic but am quite good with c#.
I now have gotten this far
Option Explicit
Sub WorksheetLoop2()
' Declare Current as a worksheet object variable.
Dim Current As Worksheet
Dim LastColumn As Integer
If WorksheetFunction.CountA(Cells) > 0 Then
' Search for any entry, by searching backwards by Columns.
LastColumn = Cells.Find(What:="*", After:=[A1], _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
End If
' Loop through all of the worksheets in the active workbook.
For Each Current In Worksheets
Current.Range("A27") = Application.WorksheetFunction.CountIf(Current.Range(Cells(11, LastColumn), Cells(16, LastColumn)), ">0")
Current.Range("A28") = Application.WorksheetFunction.CountIf(Current.Range("Al17:Al22"), ">0")
Next
End Sub
When I run this I get an error saying method range of object'_worksheet' failed. I also haven't been able to find a way to get the information all on the summary sheet.
VBA Solution, in light of your last comment above.
Good VBA programming practice entails always using Option Explicit with your code, that way you know when you don't have variables declared correctly, or, sometimes, if code is bad! In this case you would have picked up that just writing A27 does not mean you are returning the value to cell A27, but rather just setting the value you get to variable A27. Or maybe you wouldn't know that exactly, but you would find out where your problem is real quick!
This code should fix it for you:
Option Explicit
Sub WorksheetLoop2()
'Declare Current as a worksheet object variable.
Dim Current As Worksheet
' Loop through all of the worksheets in the active workbook.
For Each Current In Worksheets
Current.Range("A27") = Application.WorksheetFunction.CountIf(Current.Range("A11:A12"), ">0")
Next
End Sub
In case it helps, Non-VBA solution:
Assuming you have a Summary sheet and each employee on a separate sheet, with days in column A and hours worked in column B, enter formula in formula bar in B1 of Summary and run down the list of names in column A.
I am working with a workbook that contains three worksheets of data. Each worksheet has a Contract Number column. Certain contracts must be excluded and noted in a separate worksheet.
I would like to create Excel VBA macro that:
Prompts the user to enter specific contract numbers to be excluded
Stores contract numbers
Searches all three worksheets' contract column for the contract numbers
Notes the unwanted contract details in a "summary" worksheet, which has already been created
Deletes the unwanted contract row entirely
The macro should loop through this process below for 'n' number of contracts entered by the user.
Public contString As String
Public x As Variant
Public xCount As Variant
Sub find()
contString = InputBox(Prompt:="Enter contract numbers to exclude(Comma Delimited). Cancel to include all contracts.", _
Title:="Exclude Contracts", Default:="1715478")
x = Split(contString, ",")
xCount = UBound(x) 'Number of contracts entered by user
End Sub
Sub SearchWS1()
Sheets("WS1").Activate
Columns("I:I").Select 'Contract Number Column
Selection.find(What:=x(i), After:=ActiveCell, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Activate
BKWS = ActiveCell.Worksheet.Name
BKRow = ActiveCell.Row
If BKRow > 0 Then
Cname = Range("G" & BKRow)
Cnumber = Range("I" & BKRow)
Cvalue = Range("K" & BKRow)
'Summarize Excluded Contract Info on Summary WS
Range("Summary!B25").Value = "Exclusions:"
Range("Summary!B26").Value = Cnumber
Range("Summary!C26").Value = Cname
Range("Summary!D26").Value = Cvalue
'Select and Delete Contract
Rows(ActiveCell.Row).Select
Rows(BKRow).EntireRow.Delete
Else
Call SearchWS2 'SearchWS2 is essentially the same as SearchWS1 and Calls SearchWS3 if contract isn't found.
End If
End Sub
If the contract number doesn't exist in the first WS, I get an error like 'Object variable or With block not set'. Once I can fix this error, I will need to run this process through a loop for each contract number entered by the user. Any help with debugging the error or setting up a loop for this would be greatly appreciated.
Thanks!
Use the InputBox for inputting contract numbers (let's say, comma delimited). Split the result using Split function.
Store contract numbers on a separate worksheet that you hide (wks.visible=xlVeryHidden, where wks is a worksheet object).
Find values using a multidimensional array to store the values.
Print 2D array to found worksheet using rFound=saArray (where rFound is a range object and saArray is the 2D array.
Make heavy use of recording macros to learn syntax.
See this example on fast ways to retrieve and print to cells.
Update:
Sorry, this is pretty sloppy but I just threw it together and, obviously, it hasn't been tested. Hope this helps. Sorry, I also shouldn't be having you use advanced techniques like this, but it's hard for me to go back.
dim j as integer, k as integer, m as long, iContractColumn as integer
Dim x() as string, saResults() as string
dim vData as variant
dim wks(0 to 2) as worksheet
iContractColumn=????
set wks(0) = Worksheets("First")
set wks(1) = Worksheets("Second")
set wks(2) = Worksheets("Third")
redim saresults(1 to 100, 1 to 2)
m=0
'Loop thru worksheets
for j=0 to 2
'Get data from worksheet
vdata=wks(j).range(wks(j) _
.cells(1,iContractColumn),wks(j).cells(rows.count,iContractColumn).end(xlup))
'Loop through data
for k=1 to ubound(vdata)
'Loop through user criteria
For i = 0 To UBound(x)
'Compare user criteria to data
if x(i)=cstr(vdata(k,1)) then
'Capture the row and worksheet name
m=m+1
'If array is too small increase size
if m>ubound(saresults) then
redim preserve saresults(1 to ubound(saresults)*2, 1 to 2)
end if
'Get name and row.
saresults(m,1)=wks(j).name
saresults(m, 2)=k
exit for
end if
next i
next k
next j
'Resize array to correct size
redim preserve saresults(1 to m, 1 to 2)
'Print results to a result page (you could also create hyperlinks here
'that would make it so the person can click and go to the respective page.
'You would have to do a loop for each result on the range.
with worksheets("Result Page")
.range(.cells(1,1),.cells(m,2))=saresults
end with
I have little to add Jon49's answer which does seem to cover the basics. But I wish I had discovered Forms earlier in my VBA programming career. They can be a little confusing at first but, once mastered, they add enormously to the usability of a macro for very little effort.
Forms can be used to get values from the user (instead of InputBox) or can be used to give progress information to the user. I will only talk about the second usage. Your macro might take some time; has the user time to get a cup of coffee or will it finish in 5 seconds? I HATE programs that sit there saying "please wait - this may take from a few minutes to a few hours".
The following code loads a form into memory, shows it to the user and removes it from memory at the end. If you do not unload the form, it remains on the screen after the macro has ended which may be useful if you want to leave a message for the user. This form is show "modeless" which means the macro displays it and carries on. If shown "modal", the macro stops until the user has entered whatever information the form requires.
Load frmProgress
Progress.Show vbModeless
' Main code of macro
Unload frmProgress
There are no end to the web sites offering tutorials on Forms so I will mainly describe the what rather than how.
Within the VB Editor, Insert a UserForm. Drags the bottom and right edges if you want it bigger. Use the Properties Window to change the Name to frmProgress.
Drag four labels from the Tool Box and arrange them in a line. Set the caption of label 1 to "Worksheet " and the caption of label 3 to "of". Name label 2 "lblWSNumCrnt" and name label 4 "lblWSNumTotal".
Add the following around "for j = 0 to 2"
frmProgress.lblWSNumTotal.Caption = 3
for j = 0 to 2
frmProgress.lblWSNumCrnt.Caption = j + 1
DoEvents
This means the user will see the following with n stepping from 1 to 3 as the macro progesses:
Worksheet n of 3
Add another four labels for row number, and the following code around the k loop:
frmProgress.lblRowNumTotal.Caption = ubound(vdata, 1)
for k = 1 to ubound(vdata, 1)
frmProgress.lblRowNumCrnt.Caption = k
DoEvents
Now the user will see something like:
Worksheet 2 of 3
Row 1456 or 2450
The above technique is simple and does not involve any change to Jon49's code. The following technique, borrowed from Wrox's excellent Excel VBA Programmer's Reference, is a little more complicated but gives your macro a more professional appearance.
Create a label that runs across the entire form. Name it "lblToDo" and colour it white. Create another label of the same size over the top. Name it "lblDone" and colour it black.
Create a copy of the code to count the rows in each sheet at the top so you can calculate the total number of rows, "TotalRowsTotal", before you do anything else.
Create a new variable "TotalRowsCrnt", initialise it to zero and add one to it for every row in every worksheet.
Within the inner loop, add:
frmProgress.lblToDo.Width = _
frmProgress.lblDone.Width * TotalRowsCrnt / TotalRowsTotal
For Excel 2003, which all the organisations I work with still use, this gives a progress bar with the black Done label steadily covering the white ToDo label. Later version of Excel may offer a progress bar control as standard.
I hope this gives you some ideas for making your macros more attractive to your users.
I need to simply go through all the cells in a Excel Spreadsheet and check the values in the cells. The cells may contain text, numbers or be blank. I am not very familiar / comfortable working with the concept of 'Range'. Therefore, any sample codes would be greatly appreciated. (I did try to google it, but the code snippets I found didn't quite do what I needed)
Thank you.
If you only need to look at the cells that are in use you can use:
sub IterateCells()
For Each Cell in ActiveSheet.UsedRange.Cells
'do some stuff
Next
End Sub
that will hit everything in the range from A1 to the last cell with data (the bottom right-most cell)
Sub CheckValues1()
Dim rwIndex As Integer
Dim colIndex As Integer
For rwIndex = 1 To 10
For colIndex = 1 To 5
If Cells(rwIndex, colIndex).Value <> 0 Then _
Cells(rwIndex, colIndex).Value = 0
Next colIndex
Next rwIndex
End Sub
Found this snippet on http://www.java2s.com/Code/VBA-Excel-Access-Word/Excel/Checksvaluesinarange10rowsby5columns.htm It seems to be quite useful as a function to illustrate the means to check values in cells in an ordered fashion.
Just imagine it as being a 2d Array of sorts and apply the same logic to loop through cells.
If you're just looking at values of cells you can store the values in an array of variant type. It seems that getting the value of an element in an array can be much faster than interacting with Excel, so you can see some difference in performance using an array of all cell values compared to repeatedly getting single cells.
Dim ValArray as Variant
ValArray = Range("A1:IV" & Rows.Count).Value
Then you can get a cell value just by checking ValArray( row , column )
You can use a For Each to iterate through all the cells in a defined range.
Public Sub IterateThroughRange()
Dim wb As Workbook
Dim ws As Worksheet
Dim rng As Range
Dim cell As Range
Set wb = Application.Workbooks(1)
Set ws = wb.Sheets(1)
Set rng = ws.Range("A1", "C3")
For Each cell In rng.Cells
cell.Value = cell.Address
Next cell
End Sub
For a VB or C# app, one way to do this is by using Office Interop. This depends on which version of Excel you're working with.
For Excel 2003, this MSDN article is a good place to start.
Understanding the Excel Object Model from a Visual Studio 2005 Developer's Perspective
You'll basically need to do the following:
Start the Excel application.
Open the Excel workbook.
Retrieve the worksheet from the workbook by name or index.
Iterate through all the Cells in the worksheet which were retrieved as a range.
Sample (untested) code excerpt below for the last step.
Excel.Range allCellsRng;
string lowerRightCell = "IV65536";
allCellsRng = ws.get_Range("A1", lowerRightCell).Cells;
foreach (Range cell in allCellsRng)
{
if (null == cell.Value2 || isBlank(cell.Value2))
{
// Do something.
}
else if (isText(cell.Value2))
{
// Do something.
}
else if (isNumeric(cell.Value2))
{
// Do something.
}
}
For Excel 2007, try this MSDN reference.
There are several methods to accomplish this, each of which has advantages and disadvantages; First and foremost, you're going to need to have an instance of a Worksheet object, Application.ActiveSheet works if you just want the one the user is looking at.
The Worksheet object has three properties that can be used to access cell data (Cells, Rows, Columns) and a method that can be used to obtain a block of cell data, (get_Range).
Ranges can be resized and such, but you may need to use the properties mentioned above to find out where the boundaries of your data are. The advantage to a Range becomes apparent when you are working with large amounts of data because VSTO add-ins are hosted outside the boundaries of the Excel application itself, so all calls to Excel have to be passed through a layer with overhead; obtaining a Range allows you to get/set all of the data you want in one call which can have huge performance benefits, but it requires you to use explicit details rather than iterating through each entry.
This MSDN forum post shows a VB.Net developer asking a question about getting the results of a Range as an array
You basically can loop over a Range
Get a sheet
myWs = (Worksheet)MyWb.Worksheets[1];
Get the Range you're interested in If you really want to check every cell use Excel's limits
The Excel 2007 "Big Grid" increases
the maximum number of rows per
worksheet from 65,536 to over 1
million, and the number of columns
from 256 (IV) to 16,384 (XFD).
from here http://msdn.microsoft.com/en-us/library/aa730921.aspx#Office2007excelPerf_BigGridIncreasedLimitsExcel
and then loop over the range
Range myBigRange = myWs.get_Range("A1", "A256");
string myValue;
foreach(Range myCell in myBigRange )
{
myValue = myCell.Value2.ToString();
}
In Excel VBA, this function will give you the content of any cell in any worksheet.
Function getCellContent(Byref ws As Worksheet, ByVal rowindex As Integer, ByVal colindex As Integer) as String
getCellContent = CStr(ws.Cells(rowindex, colindex))
End Function
So if you want to check the value of cells, just put the function in a loop, give it the reference to the worksheet you want and the row index and column index of the cell. Row index and column index both start from 1, meaning that cell A1 will be ws.Cells(1,1) and so on.
My VBA skills are a little rusty, but this is the general idea of what I'd do.
The easiest way to do this would be to iterate through a loop for every column:
public sub CellProcessing()
on error goto errHandler
dim MAX_ROW as Integer 'how many rows in the spreadsheet
dim i as Integer
dim cols as String
for i = 1 to MAX_ROW
'perform checks on the cell here
'access the cell with Range("A" & i) to get cell A1 where i = 1
next i
exitHandler:
exit sub
errHandler:
msgbox "Error " & err.Number & ": " & err.Description
resume exitHandler
end sub
it seems that the color syntax highlighting doesn't like vba, but hopefully this will help somewhat (at least give you a starting point to work from).
Brisketeer