How to make an noncontiguous range of cells work for every cell referenced - vba

I have a noncontiguous range and I want whatever the user writes in each cell in the range to show up in a column in a table I made. In the first column of my table I'm having the program number each generated entry in the table when the user adds a value in one of the specified cells all the way up to 18. I renamed each cell in the range to be "Space_ (some number)". Even though I have written in three of the specified cells, my table only shows me the first value in the first specified cell.
Here is my code so far:
Sub test2()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("Sheet1")
Dim i As Integer
Dim rng As Range
Set rng = ws.Range("Space_7, Space_10, Space_13, Space_16, Space_19, Space_22, Space_25, Space_28, Space_31, Space_34, Space_37, Space_40, Space_53, Space_56, Space_59, Space_62, Space_65, Space_68")
ws.Range("A13:A31,B13:B31").ClearContents
For i = 1 To 18
If Not IsEmpty("rng") Then
ws.Range("A12").Offset(1).Value = i
End If
Exit For
Next i
If Not IsEmpty("rng") Then
ws.Range("B12").Offset(1).Value = rng.Value
End If
End Sub

This should address the various issues I mentioned in my comment:
Sub test2()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("Sheet1")
Dim i As Long
Dim rng As Range, r As Range
With ws
Set rng = .Range("Space_7, Space_10, Space_13, Space_16, Space_19, Space_22, Space_25, Space_28, Space_31, Space_34, Space_37, Space_40, Space_53, Space_56, Space_59, Space_62, Space_65, Space_68")
.Range("A13:B31").ClearContents
For Each r In rng.Areas
If Not IsEmpty(r) Then
.Range("A13").Offset(i).Value = i + 1
.Range("B13").Offset(i).Value = r.Value
i = i + 1
End If
Next r
End With
End Sub

A couple things here - Instead of trying to put all your named ranges into a Range, put them individually in an Array and cycle through them - If they're not blank, put the value into the cell.
Your .Offset is always going 1 below row 12, so that's why you're only seeing one row of data.
Sub test2()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("Sheet1")
Dim i As Long, j As Long
Dim rngarray As Variant
rngarray = Array("Space_7", "Space_10", "Space_13", "Space_16", "Space_19", "Space_22", "Space_25", "Space_28", "Space_31", "Space_34", "Space_37", "Space_40", "Space_53", "Space_56", "Space_59", "Space_62", "Space_65", "Space_68")
j = 12
ws.Range("A13:B31").ClearContents
For i = 0 To UBound(rngarray)
If ws.Range(rngarray(i)).Value <> "" Then
ws.Range("A12").Offset(j - 11).Value = i + 1
ws.Range("B12").Offset(j - 11).Value = ws.Range(rngarray(i)).Value
j = j + 1
End If
Next i
End Sub

I'd go as follows:
Sub test2()
Dim i As Integer
Dim rng As Range, cell As Range
With ThisWorkbook.Sheets("Sheet1")
.Range("A13:A31,B13:B31").ClearContents
Set rng = .Range("Space_7, Space_10, Space_13, Space_16, Space_19, Space_22, Space_25, Space_28, Space_31, Space_34, Space_37, Space_40, Space_53, Space_56, Space_59, Space_62, Space_65, Space_68")
For Each cell In rng.SpecialCells(xlCellTypeConstants).Areas
ws.Range("A12:B12").Offset(i).Value = Array(i + 1, cell(1, 1).Value)
i = i + 1
Next
End With
End Sub

Related

Excel VBA - Copy Sheet to new workbook X times

