Overwriting a formula in Excel using VBA - excel

Here is the formula in question.
.Range("F5").Formula = "=SUMPRODUCT(--(I23:I29>='Raw Data'!K2),--(I23:I29<='Raw Data'!K3))"
This works fine, but what I want is instead of I23:I29, I want it so that when I did a "lastrow" formula in excel VBA, it will replace the I29, with the I and whatever the response in the last row actually is.
I figured that to make this happen I'd have to break the parentheses, but I wasn't sure if it was the correct thing to do.
What I thought I'd have to do is this:
.Range("F5").Formula = "=SUMPRODUCT(--(I23:I" & lastrow">='Raw Data'!K2),--(I23:I" & lastrow"<='Raw Data'!K3))"
But it doesn't look right. And Excel is giving me a redline for it as well, so I know I'm not doing it correctly. Can someone help me figure out this little nightmare?

Close - watch out, and make sure the & are between every part of the string build:
.Range("F5").Formula = "=SUMPRODUCT(--(I23:I" & lastrow & ">='Raw Data'!K2),--(I23:I" & lastrow & "<='Raw Data'!K3))"

Related

Odd behaviour by automatically changing color of certain characters in a cell

I'm facing a odd behavior by applying different colours within one cell via VBA.
In my case there are hundrets of cells within one column, showing different work-packages.
My vba code exaclty does what it should do, by coloring identified strings (respecively work packages) via looping through the cells and identifiying each work package via RegExp.
Here there is one extract that is doing the coloring job:
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Global = True
.Pattern = suchmuster
If .test(objWks_myTable.Cells(row_myTable, 20).Value) Then
Set RegMC = .Execute(objWks_myTable.Cells(row_myTable, 20).Value)
For Each RegM In RegMC
objWks_myTable.Cells(row_myTable, 20).Characters(RegM.FirstIndex + 1, RegM.Length).Font.Color = vbOrange
Next
End If
End With
The issue appears as soon as I double click the cell after my makro run.
Then without any recognizable pattern, some characters are shown in a different color (mostly not only one character but a connected bunch of). In the picutre, the first cell shows the colours after my vba run, the second cell shows how it will immediately look like, if i double click it.
If I leave the edit mode via Escape, the original vba set colors will stay, If I leave the edit mode via Return, the undefined changes happen.
There are no formats nor format conditions set within the cells.
I really need somebodys help here. Would be great to find a solution!
Many Thanks !
This picture should show the issue:
Picture of the issue
I've found the issue.
First I tried also Instr instead of using a RegExp but the issue didn't disappear.
So I was investigating in my code that writes the strings into the cells.
And within that code I did the following:
dummy = dummy & " # " & z_trim(ctrl.Caption) & vbCrLf
ActiveCell.Value = dummy
The issue is because of vbCrLf
If I write the strings into the cells the following way, the changes within my coloring run are fixed, there is no change by entering the cell in edit mode:
dummy = dummy & " # " & z_trim(ctrl.Caption) & Chr(10)
ActiveCell.Value = dummy
Picture of fixed issue
It works, so I'm fine. But still interessted, why vbCrLf is causing such confusing thing?

Rules for escaping formulas and variables

I know it's been asked several times, but I just don't get it.
I'd like to know the rules in order to correctly build VBA code which incorporates formulas and variables in a VBA Evaluate function.
This works ok:
stringa_per_mesi = "=DATEDIF(""" & d1 & """,""" & WorksheetFunction.EDate(d1, 12) & """,""ym"")"
mesi = Application.Evaluate(stringa_per_mesi)
I have to write a more complex formula with Evaluate but I get lost, so I have to solve the doubts I have.
In the above example, why couldn't I just write
stringa_per_mesi = "=DATEDIF(d1, & WorksheetFunction.EDate(d1, 12) & """,""ym"")"
and why this works
WorksheetFunction.EDate(d1, 12)
even without quotation marks here (d1, 12)?
Thank you!

Comparing Textbox value to cell value

