Clearing Contents of Row with For Loop - vba

I have code that is designed to loop through each cell in a row and delete them EXCEPT for the A and O columns. When I run this code it only deletes the second column.
I am aware of the "Rows(Target.Row).ClearContents" line but this does not suit my purposes as I need specific columns to stay intact.
Dim i As Integer
For i = 2 To i = 30
If i = 15 Then
'update i but do nothing
i = i + 1
Else
'update i and clear contents of cell
.Cells(Target.Row, i).Clear
i = i + 1
End If
Next

The For loop increments the i so you shouldn't, and this syntax is incorrect For i = 2 To i = 30:
Dim i As Long
For i = 2 To 30
If i <> 15 Then .Cells(Target.Row, i).Clear
Next
A faster way to exclude certain columns from the row (without using a loop):
With Target.Parent
.Columns(15).Hidden = True
.UsedRange.Rows(Target.Row).SpecialCells(xlCellTypeVisible).Clear
.Columns(15).Hidden = False
End With

Why use loops at all?
Union(Range(.Cells(Target.Row,2),.Cells(Target.Row,14)), Range(.Cells(Target.Row,16),.Cells(Target.Row,30))).Clear

Related

Do-While loop (VBA) not looping

so I thought this would be a simple logical problem, but for the life of me I cannot find the issue with this code block. I have checked around on Stack for a solution, but all other do/while loop problems appear to be primarily with other languages.
What I am trying to do is simply loop through an array & add a new worksheet for each element in the array that is not null. Pretty simple right? Yet for some reason it simply loops through once and thats it.
Here is the code block:
Dim repNames() As String
Dim x As Integer
x = 25
ReDim repNames(1 To x)
repNames(1) = "Ahern"
repNames(2) = "Castronovo"
repNames(3) = "Glick"
repNames(4) = "Fields"
repNames(5) = "Murphy"
repNames(6) = "Sleeter"
repNames(7) = "Vivian"
repNames(8) = "Walschot"
repNames(9) = "Wilson"
Dim i As Integer
i = 1
Do 'Loop keeps creating only 1 new sheet. Should create 9.
Worksheets.Add.Name = repNames(i)
i = i + 2
Loop While repNames(i) <> Null
I believe the problem is with this line: Loop While repNames(i) <> Null,
but obviously the logical test seems to hold up.
Any help would be hugely appreciated!
As others note, Null is not the comparison you want to make. Testing anything for equivalence with Null will return Null -- even ?Null = Null returns Null, which is why your loop is exiting early. (Note: To test for a Null, you need to use the IsNull function which returns a boolean, but that is NOT how you test for an empty string.)
In VBA, to test for a zero-length string or empty string, you can use either "" or vbNullString constant, or some people use the Len function to check for zero-length.
Rectifying that error, as originally written in your code, your logical test should abort the loop if any item is an empty string, but none of the items are empty strings (at least not in the example data you've provided) so you end up with an infinite loop which will error once i exceeds the number of items in the repNames array.
This would be probably better suited as a For Each loop.
Dim rep as Variant
For Each rep in repNames
Worksheets.Add.Name = rep
Next
If you need to skip empty values, or duplicate values, you can add that logic as needed within the loop:
For Each rep in repNames
If rep <> vbNullString 'only process non-zero-length strings
Worksheets.Add.name = rep
End If
Next
Etc.
Firstly, you should be comparing to vbNullString. This loops multiple times:
' Declare variables
Dim repNames() As String
Dim x As Integer
Dim i As Integer
' Set data
x = 25
ReDim repNames(1 To x)
repNames(1) = "Ahern"
repNames(2) = "Castronovo"
repNames(3) = "Glick"
repNames(4) = "Fields"
repNames(5) = "Murphy"
repNames(6) = "Sleeter"
repNames(7) = "Vivian"
repNames(8) = "Walschot"
repNames(9) = "Wilson"
' Loop through items
i = 1
Do
Worksheets.Add.Name = repNames(i)
i = i + 2
Loop While repNames(i) <> vbNullString
There is one more problem – why i = i + 2 ? In your question you say you wanted the loop to execute 9 times, but using i = i + 2 skips every other item. If you indeed want to loop through every item:
Do
Worksheets.Add.Name = repNames(i)
i = i + 1
Loop While repNames(i) <> vbNullString
Here you go, I have changed the loop conditional, and changed i=i+2 to i=i+1. A regular while loop would be better than a do while encase the first element is empty
Dim repNames()
Dim x As Integer
x = 25
ReDim repNames(1 To x)
repNames(1) = "Ahern"
repNames(2) = "Castronovo"
repNames(3) = "Glick"
repNames(4) = "Fields"
repNames(5) = "Murphy"
repNames(6) = "Sleeter"
repNames(7) = "Vivian"
repNames(8) = "Walschot"
repNames(9) = "Wilson"
Dim i As Integer
i = 1
Do While repNames(i) <> ""
Worksheets.Add.Name = repNames(i)
i = i + 1
Loop

Writing a loop in Excel for Visual Basic

How do i write the following code as a loop. I want to copy values from a table in sheet 4 in a row from range (b:17:L17"). is there a more efficient way to do it with loops ?
ActiveSheet.Range("B17").Value = Sheets(4).Range("G8")
ActiveSheet.Range("C17").Value = Sheets(4).Range("G9")
ActiveSheet.Range("D17").Value = Sheets(4).Range("G10")
ActiveSheet.Range("E17").Value = Sheets(4).Range("G11")
ActiveSheet.Range("F17").Value = Sheets(4).Range("G12")
ActiveSheet.Range("G17").Value = Sheets(4).Range("G13")
ActiveSheet.Range("H17").Value = Sheets(4).Range("G14")
ActiveSheet.Range("I17").Value = Sheets(4).Range("G15")
ActiveSheet.Range("J17").Value = Sheets(4).Range("G16")
ActiveSheet.Range("K17").Value = Sheets(4).Range("G17")
ActiveSheet.Range("L17").Value = Sheets(4).Range("G18")
Yes, there is:
ActiveSheet.Range("B17:L17").Value = Application.Transpose(Sheets(4).Range("G8:G18").Value)
You can, using something like this (VB.Net, but may copy easily to VBA):
Dim cell as Integer, c as Integer
cell = 8
For c = 66 To 76
ActiveSheet.Range(Chr(c) & "17").Value = Sheets(4).Range("G" & cell)
cell = cell + 1
Next
The Chr() function gets the character associated with the character code (66-76), and then this value is concatenated with the string "17" to form a complete cell name ("B17", "C17", ...)
I am also incrementing the cell number for G at the same time.
Use this if you really want to use a loop - but there could be better ways, like the answer given by #A.S.H
Solution explanation:
Establish your rules! What is changing in the range for active sheet? The column is going to grow as the for/to cycle does! So, we should sum that to it. What is the another thing that is going to increment? The Range in the other side of the '=' so, by setting an algorithm, we may say that the row is const in the Activesheet range and the column is the on variable on the other side.
Solution:
Sub Test()
Const TotalInteractions As Long = 11
Dim CounterInteractions As Long
For CounterInteractions = 1 To TotalInteractions
'where 1 is column A so when it starts the cycle would be B,C and so on
'where 7 is the row to start so when it begins it would became 8,9 and so on for column G
ActiveSheet.Cells(17, 1 + CounterInteractions).Value = Sheets(4).Cells(7 + CounterInteractions, 7)
Next CounterInteractions
End Sub
This is probably your most efficient solution in a with statement:
Sub LoopExample()
Sheets("Sheet4").Range("G8:G18").Copy
Sheets("Sheet2").Range("B17").PasteSpecial xlPasteValues, Transpose:=True
End Sub

In excel If test passes when value typed manually but fail from a cell

Using excel VBA, I have constructed a dictionary and populated it. I did my tests and it's well done.
After that, in a loop I had to test if a key exists to do some operations:
For i3 = 2 To n 'n is the the number of rows
If dicos.Exists(ActiveSheet.Range("T" & i3)) Then
ActiveSheet.Range("N" & i3) = dicos(ActiveSheet.Range("T" & i3)) + 1
Else
ActiveSheet.Range("N" & i3) = 1
End If
Next
It doesn't work and I have 1 in all the column N. I tried to test with some values from the column T manually and it finds it!
Can anyone explain to me what I have done wrong and why the test is positive when I type the value manually and it is negative when the program has to take it from a cell (column T)?
Thank you very much.
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim dicos As Dictionary
Set dicos = new Dictionary
'Populate dicos....
For i = 2 To n 'n is the the number of rows
If dicos.Exists(ws.Cells(i, 20).Value) Then
ws.Cells(i, 14) = dicos.Item(ws.Cells(i, 20).Value) + 1
Else
ws.Cells(i, 14) = 1
End If
Next
I believe the problem was that you didn't use .Value on the additive line, thus it was just putting 1 in there. When I tested your code as-posted I changed the +1 to a +4 and got 4 in cells(i,14) instead of 1.

Incrementing VBA For loop through command button

Good day!
I am currently having a slight issue with a command button, which, I would like to be able to do the following: format a specific row to a certain row height, add thick borders to a certain number of cells in this same row and counting and adding the number of rows thus produced to the initial number in the file. Basically, the button should enable the user of the spread sheet to add a new row with specific formatting into which the user will input data and keep track of the number of rows added.
My current code stands as is:
Option Explicit
Private Sub NewLineRedButton_Click()
Dim i As Long
Dim y As Long
For y = ThisWorkbook.Worksheets("Flags").Cells(16.3) To y + 1
ThisWorkbook.Worksheets("Flags").Cells(16, 3) = y + 1
For i = 20 To i + y Step 1
ThisWorkbook.Worksheets("Flags").Rows(i).RowHeight = 45
ThisWorkbook.Worksheets("Flags").Cells(i, 1).Borders.LineStyle = xlContinuous
ThisWorkbook.Worksheets("Flags").Cells(i, 1).Borders.Weight = xlMedium
Next
Next
End Sub
At the moment the code executes only for two rows below and stops. I am not quite sure, why...?
Writing a for loop like this
For y = ThisWorkbook.Worksheets("Flags").Cells(16.3) To y + 1
is the same as writing it like this
For y = ThisWorkbook.Worksheets("Flags").Cells(16.3) To 1
I'm guessing the value in the cell is zero so it will execute the loop for 0 and 1 - i.e. the two times you are seeing.
You need something like
lEndRow = lStartRow + (lRowCount - 1)
For y = lStartRow to lEndRow
I have this going fine now. Just can't get it to do all the columns with the right borders... I am not sure how to to call them while using the cells(#, #) notation and I can't see how to use the Range(''Z#,Z#'') notation with my i variable being a Long...
Anyways: here's the result so far:
Option Explicit
Private Sub NewLineRedButton_Click()
Dim i As Long
Dim y As Long
Dim RowEnd As Long
RowEnd = ThisWorkbook.Worksheets("Flags").Cells(Rows.Count, 1).End(xlUp).Row
For y = 19 To RowEnd
ThisWorkbook.Worksheets("Flags").Cells(16, 3) = y - 17 ' First row which is already on the sheet is on row 19, first row appearing by button clicking is on row 20 and the program is counting the header hence the y - 17 for the value of the number of rows.
For i = 19 To RowEnd + 1 Step 1
ThisWorkbook.Worksheets("Flags").Rows(i).RowHeight = 45
ThisWorkbook.Worksheets("Flags").Cells(i, 1).Borders.LineStyle = xlContinuous
ThisWorkbook.Worksheets("Flags").Cells(i, 1).Borders.Weight = xlMedium
Next
Next
End Sub
Thanks for the help and ideas, finally wiggled around and found other resources from the leads given here.

Adding to an array with select case

Hope someone can help with a puzzling problem.
I have an excel worksheet that has a lot of lines that need to be moved to different sheets.
I have a select case statement that sets 3 variables to true or false depending on whether the numbers in the first column match a case statement. This works ok but I now want to add a name to an array if the value is true.
The select case statement is as follows :
While LContinue
If LRow = Lastrow Then
LContinue = False
Else
Select Case Range("A" & LRow).Value
Case 30 To 39
MainSheet = True
'Tabs(0) = "Main"
Case 40 To 49
SecondSheet = True
'Tabs(1) = "Second"
Case 111 To 112
ThirdSheet = True
'Tabs(2) = "Third"
End Select
LRow = LRow + 1
End If
Wend
This is used to see if I need to add the sheet or not. to add the sheets I use the following code :
For i = LBound(Tabs) To UBound(Tabs)
Sheets.Add(After:=Worksheets(Worksheets.Count)).Name = Tabs(i)
Next i
So what I would like to know is how would I go about adding the sheetnames to the array but only if the value in the select case is true.
Any help would be much appreciated.
Thanks
Why not use worksheet function 'CountIfs'?
It counts on multiple criteria and you do not need any loops so your code will run quicker.
CountIfs(testedRange, ">=30", testedRange, "<=39")
... calculates number of values in 'testedRange' which are >=30 and <=39. If there is at least one then just add your sheet, that's it. No loops, no arrays, no additional variables needed. HTH.
Public Sub test()
Dim testedRange As Range
Dim Lastrow As Long
Lastrow = 10
Set testedRange = ActiveSheet.Range("A1:A" & Lastrow)
With Application.WorksheetFunction
If .CountIfs(testedRange, ">=30", testedRange, "<=39") > 0 Then
ThisWorkbook.Sheets.Add(After:=Worksheets(Worksheets.Count)).Name = "Main"
End If
If .CountIfs(testedRange, ">=40", testedRange, "<=49") > 0 Then
ThisWorkbook.Sheets.Add(After:=Worksheets(Worksheets.Count)).Name = "Second"
End If
If .CountIfs(testedRange, ">=111", testedRange, "<=112") > 0 Then
ThisWorkbook.Sheets.Add(After:=Worksheets(Worksheets.Count)).Name = "Third"
End If
End With
End Sub
Excel VBA is not very flexible when it come to working with actual arrays. But you can work with a collection instead:
SET tabs = new Collection
And then you can add a new value to it whenever you need to (e.g. in the CASE structure):
.
..
...
Case 40 To 49
SecondSheet = True
Tabs.add "Second"
...
..
The values of the collection can be accessed almost in the same way as those of an array:
for j=1 to tabs.count
Sheets.Add(After:=Worksheets(Worksheets.Count)).Name = tabs(j)
next j
Edit:
Since the code is re-entrant, i.e. there can be several instances when Range("A" & LRow).Value will be evaluated, we must make sure, that an item is set only once. This can be done easiest with a dictionary (instead of a collection):
Set tabs = CreateObject("Scripting.Dictionary")
Now it is easy to establish, whether a particular page has already been defined before:
..
...
Case 40 To 49
SecondSheet = True
tabs("Second")=1
The page creation loop then looks like this
for each k in tabs.keys
Sheets.Add(After:=Worksheets(Worksheets.Count)).Name = k
next k
The loop iterates over the keys only. There is no need to check for duplicate entries as all unique keys will be defined and listed only once!
To do this with an array you would want to:
declare a dynamic array of strings
declare a counter for the number of elements added
set the array's size to the largest value that it could possibly be
assign elements to the array, incrementing the counter for each addition
resize the array using the counter value (or test for empty elements when accessing array)
In code that could translate into something like:
Dim Tabs() as String
Dim counter As Long
...
Redim Tabs(0 to Lastrow)
counter = 0
...
While ...
Select Case .Range("A" & lrow).Value
Case 30 To 39
Mainsheet = True
Tabs(count) = "Main"
...
Case Else
counter = counter - 1
End Select
counter = counter + 1
...
Wend
If Not counter = 0 Then
Redim Preserve Tab(0 to counter - 1)
...
'create worksheets using Tabs(), etc.
...
End If