I am currently analyzing a schedule with color coded events that occur in a row and the time expands over the columns (there is only color in the cells no text, yes it's dumb but it's out of my control). I am currently able to print the result for one occurrence of an event into another worksheet, but I cannot determine how to make it print the dates for recurring events in different cells (it currently only prints the last time an event occurs). My current code is:
For i = 2 To 93
If Cells(7, i).Interior.Color = "8421631" And Cells(7, i - 1).Interior.Color = "16777215" Then
startDay = Cells(3, i).Value
startMonth = Cells(1, i).Value
name = Cells(7, i).Value
Worksheets("Sheet1").Activate
ActiveWorkbook.Worksheets("Sheet1").Cells(2, 1) = startDay + startMonth
End If
If Cells(7, i).Interior.Color = "8421631" And Cells(7, i + 1).Interior.Color = "16777215" Then
endDay = Cells(3, i).Value
endMonth = Cells(1, i).Value
ActiveWorkbook.Worksheets("Sheet1").Cells(2, 2) = endDay + endMonth
End If
Next i
All of my variables are entered as strings. I attempted a few different methods with no success. I feel that I need to add another loop in my IF statement, but I am unsure as to how to best do it. Overall the code achieves its purpose (previously used message boxes for output to confirm it was operating as it should). This is just a small part of the overall code, but with this answer I would be able to apply it elsewhere.
for what I could grasp out of your description you may try this code:
Option Explicit
Sub main()
Dim i As Long
For i = 2 To 93
If Cells(7, i).Interior.Color = "8421631" Then
If Cells(7, i - 1).Interior.Color = "16777215" Or Cells(7, i + 1).Interior.Color = "16777215" Then
WriteDate Cells(3, i).Value, Cells(1, i).Value
End If
End If
Next i
End Sub
Sub WriteDate(day As String, month As String)
With ActiveWorkbook.Worksheets("Sheet1")
.Cells(2, .Columns.Count).End(xlToLeft).Offset(, 1) = day & "/" & month
End With
End Sub
Related
I have this piece of code
Sub neviem()
Dim ws As Worksheet
Dim i As Range
Dim j As Long
Set i = Range("GKC")
For j = i.Rows.Count To 1 Step -1
If IsEmpty(Range("E3").Value) Then
If i(j, 1) Like Range("E2") Then
i(j, 1).Offset(0, 1).Copy Range("E2").Offset(1, 0)
End If
ElseIf i(j, 1) Like Range("E2") Then
i(j, 1).Offset(0, 1).Copy Range("E2").Offset(1, 0) & "," & Range("E2").Value
End If
Next
End Sub
With this code I'm trying to add multiple text values in the same cell. The first part is ok when I run it, it will add a text value. The problem is when I run it for a second time it gives me an error
runtime err 1004 copy method class failed
so I'm not able to put more text values next to the one I already have.
Is this possible in VBA?
Instead this i(j, 1).Offset(0, 1).Copy Range("E2").Offset(1, 0) & "," & Range("E2").Value
Try this i(j, 1).Offset(0, 1) = Range("E3") & "," & Range("E2")
I know this has been asked many times but I keep reading and cant get it right. I have included all the necessary End If and the Do is there for my Loop.
My Code
Sub update_names()
Dim EMAIL, NewName As String
Dim i, total As Integer
Dim Search As Range
total = 0
i = 2024
Do While i < 2048
Sheets("Edit Multiple Subscribers").Select
EMAIL = Cells(i, 2).Value
NewName = Cells(i, 1).Value
Sheets("MASTER").Select
With Worksheets("MASTER").Cells
Set Search = .Find(EMAIL, LookIn:=xlValues, After:=ActiveCell)
If Search Is Nothing Then
Sheets("Edit Multiple Subscribers").Select
Cells(i, 2).Interior.Color = RGB(250, 0, 250)
GoTo Add1
Else:
Search.Select
ActiveCell.Offset(0, -1).Select
If ActiveCell.Value = NewName Then
GoTo Add1
Else:
NewName = ActiveCell.Value
End If
End If
Sheets("Edit Multiple Subscribers").Select
ActiveSheet.Cells(i, 2).Select
ActiveCell.Offset(0, -1).Select
ActiveCell.Value = NewName
total = total + 1
Add1: i = i + 1
Loop
MsgBox "Number Of edits: " & total
End Sub
You're missing an End With statement, which is equivalent to forgetting an End If-statement as you pointed out yourself.
Side note: I would discourage using GoTo-statements as they make code harder to read and maintain.
The reason for you error already got an answer in #Stanislas answer above.
However, there are a lot other thing you should avoid in your VBA code, like how to avoid using Select, and ActiveCell, instead use fully qualified objects.
Example, in your code you have :
Sheets("Edit Multiple Subscribers").Select
ActiveSheet.Cells(i, 2).Select
ActiveCell.Offset(0, -1).Select
ActiveCell.Value = NewName
This could be replaced with:
Sheets("Edit Multiple Subscribers").Cells(i, 2).Offset(0, -1).Value = NewName
which is not only shorter, but the code will run a lot faster.
Another issue: you have Dim i, total As Integer which means total As Integer but i is actually Variant. You need to define each one explicitly : Dim i As Long, total As Long , I am using Long since it's safer than Integer (can take higher values), and with Windows based x64 systems, they take just as much as memory.
Implementing a few other small modifications, your code could look a little like this:
Option Explicit ' <--- get used to add this at the top of your code
Sub update_names()
Dim EMAIL As String, NewName As String
Dim i As Long, total As Long
Dim Search As Range
total = 0
i = 2024
Do While i < 2048
With Sheets("Edit Multiple Subscribers")
EMAIL = .Cells(i, 2).Value
NewName = .Cells(i, 1).Value
End With
With Worksheets("MASTER")
Set Search = .Cells.Find(EMAIL, LookIn:=xlValues)
If Search Is Nothing Then
Sheets("Edit Multiple Subscribers").Cells(i, 2).Interior.Color = RGB(250, 0, 250)
Else
If Search.Offset(0, -1).Value <> NewName Then
NewName = Search.Value
Sheets("Edit Multiple Subscribers").Cells(i, 2).Offset(0, -1).Value = NewName
total = total + 1
End If
End If
End With
i = i + 1
Loop
MsgBox "Number Of edits: " & total
End Sub
I am trying to conditionally format a range of cells based on the number in the column to each cell groupings' left. Basically, if in row 13, the gray column to the left of each cell grouping = 0, then I want the whole cell grouping to its right to turn green, if = 15, turn yellow, if = 25 turn red. Row 12 is what is happening with my code right now and row 13 is what I want it to look like. I can't seem to get the loop correct.
Sub Highlight3()
For i = 1 To ActiveSheet.Cells(Rows.Count, 4).End(xlUp).Row
If Cells(i, 4) = "Highlight" Then
For j = 1 To 15
Range(Cells(i, j * 4 + 2), Cells(i + 1, j * 4 + 4)).Select
Selection.FormatConditions.Delete
Selection.FormatConditions.Add Type:=xlExpression, Formula1:="=$E$23 = 0"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.Color = rgbRed
End With
Selection.FormatConditions.Add Type:=xlExpression, Formula1:="=$E$23= 15"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.Color = rgbGold
End With
Selection.FormatConditions.Add Type:=xlExpression, Formula1:="=$E$23 = 25"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Interior
.Color = rgbGreen
End With
Next j
End If
Next i
End Sub
Avoid Select because it's slow and unyieldy. Just directly assign your Ranges to variables and work with those.
Sub Highlight3()
For i = 1 To ActiveSheet.Cells(Rows.Count, 4).End(xlUp).Row Step 2
If Cells(i, 4) = "Highlight" Then
For j = 1 To 15
Dim r As Range
Set r = Range(Cells(i, j * 4 + 2), Cells(i + 1, j * 4 + 4))
Dim checkAddress As String
checkAddress = Cells(i, j * 4 + 1).Address
With r.FormatConditions
.Delete
.Add Type:=xlExpression, Formula1:="=" & checkAddress & " = 0"
.Item(.Count).Interior.Color = rgbRed
.Add Type:=xlExpression, Formula1:="=" & checkAddress & " = 15"
.Item(.Count).Interior.Color = rgbGold
.Add Type:=xlExpression, Formula1:="=" & checkAddress & " = 25"
.Item(.Count).Interior.Color = rgbGreen
End With
Next j
End If
Next i
End Sub
Things to notice:
No more ugly use of selection - get the Range r once and do all the tasks with its conditional formatting in one clean block.
No longer sets the new conditional formats to have first priority. Edit that back in if necessary, but I was guessing that it was just something that the Macro Recorder did.
Builds the formatting formula to check against the address directly left of the first cell. Make sure that the expression for checkAddress is what you'd expect, because I had to infer it from your picture and code. If that area with the value 0/15/25 is actually two merged cells (kinda looks like it is), then make sure this formula is for the upper cell, because that cell will be the one that actually holds the value.
Again, hard to tell from just a picture, but it looks like each of your "rows" is actually two cells high (based on your code, too). So you actually want to step through values of i by 2 at a time, not 1 at a time.
If any of the assumptions I've just listed about your table's formatting are wrong, let me know and I'll help iron out any remain kinks in the code.
This should do what you want and also be a bit faster:
Sub Highlight3()
Dim i As Long, j As Byte, myCols As Range, myRng As Range
Set myCols = Range("$B:$D")
For i = 1 To ActiveSheet.Cells(Rows.Count, 4).End(xlUp).Row
If Cells(i, 4) = "Highlight" Then
If myRng Is Nothing Then
Set myRng = Intersect(Rows(i), myCols)
Else
Set myRng = Union(myRng, Intersect(Rows(i), myCols))
End If
i = i + 1 'skip the line after, because it will never have a value / merged cell
End If
Next
If myRng Is Nothing Then Exit Sub
For i = 4 To 60 Step 4
For j = 0 To 1
With myRng.Offset(j, i)
.Cells(1).Offset(-j).Activate
.FormatConditions.Delete 'if that does not interfer with other stuff, better use the next line
'If j = 0 Then myCols.Offset(, i).FormatConditions.Delete
.FormatConditions.Add Type:=xlExpression, Formula1:="=" & .Cells(1).Offset(-j, -1).Address(0) & "=0"
.FormatConditions(.FormatConditions.Count).SetFirstPriority
.FormatConditions(1).Interior.Color = rgbRed
.FormatConditions.Add Type:=xlExpression, Formula1:="=" & .Cells(1).Offset(-j, -1).Address(0) & "=15"
.FormatConditions(.FormatConditions.Count).SetFirstPriority
.FormatConditions(1).Interior.Color = rgbGold
.FormatConditions.Add Type:=xlExpression, Formula1:="=" & .Cells(1).Offset(-j, -1).Address(0) & "=25"
.FormatConditions(.FormatConditions.Count).SetFirstPriority
.FormatConditions(1).Interior.Color = rgbGreen
End With
Next
Next
End Sub
tested it locally and it worked... there may be issues which I can not know (better test it with a copy of your workbook).
The first part pushes all lines in a range which is used in the second part. This way, each pack of columns needs only 2 steps (no need to run EVERY line).
If you have any questions or problems with this code, just ask ;)
First, thanks for reading and any help offered.
I'm basically clueless here. I've spent the last several days trying to figure out how to code what I'd like done, and I'll try to explain it clearly.
My workbook has multiple sheets, but only two of them are of interest regarding this: Schedule & Shift.
On Schedule, there are 17 columns and 40-100 rows containing the employees name (column A) in one column, their initials (B), their employee number (C), their shift (D) and shift hours (E - which is returned via vlookup to another sheet).
Basically, I want a button that will copy the data from each of those 5 columns to the Shift sheet starting at "A3" and continue to copy down the rows in Schedule until it reaches a blank field for their name (which is column A).
So far, I've managed to copy the first row and the second row with the following code:
Private Sub CommandButton1_Click()
Dim i As Integer, IntName As String, IntInit As String, IntID As Integer, Shift As String, Hours As Integer
Worksheets("Schedule").Select
i = 1
IntName = Range("a4")
IntInit = Range("b4")
IntID = Range("C4")
Shift = Range("D4")
Hours = Range("E4")
Do While i < 5
Worksheets("Shift").Select
Worksheets("Shift").Range("a2").Select
If Worksheets("Shift").Range("a2").Offset(1, 0) <> "" Then
Worksheets("Shift").Range("a2").End(xlDown).Select
End If
ActiveCell.Offset(1, 0).Select
ActiveCell.Value = IntName
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = IntInit
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = IntID
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = Shift
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = Hours
Worksheets("Schedule").Select
IntName = Worksheets("Schedule").Range("a4").Offset(1, 0)
IntInit = Worksheets("Schedule").Range("b4").Offset(1, 0)
IntID = Worksheets("Schedule").Range("c4").Offset(1, 0)
Shift = Worksheets("Schedule").Range("d4").Offset(1, 0)
Hours = Worksheets("Schedule").Range("e4").Offset(1, 0)
i = i + 1
Loop
End Sub
Obviously, this is clunky, and it doesn't actually do what I want beyond the 2nd time through the loop.
Any suggestions or pointers to help me move in the right direction?
Thanks again.
You're on the right path, you just need to nest our loop in another loop. Also, heed #BruceWayne's advice.
Private Sub CommandButton1_Click()
Dim i As Integer
Dim intCounter As Integer
Dim IntName As String
Dim IntInit As String
Dim IntID As Integer
Dim Shift As String
Dim Hours As Integer
'Adjust intCounter if you want to start on a row other than 1
intCounter = 1
Do
With Worksheets("Schedule")
IntName = .Cells(intCounter, 1).Value
IntInit = .Cells(intCounter, 2).Value
IntID = .Cells(intCounter, 3).Value
Shift = .Cells(intCounter, 4).Value
Hours = .Cells(intCounter, 5).Value
End With
If IntName = "" Then Exit Do
i = 1
Do While i < 5
'No need to use offset when you can just reference the cell directly.
'Also, not sure why you select this column anyhow.
'These lines can probably be deleted?
'If Worksheets("Shift").Range("a3").Value <> "" Then
' Worksheets("Shift").Range("a2").End(xlDown).Select
'End If
'Avoid using things like Select, ActiveCell, and ActiveSheet.
'What if someone clicks on something while your code is running?? Oops!
With Worksheets("Shift")
.Cells(i + 1, 2).Value = IntName
.Cells(i + 1, 3).Value = IntInit
.Cells(i + 1, 4).Value = IntID
.Cells(i + 1, 5).Value = Shift
.Cells(i + 1, 6).Value = Hours
End With
i = i + 1
Loop
'Increment to go to the next row of Schedule
intCounter = intCounter + 1
Loop
End Sub
brought in by Tim's concern about compact code, try this
Private Sub CommandButton1_Click()
With Worksheets("Schedule").Range("A4:E4").CurrentRegion
.Offset(1).Resize(.Rows.Count - 1).Copy Destination:=Worksheets("Shift").Range("A3")
End With
End Sub
I was running a VBA code in Excel 2007. I got the above mention run/Application error of 1004.
My code is
Public Sub LblImport_Click()
Dim i As Long, j As Long
Dim vData As Variant, vCleanData As Variant, vFile As Variant, sMarket As String
Dim wbkExtract As Workbook, sLastCellAddress As String, month As String
Dim cnCountries As New Collection
Application.ScreenUpdating = False
' Get the name of the Dataview Extract file to transform and the market name
vFile = "D:\DRX\" & "Norvasc_Formatted.xlsx"
sMarket = "Hypertension"
ThisWorkbook.Worksheets("Control").Range("TherapeuticMarket").Value = "Hypertension"
' Clear all existing data from this workbook
ThisWorkbook.Worksheets("RawData").Cells.ClearContents
' Create labels in Raw Data Sheet
ThisWorkbook.Worksheets("RawData").Cells(1, 1).Value = "Therapy Market"
ThisWorkbook.Worksheets("RawData").Cells(1, 2).Value = "Country"
ThisWorkbook.Worksheets("RawData").Cells(1, 3).Value = "Brand"
ThisWorkbook.Worksheets("RawData").Cells(1, 4).Value = "Corporation"
ThisWorkbook.Worksheets("RawData").Cells(1, 5).Value = "Molecule"
' Open Dataview extract, copy and clean data
Set wbkExtract = Workbooks.Open(vFile)
i = 2
Do While wbkExtract.ActiveSheet.Cells(1, i).Value <> ""
If UCase(Mid(wbkExtract.ActiveSheet.Cells(1, i).Value, 1, 3)) = "TRX" Then
month = Split(wbkExtract.ActiveSheet.Cells(1, i).Value, "/")(1)
If Len(month) = 1 Then
month = "0" + month
End If
ThisWorkbook.Worksheets("RawData").Cells(1, i + 4).Value = Mid(wbkExtract.ActiveSheet.Cells(1, i).Value, 1, 10) + month + "/" + Mid(Split(wbkExtract.ActiveSheet.Cells(1, i).Value, "/")(2), 3, 2)
End If
If UCase(Mid(wbkExtract.ActiveSheet.Cells(1, i).Value, 1, 3)) = "LCD" Then
month = Split(wbkExtract.ActiveSheet.Cells(1, i).Value, "/")(2)
If Len(month) = 1 Then
month = "0" + month
End If
ThisWorkbook.Worksheets("RawData").Cells(1, i + 4).Value = Mid(wbkExtract.ActiveSheet.Cells(1, i).Value, 1, 14) + month + "/" + Mid(Split(wbkExtract.ActiveSheet.Cells(1, i).Value, "/")(3), 3, 2)
End If
i = i + 1
Loop
wbkExtract.ActiveSheet.Cells(1, 1).EntireRow.Delete
vData = wbkExtract.ActiveSheet.Cells(1, 1).CurrentRegion.Value
wbkExtract.Close savechanges:=False
vCleanData = CleanRawData(vData, sMarket)
sLastCellAddress = ThisWorkbook.Worksheets("RawData").Cells(UBound(vCleanData, 1) + 1, UBound(vCleanData, 2)).Address(RowAbsolute:=False, ColumnAbsolute:=False)
ThisWorkbook.Worksheets("RawData").Range("A2:" & sLastCellAddress).Value = vCleanData
' Get List of Unique Countries
On Error Resume Next
For i = 1 To UBound(vCleanData, 1)
cnCountries.Add vCleanData(i, 2), vCleanData(i, 2)
Next i
On Error GoTo 0
ThisWorkbook.Worksheets("Market").Cells(1, 1).CurrentRegion.Clear
ThisWorkbook.Worksheets("Market").Cells(1, 1).Value = "Country"
ThisWorkbook.Worksheets("Market").Cells(1, 2).Value = "Group 1"
ThisWorkbook.Worksheets("Market").Cells(1, 3).Value = "Group 2"
ThisWorkbook.Worksheets("Market").Cells(1, 4).Value = "Group 3"
ThisWorkbook.Worksheets("Market").Cells(1, 5).Value = "Group 4"
ThisWorkbook.Worksheets("Market").Range("A1:G1").Font.Bold = True
For i = 1 To cnCountries.Count
ThisWorkbook.Worksheets("Market").Cells(i + 1, 1).Value = cnCountries.Item(i)
Next i
End Sub
Sounds like a broken code cache.
I've seen errors happen like this before in older format (xls) workbooks and it can be a sign of problems in the file overall.
Try the compile option suggested by #Scott Holtzman first. In some cases I've seen the recompile not work and if that happens just force a compile by making a change to the code. A trivial change is enough usually.
If that doesn't work then (to help disagnose a corruption issue) try copying the code into a new workbook and see what happens there. If it runs in the new sheet then I wouldn't waste more time on it and just rebuild the sheet, trust me it'll be quicker than messing about troublshooting the one you have.