I'm having a problem of iterating through a range of items in a for loop:
How the procedure is supposed to work-
I start off on worksheet 1("Tracking Spreadsheet"), and depending on a change in worksheet 1 ( selecting "yes" in a cell) it would transfer you to worksheet 2("Deferred Submittals") and then iterate through a range of cells ( A1:A20 for example) from worksheet 2. The for loop would keep going until it reached a cell that was empty, and stop and then proceed to write into that cell.
How its working now-
I start off on worksheet 1, and depending on a change in worksheet 1 ( selecting "yes" in a cell) it would transfer you to worksheet 2 and then iterate through a range of cells ( A1:A20 for example) from worksheet 2. However, instead of iterating through worksheet 2's A1:A20, it would iterate through worksheet 1's A1:A20. After it found an empty cell in worksheet 1's A1:A20 range, it would then fill in the corresponding cell in Worksheet 2 ( If A5 is empty on worksheet 1, it would then fill in A5 on worksheet 2).
I was hoping to get help on having the range iterate through the active sheet at the time ( worksheet 2) instead of iterating through worksheet 1.
My code so far:
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
' Deferred Submittal, Column C = 3
Dim cellTextDS As String
Dim deferredArray As Range, deferredCell As Range, deferredRowEmpty As Long
deferredRowEmpty = 1
' Deferred Submittal, Column C
If Target.Column = 3 Then
Row = Target.Row
cellTextDS = ActiveSheet.Range("C" & Row).Text
If cellTextDS = "Yes" Then
Sheets(3).Activate
Set deferredRange = Workbooks("BPS Tracking Sheet v6.xlsm").Worksheets("Deferred Submittals").Range("A1:A20")
For Each deferredCell In deferredRange
Sheets(3).Activate
MsgBox "inside deferredCell is " & deferredCell
MsgBox " active sheet currently is " & name
If IsEmpty(Range("A" & deferredRowEmpty).Value) = True Then Exit For
MsgBox " deferredRowEmpty is " & deferredRowEmpty
deferredRowEmpty = deferredRowEmpty + 1
Next deferredCell
MsgBox "Moving to 'Deferred Submittals' tab in order to input more information. row is " & deferredRowEmpty
ActiveSheet.Range("A" & deferredRowEmpty).Value = "empty"
End If
End If
End Sub
Any help would be really appreciated!
p.s. the code is in the worksheet_change section of worksheet 1 if that makes any difference.
p.s.s. I've tried using this stackoverflow method for setting workbooks and worksheets, to no avail
p.s.s.s. posted the rest of my code for this portion. There is more code in this section, but it is literally just copy and paste of this section but for different columns. I've also edited what worksheet 1 and 2 are, but they are the different worksheet tabs in this workbook, specifically worksheet 1 = "Tracking Spreadsheet" and worksheet 2 = "Deferred Submittals"
OK - I think this is the kind of thing you're looking for. When using the worksheet_change event there are a few things that should be done.
Disabling events means the macro can run without triggering further erroneous change calls and therefore having some error management is required.
I have left a commented line which may be of use so that any changes on multiple cells at one time won't trigger further changes and will just exit the sub
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
'If Target.Cells.Count > 1 Then Exit Sub
If Target.Column <> 3 Then Exit Sub
On Error GoTo ExitSub
Application.EnableEvents = False
Dim wsSource As Worksheet: Set wsSource = Me
Dim wsTarget As Worksheet: Set wsTarget = ThisWorkbook.Worksheets("Deferred Submittals")
Dim NextEmpty As Range
If wsSource.Cells(Target.Row, 3) = "Yes" Then
Set NextEmpty = wsTarget.Range("A1:A20").Find("", LookIn:=xlValues)
If Not NextEmpty Is Nothing Then
Debug.Print NextEmpty.Address ' Function check
NextEmpty.Value = Target.Row ' Or whatever you want the value to be
End If
End If
ExitSub:
Application.EnableEvents = True
End Sub
Related
I have data in Column A in excel..I am iterating through column and i need to find if a cell value has hyperlink init.
LR=Activeworkbook.Worksheets("Emp").Range("A65000").End(xlup).Row
for j=1 to LR
if Thisworkbooks.Worksheets("Emp").cells(j,1)="" then 'Logic to find hyperlink
'Function
end if
next
Identify Cells Containing Hyperlinks
As Red Hare already mentioned in the comments, it is best tested with something like the following:
Dim cell As Range: Set cell = Sheet1.Range("A1")
If cell.Hyperlinks.Count > 0 Then ' has a hyperlink
Else ' has no hyperlink
End If
that is, using the Hyperlinks.Count property of the Hyperlinks object returned by the cell's Hyperlinks property which is a collection of hyperlinks in a range (in this case, a single cell). For a single cell, the Count property will return only 0 or 1 so you could actually use
If cell.Hyperlinks.Count = 1 Then ' has a hyperlink
instead.
Example Code
Option Explicit
Sub IdentifyCellsWithHyperlink()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' If it's not, modify accordingly.
Dim ws As Worksheet: Set ws = wb.Worksheets("Emp")
Dim rg As Range
Set rg = ws.Range("A2", ws.Cells(ws.Rows.Count, "A").End(xlUp))
Dim cell As Range
For Each cell In rg.Cells
If cell.Hyperlinks.Count > 0 Then ' has a hyperlink
Else ' has no hyperlink
End If
Next cell
End Sub
Here is something that can be used to run through each row to determine if it can be set as a hyperlink. Kinda hard to figure out what the range of possible solutions are that will work for you without fully understanding the context...
Private Sub cmdFollowLink_Click()
CreateHyperlink Me!cmdFollowLink, Me!txtSubAddress, _
Me!txtAddress
End Sub
Sub CreateHyperlink(ctlSelected As Control, _
strSubAddress As String, Optional strAddress As String)
Dim hlk As Hyperlink
Select Case ctlSelected.ControlType
Case acLabel, acImage, acCommandButton
Set hlk = ctlSelected.Hyperlink
With hlk
If Not IsMissing(strAddress) Then
.Address = strAddress
Else
.Address = ""
End If
.SubAddress = strSubAddress
.Follow
.Address = ""
.SubAddress = ""
End With
Case Else
MsgBox "The control '" & ctlSelected.Name _
& "' does not support hyperlinks."
End Select
End Sub
I'm trying to generate a code that will fill cells in a row based on the input of the selected cell. In a nutshell, there's 6 steps and the goal is to type "Step 6" in one cell and have Steps 5-1 generate in the 5 cells to the right, however the code cannot be restricted to a fixed cell and must move relative to the first cell selected. Is this possible? Ive used the week autofill as reference below but am lost.
Sub Weekday_Data_Update()
Dim startRange As Range
Dim stopRange As Range
Set startRange = Sheets("Sheet1").Range("A2")
'Specify the cell until which you want weekdays to be displayed
Set stopRange = Sheets("Sheet1").Range("A2:A6") startRange.Select
Selection.AutoFill Destination:=stopRange, Type:=xlFillWeekdays
End Sub
Like this (code goes in the worksheet module)
Private Sub Worksheet_Change(ByVal Target As Range)
Dim v, i As Long
If Target.CountLarge > 1 Then Exit Sub 'only tracking single-cell changes
v = Target.Value
If IsError(v) Then Exit Sub 'cell has error - exit
If v = "Step 6" Then
For i = 5 To 1 Step -1
Target.Offset(0, 6 - i).Value = "Step " & i
Next i
End If
End Sub
I have a form that is automatically filled when user chooses job position, however in 3 sections I have drop-down lists (B21:B45, B27:B30, B50:B67) and users will be allowed to change max 2 options from these drop-down lists.
In other words I have a table B21:C45 and if user will modify 2 out of 25 cells in column B then macro will automatically give a message that you've modified the maximum number of cells and then macro will lock cells B21:B45. The same applies to other 2 tables (so for RngTwo and RngThree).
I've tried to use Intersect function but I am not sure how to write a macro that would lock specific range of cells if 2 cells in this range are changed. The biggest challenge for me is that macro needs to take into condsideration all 3 ranges.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim RngOne As Range
Dim RngTwo As Range
Dim RngThree As Range
Set RngOne = Range("B21:B45")
Set RngTwo = Range("B27:B30")
Set RngThree = Range("B50:B67")
If Not Application.Intersect(RngOne, Range(Target.Address)) Is Nothing Then
MsgBox "You changed " & Target.Count & " out of " & RngOne.Count & " cells."
End If
End Sub
You may like to try this code.
Private Sub Worksheet_Change(ByVal Target As Range)
' 048
Static Count(1 To 3) As Integer
Dim Rng As Range
Dim i As Integer ' array index
If Target.CountLarge > 1 Then Exit Sub
Set Rng = Application.Union(Range("B21:B25"), Range("B27:B30"), Range("B50:B67"))
For i = 1 To 3
If Not Application.Intersect(Rng.Areas(i), Target) Is Nothing Then
If Count(i) < 2 Then
Count(i) = Count(i) + 1
Else
MsgBox "You have exceeded the maximum number (2)" & vbCr & _
"of permissible changes in this section." & vbCr & _
"This change will be rolled back.", _
vbInformation, "Too many changes"
With Application
.EnableEvents = False
.Undo
.EnableEvents = True
End With
End If
Exit For
End If
Next i
End Sub
The three ranges you set are overlapping, and that would require more precise coding once you specify what you really mean. For the moment I have just presumed that there is a type in one of the addresses and set the first range as B21:B25 instead of B21:B45.
Anyway, this is only to show the approach. The solution is only perfunctorily tested. Should errors occur when you test please let me know and I shall fix them.
My solution is that there are two subs working together. The startSelection is storing the status of the ranges into the arrays. It shall be triggered before let the user starting changes.
Then the Worksheet_Change compare the values and calculate how many cells has been changed. Calling the startSelection can be re-initiated the process.
I have not finalized the sub for all the ranges so it shall be finished if this solution is considered good.
Dim RngOne As Range ' Global variables
Dim RngTwo As Range
Dim RngThree As Range
Dim vOne As Variant
Dim vTwo As Variant
Dim vThree As Variant
Sub startSelection()
Set RngOne = Range("B21:B45")
Set RngTwo = Range("B27:B30")
Set RngThree = Range("B50:B67")
vOne = RngOne.value
vTwo = RngTwo.value
vThree = RngThree.value
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
If RngOne Is Nothing Then Call startSelection
If Intersect(Target, Union(RngOne, RngTwo, RngThree)) Is Nothing Then
Exit Sub
End If
Dim i As Integer
Dim rng As Range
Dim iChanged As Integer
iChanged = 0
For Each rng In RngOne
i = i + 1
If vOne(i, 1) <> rng.value Then iChanged = iChanged + 1
Next rng
'should be repeated for the other two ranges
If iChanged > 2 Then
MsgBox "You changed " & iChanged & " out of " & RngOne.Count & " cells."
End If
End Sub
I need to copy the contents of cells A2 to A88 and C2 to C88 based on the contents of what is in cells in column G from several spreadsheets in a workbook to the Summary sheet.
So I need code to scan all spreadsheets to see if the word Case closed is in cell G33 and than copy the contents of cell A33 and C33 to a cell on the summary page.
I have seen several close answers but nothing that does the job.
Sorry no code available.
Thanks for any and all answers.
You could create some vba if you cannot solve this using excel formulas... I made a little test excel sheet with following vba code:
Sub test()
processSheet Application.ActiveWorkbook, "Sheet1"
End Sub
Function FindSheet(currentWorkbook As Workbook, sheetName As String) As Worksheet
If currentWorkbook Is Nothing Then
Err.Raise vbObjectError + 1, "FindSheet", "Supplied workbook is nothing"
End If
Dim idx As Integer
For idx = 1 To currentWorkbook.Sheets.Count
Dim checkSheet As Worksheet
Set checkSheet = currentWorkbook.Sheets.Item(idx)
If checkSheet.Name = sheetName Then
Set FindSheet = checkSheet
Exit Function
End If
Next
End Function
Function IsEmpty(currentCell As Range) As Boolean
IsEmpty = False
If currentCell.Value = "" And currentCell.Value2 = "" Then
IsEmpty = True
End If
End Function
Sub processSheet(currentWorkbook As Workbook, sheetName As String)
On Error GoTo Catch
Dim currentSheet As Worksheet
Set currentSheet = FindSheet(currentWorkbook, sheetName)
If currentSheet Is Nothing Then
Err.Raise vbObjectError + 2, "ProcessSheet", "Could not find sheet " + sheetName
End If
Dim colA As Range
Dim colB As Range
Dim colCondition As Range
Dim colResult As Range
currentSheet.Activate
Set colA = currentSheet.Columns(1)
Set colB = currentSheet.Columns(2)
Set colCondition = currentSheet.Columns(3)
Set colResult = currentSheet.Columns(4)
Dim index As Integer: index = 2
Dim run As Boolean: run = True
Do While run
If IsEmpty(colA.Rows(index)) And IsEmpty(colB.Rows(index)) And IsEmpty(colCondition.Rows(index)) Then
run = False
Else
index = index + 1
If colCondition.Rows(index).Value = "Closed" Then
resultContent = CStr(colA.Rows(index).Value2) + ": " + CStr(colB.Rows(index).Value2)
Else
resultContent = "-"
End If
colResult.Rows(index).Value2 = resultContent
End If
Loop
GoTo Finally
Catch:
MsgBox ("An error occured: " + Err.Description)
Exit Sub
Finally:
End Sub
You can just put this macro in the macros of a new workbook. Open the Sheet1 and add 4 columns. I added a screenshot of how the excel sheet looks like.
As a new user I'm not allowed to post images.. so here is the link: Sheet1
Short explanation of the code.
A workbook is passed and a sheet selected by a sheet name
If the sheet is available the script runs through the three dependent columns (two columns needed for concatenation and one for the condition) and checks if the values are set. The loop stops when all the three columns do not contain any value (in your case you could hardcode the start and end index, if it always stays the same).
During the iteration, the condition field is checked. If it is equals "Closed", the result cell is filled with the first two columns values concatenated.
You certainly need to adapt the code to your problem, but shouldn't be a big thing to do.
I have a sheet in which I have data from two different sources.I've a blank row between them.I want to make this blank row as my delimiter.How can I find out if the entire row is blank or not.
If you're talking a literal entire row then code similar to this should work (so long as there are no formulas or spaces present in any of the cells as well):
If Application.CountA(ActiveCell.EntireRow)=0 Then
MsgBox "Row Empty"
Exit Sub
End If
Otherwise, for a range from a row:
Dim neValues As Range, neFormulas As Range, MyRange As Range
Set MyRange = Columns("C:AA")
On Error Resume Next
Set neValues = Intersect(ActiveCell.EntireRow.SpecialCells(xlConstants), MyRange)
Set neFormulas = Intersect(ActiveCell.EntireRow.SpecialCells(xlFormulas), MyRange)
On Error GoTo 0
If neValues Is Nothing And neFormulas Is Nothing Then
MsgBox "Nothing There"
Else
MsgBox "Something's There"
End If
(Source: http://www.ozgrid.com/forum/showthread.php?t=26509&page=1)
WorksheetFunction.CountA(), as demonstrated below:
Dim row As Range
Dim sheet As Worksheet
Set sheet = ActiveSheet
For i = 1 To sheet.UsedRange.Rows.Count
Set row = sheet.Rows(i)
If WorksheetFunction.CountA(row) = 0 Then
MsgBox "row " & i & " is empty"
End If
Next i