I need to copy the same worksheet X times (x = sheet2 row A) into a new workbook.
For each copy I need to:
1.Change a drop down to display the next value
2.Do a Refresh (Workbook is connected to a database which pulls different information based on the value of the drop down and is not automatically refreshed)
3.Copy just the values (no formulas)
Rename the sheet to the value of the drop down.
Save all of the copied worksheets into 1 workbook
My code (below) which is called on a button press currently saves the sheet X times based on sheet2 rowA (as intended).
It is missing steps 1,2,4 and 5
The code I have at the moment (called on button click)
Dim x As Integer '~~>Loop counter
Dim WS As Worksheet
Dim LastCellA As Range, LastCellB As Range
Dim LastCellRowNumber As Long
Set WS = Worksheets("Sheet2") '~~>Sheet with names
With WS
Set LastCellA = .Cells(.Rows.Count, "A").End(xlUp) '~~>Column with names.
'~~>This needs to be changed to find the range as data may not start at A1
x = Application.WorksheetFunction.Max(LastCellA.Row)
End With
For numtimes = 1 To x
ActiveWorkbook.Sheets("Sheet1").Copy _
After:=ActiveWorkbook.Sheets(Worksheets.Count)
'~~>Copy values only
ActiveSheet.UsedRange.Value = ActiveSheet.UsedRange.Value
Next
Still... I'm not sure of the point that you "Import" different values based on a drop down. That may be a different macro for loding the data. Then you need to call that macro instead of the .RefreshAll.
Sub test()
Dim uRow As Long, lRow As Long, i As Long
Dim wb As Workbook, ws As Object
With ThisWorkbook
Set ws = .Sheets("Sheet2")
With ws
uRow = .Cells(.Rows.Count, "A").End(xlUp).End(xlUp).Row
lRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Set wb = Workbooks.Add
For i = uRow To lRow
.Sheets("Sheet1").Range("M1").Value = ws.Cells(i, 1).Value '<~~~ this should change the dropdown
Calculate
.RefreshAll
.Sheets("Sheet1").Copy , wb.Sheets(wb.Sheets.Count)
wb.Sheets(wb.Sheets.Count).Name = ws.Cells(i, 1).Value
Next
Application.DisplayAlerts = False
wb.Sheets(1).Delete
Application.DisplayAlerts = True
For Each ws In wb.Sheets
ws.UsedRange.Value = ws.UsedRange.Value
Next
End With
End Sub
EDIT:
If you get trouble with the Sheet2 Column A List (cus it contains empty cells resulting of formulas) you may try a different approach:
Sub test()
Dim wb As Workbook, ws As Worksheet
Dim xVal As Variant
With ThisWorkbook
Set ws = .Sheets("Sheet2")
Set wb = Workbooks.Add
For Each xVal In Intersect(ws.Range("A:A"), ws.UsedRange).Value
If Len(xVal) Then
.Sheets("Sheet1").Range("M1").Value = xVal
Calculate
.RefreshAll
.Sheets("Sheet1").Copy , wb.Sheets(wb.Sheets.Count)
wb.Sheets(wb.Sheets.Count).Name = ws.Cells(i, 1).Value
wb.Sheets(wb.Sheets.Count).UsedRange.Value = wb.Sheets(wb.Sheets.Count).UsedRange.Value
End If
Next
Application.DisplayAlerts = False
wb.Sheets(1).Delete
Application.DisplayAlerts = True
End With
End Sub
Based on the code you provided, I believe this is what you are looking for.
It will loop through your list, copy sheet1 to the new workbook and name the sheet.
I am not sure what you want with looping through your dropdown list.
Sub Button1_Click()
Dim wb As Workbook, Bk As Workbook
Dim WS As Worksheet, sh As Worksheet
Dim LastCellA As Long, LastCellB As Range, c As Range
Dim LastCellRowNumber As Long
Dim x As Integer '~~>Loop counter
Set wb = ThisWorkbook
Set WS = wb.Worksheets("Sheet2") '~~>Sheet with names
Set sh = wb.Sheets("Sheet1")
With WS
LastCellA = .Cells(.Rows.Count, "A").End(xlUp).Row '~~>Column with names.
'~~>This needs to be changed to find the range as data may not start at A1
Set LastCellB = .Range("A1:A" & LastCellA).SpecialCells(xlCellTypeConstants, 23)
End With
Set Bk = Workbooks.Add
For Each c In LastCellB.Cells
sh.Range("M1") = c
sh.Copy After:=Bk.Sheets(Worksheets.Count)
With ActiveSheet
'~~>Copy values only
.UsedRange.Value = .UsedRange.Value
.Name = c
End With
Next c
End Sub

How do I use Loop with Variable Range

