I understand how to use the offset function for a dynamic range, but what if that dynamic range is within a specific number of additional columns? For example, say I have a worksheet with columns A:N, and the named range refers to D2:E2. If I add two more columns, that range should expand to D2:G2, but not include columns F and onward.
I'm currently using the offset function with the counta function to do this, but there are a number of natural blank cells within this range (because of merged cells). Is there a way for me to remove these blanks for use in the combobox's dropdown?
Currently I've defined the name as:
=OFFSET('Sheet 1'!$D$2,0,0,1,COUNTA('Sheet 1'!$D2:$ZZ2))
Which returns all of the values I'm looking for, but several blanks as well that I don't want in the dropdown.
I'm currently using the following code during the userform's initialization, but this doesn't seem to be working either:
Dim Rng As Range
Dim i As Long
Me.ComboBox1.RowSource = ""
Set Rng = Range("Combo")
For i = 1 To Rng.Rows.Count
If Rng(i) <> "" Then
Me.ComboBox1.AddItem Rng(i)
End If
Next i
I've also tried
Dim aCell As Range, ws1 As Worksheet, lastColumn As Long, stopColumn As Long
Set ws1 = Worksheets("sheet 1")
With ws1
lastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
stopColumn = lastColumn - 12
Me.ComboBox1.RowSource = ""
With ws1
For Each aCell In .Range("D2", .Cells(2, stopColumn))
If aCell.Value <> "" Then
Me.ComboBox1.AddItem aCell.Value
End If
Next
End With
Neither attempt has worked though, the combobox dropdown is empty.
The second part of the code above actually was functional, I was just using the wrong procedure name. I was using UserForm2, and had renamed the initialize procedure Private Sub UserForm2_Initialize() when it should have instead been `Private Sub UserForm_Initialize()
Related
I'm currently trying to copy a filtered column to an array to populate a ComboBox in a Powerpoint presentation.
The line of code I'm using to do this is:
ar = tbl.ListColumns(ColNumber).Range.SpecialCells(12).Value
Where "ar" is the destination array, "tbl" is the source table and "ColNumber" is the number of column I'm trying to copy.
The filtered column I'm trying to copy has around 180 records but I noticed the destination array has 6 values since it selected only until the first "hidden" row in the range, and skipped every other visible row after that.
Is there a way to get the value of every visible row and not just the first ones?
You are facing that issue because of Non Contigous range. You cannot use the method Array = Range.Value for Non Contigous range. There are two ways you can follow to achieve what you want.
WAY 1 Identify the Range, Loop through the cells and populate the array. Suitable for your case as you are dealing with single column.
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim tbl As ListObject
Dim ar As Variant
Dim i As Long, n As Long, ColNumber As Long
Dim aCell As Range, rng As Range
'~~> Change this to the relevant sheet
Set ws = Sheet1
'~~> Change this to the relevant table
Set tbl = ws.ListObjects("Table1")
ws.AutoFilterMode = False
'~~> Change to relevant column number
ColNumber = 1
'~~> Autofilter as required
tbl.Range.AutoFilter Field:=ColNumber, Criteria1:="Blah1"
'~~> Set your range
Set rng = tbl.ListColumns(ColNumber).Range.SpecialCells(12)
'~~> Get the count of cells in that range
n = rng.Cells.Count
'~~> Resize the array to hold the data
ReDim ar(1 To n)
n = 1
'~~> Store the values from that range into the array
For Each aCell In rng.Cells
ar(n) = aCell.Value
n = n + 1
Next aCell
For i = LBound(ar) To UBound(ar)
Debug.Print ar(i)
Next i
End Sub
WAY 2 Identify the Range, loop thorough the Area and then loop through the cells in that Area and then populate the array. Very similar to the above code.
In Action
Master Dataset- Sheet1
Sub Dataset- Sheet2
Similar to the question on If and Loop function to extract data, I have two worksheets. I am trying to use VBA to input Column M for me- the x's. For example, to the left of apple should be 123, as it is its code, and orange 456 etc., according to the Master Dataset. Because it is a similar problem as the one on the aforementioned site, I tweaked the code a little, but it would not work. It is as follows:
Option Compare Text
Sub DataExtraction()
Dim SrchRng As Range, cel As Range, rngDest as Range
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = Worksheets("Sheet1")
Set ws2 = Worksheets("Sheet2")
'restrict the search range
Set SrchRng = Application.Intersect(ws1.Range("F;F"), ws1.UsedRange)
Set rngDest = ws2.cells(rows.count, 1).end(xlUp).Offset(1, 0) 'start copy here
For Each cel In SrchRng.Cells
If cel.value=rngDest.value Then
rngDest.offset(0, -1).value = cel.offset(0, -1).value
Set rngDest = rngDest.offset(1, 0) '<< next row down
End If
Next cel
End Sub
In short, I am trying to tell VBA that if the Fruit of interest matches, then input the Code found in Column D of Sheet1 into Column M of Sheet 2 accordingly, then move to the next row and repeat the exercise. Any help would be greatly appreciated.
P.S. A very special thanks to Tim Williams for solving my problem previously, and hitherto helping me to set up this model that I used to develop.
There is an easy solution without using VBA. You could do that with formulas too with a combination of MATCH() and INDEX(). This should even be faster.
Just use
=INDEX(Sheet1!D:D,MATCH(N:N,Sheet1!F:F,0))
If you need to automate it, I would write this formula into column M (and if necessary convert the formulas into values):
Option Explicit
Public Sub FillInCodes()
Dim wsSub As Worksheet
Set wsSub = ThisWorkbook.Worksheets("Sheet2")
Dim LastRow As Long
LastRow = wsSub.Cells(wsSub.Rows.Count, "A").End(xlUp).Row
wsSub.Range("M2:M" & LastRow).Formula = "=INDEX(Sheet1!D:D,MATCH(N:N,Sheet1!F:F,0))"
'and if you need to convert the formulas into values
wsSub.Range("M2:M" & LastRow).Value = wsSub.Range("M2:M" & LastRow).Value
End Sub
I have my data in columns A:L in Sheet2 and wish to copy each block based on the starting point, as certain cell text and the end point, again as certain cell text! The data is in columns A:L and move down down block by block
The code I have is very nearly 100% complete, but the last part I am trying to achieve is to put each item in a specific order on the destination sheet. As we know columns are A:L I want to paste my first block into Columns A:L in the destination then the next one in M:X then the final one in Y:AJ.
As there are about 10 of these blocks, Tank Engine, Weatherman etc I envisage, that I will need three blocks first, then a about three rows which are gaps before it is then repeated.
An example of this
The rows are dynamic but never more than 11 in length. The code I have is
Option Explicit
Sub MIKE3()
Dim wsSrc As Worksheet 'define source
Set wsSrc = ThisWorkbook.Worksheets("Sheet1")
Dim wsDest As Worksheet 'define destination
Set wsDest = ThisWorkbook.Worksheets("Sheet2")
Dim FindList As Variant 'defind search words
FindList = Array("Tank Engine")
Dim i As Long
Dim FindItm As Variant
For Each FindItm In FindList
Dim CopyRange As Range
Set CopyRange = FindMyRange(wsSrc.Range("A:L"), FindItm, "INFORMATION: " & FindItm)
If Not CopyRange Is Nothing Then
CopyRange.Copy wsDest.Range("A1").Offset(ColumnOffset:=i) 'note that if the first column uses merged cells the ColumnOffset:=i otherwise it is ColumnOffset:=i*12
i = i + 1
End If
Next FindItm
End Sub
Function FindMyRange(SearchInRange As Range, ByVal StartString As String, ByVal EndString As String) As Range
'find start
Dim FoundStart As Range
Set FoundStart = SearchInRange.Find(What:=StartString, LookAt:=xlWhole)
If FoundStart Is Nothing Then GoTo ERR_NOTHING_FOUND
find end
Dim FoundEnd As Range
Set FoundEnd = SearchInRange.Find(What:=EndString, LookAt:=xlWhole, After:=FoundStart)
If FoundEnd Is Nothing Then GoTo ERR_NOTHING_FOUND
Set FindMyRange = SearchInRange.Parent.Range(FoundStart, FoundEnd).Resize(ColumnSize:=12)
Exit Function'
ERR_NOTHING_FOUND:
FindMyRange = Nothing
End Function
thanks to PEH for his initial help and Thank you for looking!
I managed to make this work by editing the strings in my source data then writing x number of macros to cover my scenarios then calling them one by one in a module
I am trying to clear all the columns after the last header row
The macro runs but no clearing happens, I have played with the syntactic for awhile and am not getting it
Thanks
Sub ClearColumnsAfterLastHeader()
Dim ws As Excel.Worksheet
Dim hNames As Variant
Dim cell
Set ws = ActiveWorkbook.Sheets("Finished")
hNames = ws.Range("A1:R1").Value
For Each cell In hNames
If IsEmpty(cell) Then
cell.EntireColumn.ClearContents
End If
Next cell
End Sub
The main problem of your code is that hNames is array of Variant rather than Range and when you're looping through array For Each cell In hNames, variable cell refers to array element rather than to corresponding cell. So, you can't use cell.EntireColumn.ClearContents, because cell is not Range, but Variant.
As per my understanding of question, you want to determine last filled cell in first row (header row) and clear contents of all columns to the right of last filled header. In that case try code below:
Sub ClearColumnsAfterLastHeader()
Dim ws As Excel.Worksheet
Dim lastHeaderColumn As Long
Set ws = ActiveWorkbook.Sheets("Finished")
With ws
'determine last filled cell in first row
lastHeaderColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
'get of all cells to the right and down and clear contents
.Range(.Cells(1, lastHeaderColumn + 1), _
.Cells(.Rows.Count, .Columns.Count)).ClearContents
End With
End Sub
Cant you just do something like
Sub ClearStuff()
Dim ws As Worksheet
Dim LastCell As Range, ClearRange As Range
Set ws = ActiveWorkbook.Sheets("Finished")
Set LastCell = ws.Cells(1, ws.Columns.Count)
Set ClearRange = Range(LastCell.End(xlToLeft).Offset(0, 1), LastCell)
ClearRange.EntireColumn.ClearContents
End Sub
I have an Excel Sheet with values going in each column from cells 2:21
I need to highlight the corresponding cell in each column with the maximum value and try to loop through it with a macro. But I only know how to do it for a given hard-coded range..
Private Sub Worksheet_Activate()
Dim zelle As Range
For Each zelle In ActiveSheet.Range("B2:B21")
If zelle.Value = Application.WorksheetFunction.Max(Range("B2:B21")) Then
zelle.Interior.ColorIndex = 6
Else
zelle.Interior.ColorIndex = xlNone
End If
Next
End Sub
I tried to use a new range for column which I gave the Range ("B:IT") and iterate through that one but that didnt work.
Maybe it's just 2 or 3 lines?
This might work for you. Instead of using hard-coded ranges, it loops through whatever columns are used and adjusts for columns having different "lengths". It assumes a single header row and column.
Private Sub Worksheet_Activate()
Dim zelle As Range
Dim rng As Range
Dim lCol As Long
Dim lLastRow As Long
With ActiveSheet
For lCol = 2 To .UsedRange.Columns.Count
lLastRow = .Cells(.Rows.Count, lCol).End(xlUp).Row
Set rng = .Range(.Cells(2, lCol), .Cells(lLastRow, lCol))
For Each zelle In rng
If zelle.Value = Application.WorksheetFunction.Max(rng) Then
zelle.Interior.ColorIndex = 6
Else
zelle.Interior.ColorIndex = xlNone
End If
Next
Next lCol
End With
End Sub
An alternative way to do this is without VBA, is to
Calculate the maximum value e.g. at the bottom (=MAX(A1:A10)) and
To use conditional formatting, highlighting the cell(s) that match the result of your =MAX(A1:A10) calculations.
I know that the question referred to VBA, but this makes it dynamic and VBA independent.
Use variables:
Range(Cells(row_var_1, col_var_1),Cells(row_var_2, col_var_2))
Where row_var_1, col_var_1, row_var_2 and col_var_2 are variables that may be iterated in your loop.