I programmed a communication tool for the production floor. This tool will register what they have done, who has done it and on what time.
The following should check whether the textbox value equals the value in the worksheet or if the textbox (textbox is TextTools1) is empty. If this is true, then nothing should happen and the thus the value of the textbox is gonna stay the same.
If the textbox is not empty or is not equal to what has been previously saved in the worksheet (thus the value has changed), then it should be registered which operator has done it and what date and what time.
It works when the textbox is empty, but when the value of the textbox has stayed the same (thus TextTools.value=ActiveCell.Offset(0,23).value (Correct)) it still adds the operators name, date and time.
Something is going wrong when trying to compare the textbox value and the cell value, but cant put my finger on it.
Sheets("Checklist & overdracht").Visible = True
Sheets("Checklist & overdracht").Select
If TextTools1.Value = Range("AZ1").Value Or TextTools1.Value = Empty Then
Sheets("Checklist & overdracht").Select
rowloc1.Value = ActiveCell.Row
ActiveCell.Offset(0, 23).Value = TextTools1.Value
Else
Sheets("Checklist & overdracht").Select
rowloc1.Value = ActiveCell.Row
ActiveCell.Offset(0, 23).Value = TextTools1.Value & " " & "(" & cboOperator.Value & " " & Format(DateValue(CStr(Now)), "short date") & " " & Format(TimeValue(CStr(Now)), "hh:mm") & ")"
End If
Edit; changed it to the code above. I tested this in another userform (and used f8) and it works brilliantly, but when I put in the userform that will actually run this code, than it doesnt have the same result...
Edit2; So apparently something goes wrong with Range(AZ1).Value reference. Because when I enter a random value instead of the range and then run the code, it does work. Is there a different way of referencing?
Ok based on your comments
Stop using active cell when code from a user form is communicating to the compiler what sheet is what. You need to fully qualify what sheet you are using. Im not entirely sure where in the code the active sheet is being set but I am fairly certain the answer is never. Another reason selecting and referencing .ActiveWhatever is bad is a cardinal sin of vba is interacting with the actual application object instead of doing everything in memory. It bogs everything done and performance suffers considerably. When you start writing pretty dense stuff then you will inevitably suffer from issues where the compiler gets confused as to what thing it should be looking at and you'll have a grand ol' time of troubleshooting that nonsense.
Also, it might be a good idea to check for more than just "=Empty". What if there is a null or empty string? I tend to check for:
.value = "" OR ISNULL(.Value)=True OR .Value = vbNullstring
this isnt real feedback though - tons of people have different ways of doing the same thing.
Try:
Thisworkbook.Sheets("YOURSHEETNAME").Range("YOURRANGE").Offset(0,23).Value = Someothervalue.
Let me know if youre still facing issues.

Variable inside formulaR1C1 for offseting by column using relative referencing

Hey this has been killing me. Look up some stuff here and found some answers that don't make sense. This is the code and it works to find a location and pull a variable from that location.
Range("G7:J7").Select
ActiveCell.FormulaR1C1 = "='Test Macro'!R[-3]C[-5]"
I need to make the R[-3]C[-5] change to R[-3]C[-4] and so forth to select new data in each column. I have created a variable (macroBegin) that is used to do this. I tried many variation, but essentially, I'm trying to do this:
Range("G7:J7").Select
ActiveCell.FormulaR1C1 = "='Test Macro'!R[-3]C[-5+(macroBegin-1)]"
What is the substitute for my poor syntax? Thanks!
Use,
Range("G7:J7").Select ActiveCell.FormulaR1C1 = _
"='Test Macro'!R[-3]C[" & macroBegin - 6 & "]"
I believe the maths are correct there but double check; the string concatenation is right.

VBA Code in Excel randomly stops executing. No error messages occur