In the following code, when I get to for each curCell in Range(i) it is not able to understand the Range that I am referencing. I receive a Method 'Range' of Object'_worksheet' failed. I know the current Range(i) is incorrect, but I have tried every variation and nothing seems to work.
Can someone please help me understand how to get my code to recognize Range1, then Range2, etc?
Sub Worksheet_Change(ByVal Target As Range)
Dim Range1 As Range, Range2 As Range, Range3 As Range, Range4 As Range
Dim curCell As Variant
Dim i As Integer
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(cCostingQSheet)
Set Range1 = ws.Range("E6:E9")
Set Range2 = ws.Range("E15:E19")
Set Range3 = ws.Range("E21")
Set Range4 = ws.Range("E23")
For i = 1 To 4
For Each curCell In Range(i).Cells
If Not WorksheetFunction.IsNumber(curCell) = True Then
curCell.Value = 0
Else
End If
Next
Next
End Sub
You need to use an array if you want a setup like that. Here's how:
Replace your variable declaration statement
'Instead of your original
'Dim Range1 As Range, Range2 As Range, Range3 As Range, Range4 As Range
'Use this:
Dim arrRanges(1 To 4) As Range
Then change how you set the ranges:
Set arrRanges(1) = ws.Range("E6:E9")
Set arrRanges(2) = ws.Range("E15:E19")
Set arrRanges(3) = ws.Range("E21")
Set arrRanges(4) = ws.Range("E23")
And when you loop through them, it looks like this:
For Each curCell In arrRanges(i).Cells
You could assign an non-contiguous range to a range variable instead of using either 4 different range variables or an array of ranges (as #tigeravatar suggested in their excellent answer). Something like this:
Sub test()
Dim R As Range
Dim myCell As Range
Dim ws As Worksheet
Dim i As Long
Set ws = ActiveSheet
Set R = ws.Range("E6:E9,E15:E19,E21,E23")
i = 1
For Each myCell In R.Cells
myCell.Value = i
i = i + 1
Next myCell
End Sub
I would go a step further and
Look at each range inside the overall range.
use a variant array to process the range (where the range area is more than one cell), then dump back to the range.
code
Sub recut()
Dim rng1 As Range
Dim rng2 As Range
Dim lngCol As Long
Dim lngRow As Long
Dim ws As Worksheet
Set ws = ActiveSheet
Set rng1 = ws.Range("E6:E9,E15:E19,E21,E23")
For Each rng2 In rng1.Areas
If rng2.Cells.Count > 1 Then
x = rng2.Value
For lngRow = 1 To UBound(x)
For lngCol = 1 To UBound(x, 2)
If IsNumeric(x(lngRow, lngCol)) Then x(lngRow, lngCol) = 0
Next
Next
rng2.Value2 = x
Else
If IsNumeric(rng2.Value) Then rng2.Value = 0
End If
Next rng2
End Sub

Create worksheets based on lists

I am stuck at the following problem:
I am going through a certain range trough each item and then trying to create a new worksheet each time there is a new name in the range. (The range has several rows with the same name)
I am getting the range with the following code:
Set r = Range("a6", Range("a6").End(xlDown))
For Each Item In r
If Item.text[i]==item.text[i-1] Then create worksheet
Next Item
I can't figure out how to program the for each
Can anyone give a good suggestion ?
First I think Item is a restricted name.
Second in vb == is not what other languages use.
Third offset(row,Column) will move up/down/left/right
Dim r as range, rng as range
Set r = Range("a6", Range("a6").End(xlDown))
For Each rng In r
If rng <> item.offset(-1) Then
dim ws as worksheet
set ws =worksheets.add
ws.name = rng
end If
Next rng
This?
Set r = Range("a6", Range("a6").End(xlDown))
For Each Item In r
If Item.text[i]==item.text[i-1] Then 'this line has errors, but I'll let you fix it
Set NewSheet = ThisWorkbook.Worksheets.Add
End If
Next Item
Sub aAddworksheet()
Dim rRange As Range
Dim wb As Workbook
Dim ws As Worksheet
Dim lastrow As Long
Set wb = ThisWorkbook
Set ws = wb.ActiveSheet
Set rRange = ws.Range("A1:A10")
i = 1
For Each Item In rRange
Debug.Print Item(i)
If i > 1 Then
If Item(i).Value = Item(i - 1).Value Then
Set NewSheet = wb.Worksheets.Add()
End If
End If
i = i + 1
Next Item
End Sub

VBA Loop Debugging - Next Without For

Essentially Im trying to copy and insert a certain range of cells on the second sheet as the program loops through a range of cells on the first sheet as long as the cells arent empty. I need the copy and insert range to change to the newly copy and inserted cells for each loop. Any help would be much appreciated
Private Sub CommandButton1_Click()
Dim ws As Worksheet
Dim rng As Range
Dim i As Integer
Dim j As Integer
For i = 12 To 24
Set ws = ThisWorkbook.Sheets("Input")
With ws
If Not IsEmpty(Cells(i, 2)) Then
For j = 10 To -2
Set ws = ThisWorkbook.Sheets("Budget Output #2")
With ws
Set rng = .Range("Cell(5,i-j):Cell(17,i-j+1)")
rng.Copy
rng.Offset(0, 2).Insert Shift:=xlToRight
rng.Offset(0, 2).ColumnWidth = 20
Application.CutCopyMode = False
Next j
Next i
End If
End With
End With
End Sub
You do not need the With statements for ONE line. This will be much cleaner. Also with two sheets, you should use TWO sheet variables. Finally, I cleaned up your Range(Cells, Cells) syntax. Although, this will still not work because of your For j = 10 to -2. To move backwards, you have to use a Step -#.
Private Sub CommandButton1_Click()
Dim wsIn As Worksheet, wsOut As Worksheet
Dim rng As Range
Dim i As Integer
Dim j As Integer
Set wsIn = ThisWorkbook.Sheets("Input")
Set wsOut = ThisWorkbook.Sheets("Budget Output #2")
x = 2
For i = 12 To 24
If Not IsEmpty(wsIn.Cells(i, 2)) Then
Set rng = wsOut.Range("B:C")
rng.Copy
rng.Offset(0, x).Insert Shift:=xlToRight
rng.Offset(0, x).ColumnWidth = 20
Application.CutCopyMode = False
x = x + 2
End If
Next i
End Sub
I will let you figure out the answer. Here is the correct structure:
For i ....
For j ...
with ws
end with
next j
next i
You have two ws variables Possibly start your code out right.
Dim ws As Worksheet, sh As Worksheet
Set ws = Sheets("Budget Output #2")
Set sh = Sheets("Input")

Using cell value to specify the paste location in Excel VBA

I have a table with two rows : the first row contains the locations where the value of the second row should be pasted.
For example :
row 1 : sheet8!D2 sheet6!D2 sheet2!C5
row 2 : apple lemon pEER
So apple should be pasted in sheet 8 cell D8. Lemon should be pasted in sheet6 cell D2. The problem is that the value apple is pasted everywhere (in sheet8!D2, sheet6!D2 and sheet2!C5). How can I correct this?
Sub Sample()
Dim rng As Range
Dim Sh As String, Cl As String
Dim ws As Worksheet
Dim i As Integer
Dim Row1 As String
ncol = Range("A1:F1").Columns.Count
For i = 1 To ncol
Row1 = Range("A1:F1").Cells(1, i).Value
Set ws = ThisWorkbook.Sheets("Sheet2")
With ws
Sh = Split(Row1, "!")(0)
Cl = Split(Row1, "!")(1)
Set rng = ThisWorkbook.Sheets(Sh).Range(Cl)
rng.Value = .Range("A2").Value
End With
Next i
End Sub
There are a few issues with your code. First up its good practice to put Option Explicit at the top of each module, this will ensure variables are defined (ncol is not defined).
The following code will fix the problem although it could be tweaked in various ways. The main problem is you don't quite set the referencing ranges correctly, you move through the columns with your loop but always refer back to cell A2. Assuming your input data is on rows 1 and 2 and run from the sheet with that data this will work.
Sub SampleFixed()
Dim rng As Range
Dim Sh As String, Cl As String
Dim ws As Worksheet
Dim i As Integer, ncol As Integer
Dim Row1 As String
ncol = Range("A1:F1").Columns.Count
For i = 1 To ncol
Set ws = ActiveSheet
With ws
Row1 = .Cells(1, i).Value
If Len(Row1) > 0 Then
Sh = Split(Row1, "!")(0)
Cl = Split(Row1, "!")(1)
Set rng = ThisWorkbook.Sheets(Sh).Range(Cl)
'Here you were always refering to cell A2 not moving through the values which was the main problem.
rng.Value = .Cells(2, i).Value
End If
End With
Next i
End Sub