Essentially, I have an Updata button that takes information from two columns, in two spreadsheets (within 1 book). The overall goal of this code is to take all the values from one column, and then append the values from the other column below it.
Worksheets("Overall Flow").Range("A4:A1004").Value = Worksheets("Active").Range("A2:A1002").Value
Dim i As Integer
For i = 4 To 1004
If Worksheets("Overall Flow").Range("A" & Trim(str(i))) = "" Then
Worksheets("Overall Flow").Range("A" & Trim(str(i)) & ":A" & Trim(str(1000 + i))).Value = Worksheets("Inactive").Range("A2:A1002").Value
i = 1005
End If
Next
For some reason, the first line executes, and then finishes. When I put break points, then do step-by-step, no other steps happen afterwards.
When I run the first line individually, it appears to work fine, but not when:
Worksheets("Overall Flow").Range("A" & Trim(str(i)) & ":A" & Trim(str(1000 + i))).Value = Worksheets("Inactive").Range("A2:A1002").Value
or
Worksheets("Overall Flow").Range("A4:A1004").Value = Worksheets("Inactive").Range("A2:A1002").Value
is present aftwards.
Solution to this is very unusual.
CTRL+BREAK CTRL+BREAK CTRL+BREAK ESC
It just happened to me againg after long time, I was looking for a solution and I came here then this sequence came back to my mind and I tried.
It worked for me, I hope this will help someone.
Update: Tweaked code (now with error checking!)
Main points concerning the current code:
When copying the ACTIVE range, check for last consecutive cell used. This is faster and more effecient than a loop.
Why are you trimming a number you know will not contain spaces?
There's no need to set i = 1005, just use Exit For. This is more effecient and clear to the reader what the intention is. I don't use this in the code below since I avoided looping altogether.
Here's a different way you can do this without any looping, which I think is more clear and effecient. Try this and see if it works for you:
Sub test()
Dim lastRow As Long, offSet As Long
lastRow = Worksheets("Active").Range("A2").End(xlDown).row
'Sanity checks
If IsEmpty(Worksheets("Active").Range("A2")) = True Then offSet = 1: lastRow = 2
If lastRow > 1001 Then lastRow = 1002
Worksheets("Overall Flow").Range("A4:A" & lastRow + 2).Value = _
Worksheets("Active").Range("A2:A" & lastRow).Value
If lastRow < 1002 Then
Worksheets("Overall Flow").Range("A" & lastRow + (3 - offSet) & _
":A1004").Value = Worksheets("Inactive").Range("A2:A1002").Value
End If
End Sub
Notes:
Sanity check 1 is for if A2 is blank in the Active sheet.
Sanity check 2 is for if there are cells beyond A1002 with values in Active sheet.
This is what I am using to test your code. Since I don't know what's in the spreadsheets, I can't reproduce exactly what you're seeing so I'm first putting dummy data into the ranges.
For me it is running fine every time, and I've tried it on 2 different computers - Excel 2003, and Excel 2010.
I set a breakpoint and stepped with F8, and also Shift F8 and both worked fine.
Something may be different with your data (i.e. the first cell being copied over from the inactive sheet is blank and therefore execution stops after processing the first cell -- check that column A4 is not blank), or perhaps some memory has gotten corrupted from having Office being killed.
In a Module I have:
Sub test()
Worksheets("Active").Range("A2:A1002").Value = "active"
Worksheets("Active").Range("A5").Value = ""
Worksheets("Inactive").Range("A2:A1002").Value = "inactive"
Worksheets("Overall Flow").Range("A4:A1004").Value = Worksheets("Active").Range("A2:A1002").Value
Dim i As Integer
For i = 4 To 1004
If Worksheets("Overall Flow").Range("A" & Trim(Str(i))) = "" Then
Worksheets("Overall Flow").Range("A" & Trim(Str(i)) & ":A" & Trim(Str(1000 + i))).Value = Worksheets("Inactive").Range("A2:A1002").Value
i = 1005
End If
Next
End Sub
Have you tried the same code on another computer?
I had this issue and I tracked it down to custom VBA functions used in Conditional Formatting that was processed while application.screenupdating was still set to True.
I'm not sure how consistent this behaviour is but, when a custom VBA function is referred to in a conditional formatting rule, when the screen updates, it will not step through the code even when employing break points or the debug.assert method. Here's the breakdown of what happened:
Context:
2 open workbooks.
Conditional formatting and custom function in question were in workbook1.
The code I was attempting to execute was in workbook2.
Process
I call a procedure in workbook2.
Workbook2's procedure reaches a line executing an autofilter command.
Autofilter command triggers a screen update in all open workbooks (any command that triggers a Worksheet_Change or Worksheet_Calculate event can apply here).
Screen update processes the conditional formatting rules, including the rule in workbook1 calling workbook1's custom function.
Custom function is run in a 'silent' state (i.e. with no interaction with user, ignoring break points and "debug.assert" calls; this appears to be by design as part of the conditional formatting feature)
Custom function finishes execution and ceases all other active code execution.
I fixed my problem by adding a Application.ScreenUpdating = False line at the start to prevent screen updates and, by extension, conditional format processing (but it's best to keep custom functions away from conditional formatting to begin with).
I'm not sure if this is relevant to your situation at all but I hope it helps somebody.
It has already been mentioned in transistor1's answer, but only as a side comment.
I had a similar problem, that VBA code simply stopped executing in the middle of a function. Just before that it also jumped back a few lines of code. No Error Message was shown.
I closed all open Excel programs, and upon reopening the File everything worked fine again.
So my confirmed Answer to this problem is: Corrupted Memory, restart Excel.
Edit: after doing this, I also encountered the Problem that Visual Basic Editor crashed when I tried uncommenting a particular line. So I created a New Excel file and copied my code. Now I don't have any problems anymore.
I ran into the same problem. I had a sub routine that gave random errors throughout the code without giving error messages. By pressing F8, the code would resume.
I found someone had posted a Subroutine he called "ThatCleverDevil" I do not remember the resource or who posted it. It would warn you an error was about to occur. The routine is posted below.
I split the code into component sub-routines. The short snippits ran with no interruption or erros. I created a subroutine that called each snippit. Errors resumed.
They would run individually, but not all together.
RESOLUTION: Between called sub-routines, I ran the following line of code:
Application.Wait Second(Now) + 1
The code then ran without error.
Thanks to whomever it was that wrote ThatCleverDevil. And special thanks to the coder who wrote about Application.Wait.
Sub ThatCleverDevil()
On Error GoTo err
MsgBox "About to error"
err.Raise 12345
MsgBox "Got here after the error"
Exit Sub
err:
Stop: Resume
End Sub
Robert
VBA simply is prone to this issue. I have used it for years in corproate workflows because it is so hardcoded into lots of things, but if possible I would just consider alternatives. If this an ad-hoc project R will be faster and offer more flexibility. If this is more production oriented and meant to handle large volumes I would consider informatica.
To improve the performance I called the function DoEvents inside the loop. It solved the problem for me.

Resources