I discovered a very interesting bug today i.e if it is a bug.
Can you please confirm if you can replicate it? If it is a bug and has been not reported then I can file it as such. I am also ok if any of the Excel-MVPs want to file it as a bug.
Let's say in sheet1 in cell A1, you have a formula = $B$2+ $B$3. Now ensure that your cell is selected. Now paste this code in a module.
Sub Sample()
Dim r As Range, sPre As String, sAft As String
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
sPre = "$B$2": sAft = "$C$3"
On Error Resume Next
Set r = ws.Range("A1:A2").SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not r Is Nothing Then r.Replace what:=sPre, _
replacement:=sAft, _
lookat:=xlPart, _
MatchCase:=False
End Sub
Ideally the code should have worked and the = $B$2+ $B$3 should have changed to = $C$3+ $B$3 in the formula bar but it doesn't. It will work only if you step through it or if you do as mentioned in the next line
Now do one thing. Select any cell other than A1 or A2. Now if you run the code, the code works as expected.
At first I thought that my excel has gone crazy so I closed and re-started it but I was able to reproduce the above in Excel 2010 many number of times.
Then I thought it is a .SpecialCells issue but the above behavior can be observed with this code as well.
Sub Sample()
Dim r As Range, sPre As String, sAft As String
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
sPre = "$B$2": sAft = "$C$3"
Set r = ws.Range("A1:A2")
r.Replace what:=sPre, _
replacement:=sAft, _
lookat:=xlPart, _
MatchCase:=False
End Sub
Are you able to replicate it?
I replicated your issue and got away with it by two ways:
Try ThisWorkbook.Save after the replace.
select other cell than A1 or A2 (cell selected whose formula getting replaced) after replacing formula.
While many alternatives have been suggested in the other answers for example
Select another cell via code
Save the workbook
If I do not want to select the cell or save the workbook then is there an alternate way which is better than the above two? Yes, there is. Just tried this and it works
Sub Sample()
Dim r As Range, sPre As String, sAft As String
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
sPre = "$B$2": sAft = "$C$3"
On Error Resume Next
Set r = ws.Range("A1:A3").SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If Not r Is Nothing Then r.Replace what:=sPre, _
replacement:=sAft, _
lookat:=xlPart, _
MatchCase:=False
r.Formula = r.Formula
End Sub
But the question still remains that the Formula Bar should have updated in the original scenario but it doesn't
I'm partly able to replicate it, also Excel 2010.
If I run the macro with the cell selected, using the Run option within the Visual Basic Editor, the value in the cell changes to reflect the new formula, but the formula in the formula bar doesn't show as updated. But it must be updated because the result changed. If I click out of the cell and back in, the updated formula appears and shows that the search/replace worked.
If I step through the macro in the VBA window, the formula bar does show as updated while the macro runs.
If I run the macro from the Excel window, using Macros -> View -> Run, the formula bar does show as updated while the macro runs.
If I add r.Select to the last line of the macro, running it from VBA works.
If I run the macro so it does not update the formula bar, then click into the formula bar, the formula bar shows the old formula but the cell content changes to show the new formula instead of the answer.
Edit: The behaviour appears the same in Excel 2013
Related
I have a script in which I'm processing data in 2 different workbooks. One is wbVendor and one is wbImport.
The code is written in a user form in wbImport.
A part of the code is to prompt the user to click in a cell in wbVendor. I then need the column of this selected cell. The problem now is that it takes the cell with the whole path of the workbook. So instead of taking just $B$10 it takes '[2018 ARA Product Listing (Airline Price).xlsx]Active Parts w Detail'!$B$10
The code I'm using for this task is as followed:
wbVendor.Activate
wsVendor.Activate
Set CellPN = wsVendor.Application.InputBox _
(prompt:="Click in a cell which contains the part number in the vendors file.", Type:=8)
CellPN.Select
ColumnPN = CellPN.Column
When I then execute this code the following error message appears:
Run-time error '1004':
Select method of Range class failed.
For a better understanding I have attached a picture of the prompt in which the cell with the whole file name is in.
Thank you already for your help. I really appreciate it!!
Print Screen Cell Selection
It's not really clear exactly what you're trying to achieve here but the following should work:
wbVendor.Activate
wsVendor.Activate
Set CellPN = wsVendor.Application.InputBox _
(prompt:="Click in a cell which contains the part number in the vendors file.", Type:=8)
CellPN.Parent.Parent.Activate 'Activate the workbook of CellPN
CellPN.Parent.Select 'Select the worksheet of CellPN
CellPN.Select 'Select CellPN
ColumnPN = CellPN.Column
AddressPN = CellPN.Address
The error you're seeing is due to you selecting a cell on a different sheet and/or workbook.
AddressPN should contain the address of CellPN as text.
To directly address the question at hand:
wbVendor.Activate
wsVendor.Activate 'assuming this is the worksheet contained in the workbook above,
'the line above is redundant and not necessary
Dim cellPN as string
cellPN = wsVendor.Application.InputBox _
(prompt:="Click in a cell which contains the part number in the vendors file.", Type:=8)
Dim result() as String
result = Split(CellPN, "!")
ColumnPN = wsVendor.Range(result(1)).Column
The Split function will allow you to break up the string returned by your InputBox function at the bang (!) which is the delimiter between the file name/worksheet and the actual cell reference. This will return an array of 2 strings, the first result(0) is the file name/worksheet, the second result(1) is the actual cell reference.
From there, you can ask the Worksheet.Range() function to return the .Column of the cell reference you provide.
Though you probably want to do some reading around here on how and why you should avoid .Activate and .Select pretty much at all cost.
In order to Select a range; the worksheet on which the range resides must be active. The means the the workbook containing that Sheet must also be active:
Sub PickaCell()
Dim w As Workbook, s As Worksheet, CellPN As Range
Set CellPN = Application.InputBox(prompt:="Click in a cell which contains the part number in the vendors file.", Type:=8)
Set s = CellPN.Parent
Set w = s.Parent
w.Activate
s.Select
CellPN.Select
End Sub
First of all thank you all for your help. Now my code works perfectly. For those who are interested this is the final code:
wbVendor.Activate
wsVendor.Activate
Set CellPN = wsVendor.Application.InputBox _
(prompt:="Click in a cell which contains the part number in the vendors file.", Type:=8)
CellPN.Parent.Parent.Activate 'Activate the workbook of CellPN
CellPN.Parent.Activate 'Select the worksheet of CellPN
ColumnPN = CellPN.Column
Thanks again.
Cheers,
Dominic
Try this:
Dim ColumnPN As Long
Dim CellPN As Range
Dim wsVendor As Worksheet
Dim wb as Workbook
wbName = Application.GetOpenFilename
If wbName <> False Then
Set wb = Workbooks.Open(wbName)
End If
Set wsVendor = wb.Sheets(1)
wsVendor.Activate
Set CellPN = Application.InputBox(prompt:="Select a Cell", Type:=8)
ColumnPN = wsVendor.Range(CellPN.Address).Column
I am writing a VBA macro where I have an InputBox come up, the user will select a range which will be a full column, and then the macro will paste that range in a particular place on another worksheet. I have been trying to make this code work, but I keep getting different errors depending on what I try to fix, so I was wondering if someone could help me out. I have pasted the relevant parts of the code:
Sub Create_CONV_Files()
Dim NewCode As Range
Set NewCode = Application.InputBox(Prompt:="Select the column with the code numbers", Title:="New Event Selector", Type:=8)
Dim RawData As Worksheet
Set RawData = ActiveSheet
Dim OffSht As Worksheet
Set OffSht = Sheets.Add(After:=Sheets(Sheets.Count))
OffSht.Name = "offset.sac"
Worksheets(RawData).Range(NewCode).Copy _
Destination:=OffSht.Range("A:A")
End Sub
I have tried making the input a string instead, but I am also getting errors there and am not sure how to fix that. I was hoping to use roughly the method I have outlined as my full code has multiple destination sheets and ranges.
Thank you very much for any help you can offer!
once you have set a Range object it brings with it its worksheet property so there's no need to qualify its worksheet
Sub Create_CONV_Files()
Dim NewCode As Range
Set NewCode = Application.InputBox(prompt:="Select the column with the code numbers", title:="New Event Selector", Type:=8)
Dim OffSht As Worksheet
Set OffSht = Sheets.Add(After:=Sheets(Sheets.count))
OffSht.Name = "offset.sac"
NewCode.Copy _
Destination:=OffSht.Range("A1")
End Sub
I have lots of data (numbers) with heading in several worksheets that I am trying to zero. This is done on each column as follows: Taking the value of the first row in the column and subtracting this value from all rows in the column.
I have put together this code (may not be the best way, but Im new to VBA so :))
Dim ws As Worksheet
Dim Header As Range, Coldata As Range
Dim firstrow As Long
Dim cell As Range, cell2 As Range
Set ws = ActiveSheet
Set Header = ws.Range("B5:CJ5")
For Each cell In Header
If cell Is Nothing Then Exit For
firstrow = cell.Offset(2).Value
***Set Coldata = ws.Range(cell.offset(3),cell.Offset(3)).End(xlDown)***
cell.Value = 0
For Each cell2 In Coldata
cell2.Value = cell2.Value - firstrow
Next
Next
MsgBox "Done zeroing"
This sub is under the Module of the workbook I am working on. Whenever I run this sub from inside the VBA window it gives me the error I stated in the description on the Line of the code with **** around it.
When I try to run it from a workhsheet it says Cannot run the macro. The macro may not be avaiable in this worksheet or all macros may be disabled. The thing is I run another macro in the same module it works, so macros being disabled is out of the question.
What am I missing?
Thanks in advance!
Edit, I fixed it.. But running it takes SO much time? Excel freezes when I run it though?
You are over-specifying. Replace:
Set Coldata = ws.Range(cell.Offset(3)).End(xlDown)
with:
Set Coldata = cell.Offset(3).End(xlDown)
cell is fully qualified already.
I'm real new to VBA coding and have been doing alright but I have now hit a wall with my final (and probably more complex than it needs to be) macro of the worksheet. I've been trying to make it work all weekend through multiple google searches and using various answers from stackoverflow's other questions to compile my own script, but to no avail. This is what I have so far (apologies coders, I know this will look like it was written by a 3 year-old):
Sub Build_Delete()
Dim rngA As Range
Dim cell As Range
Set rngA = Worksheets("Database").Range("D9:D177").End(xlUp)
For Each cell In rngA
If cell.Value = Range("A2").Value Then
cell.Select
Range("D" & ActiveCell.Row & ":AB" & ActiveCell.Row).Select
Selection.Delete
End If
Next cell
End Sub
The above works, no errors are returned, however it doesn't do anything noticeable.
I'm aware this is most likely atrocious, so this is what I am trying to do:
Database!D9:D177 contains the titles for a set of data in columns D to AB (4 to 28) .
There is an ActiveX Search Box that populates cell Database!A2 in real time with whatever is searched (eg. "Test" typed into Search Box, "Test" appears in cell Database!A2).
When I run the macro, I want it to check range Database!D9:D177 for the text string found in Database!A2, then delete the contents of columns D to AB for that row (eg. A2 = "test", Found "test" in cell D21, Delete D21:AB21).
The row is a dynamic value which is what is throwing me mostly with this, but the columns are fixed.
Also, the button for the macro is located on a separate worksheet (Front Page!), but the script will run solely on the Database! page.
Only needs to work in excel, not open office.
Only other thing I can think of that is relevant is that the cells can be left blank after deletion, they do not need to be filled, and the worksheet will never need to be printed so margins aren't an issue.
Optionally I would like to add an "Are You Sure? 'Yes' 'No' Msgbox at the start of the script, but I can play with that later as I know I am pushing my luck with this.
Any help would be greatly appreciated!
I always find it faster to use FIND rather than check the value of each cell.
If you want to find all values in case of duplicates you can go on to use .FINDNEXT(rFound) - https://msdn.microsoft.com/en-us/library/office/ff839746.aspx
Public Sub Build_Delete()
Dim rngA As Range
Dim rFound As Range
Dim wrkSht As Worksheet
Set wrkSht = ThisWorkbook.Worksheets("Database")
Set rngA = wrkSht.Range("D9:D177")
With rngA
Set rFound = .Find(wrkSht.Range("A2"), LookIn:=xlValues, LookAt:=xlWhole)
If Not rFound Is Nothing Then
If MsgBox(rFound.Value & " found on row " & rFound.Row & "." & vbCr & _
"Delete?", vbInformation + vbYesNo) = vbYes Then
rFound.EntireRow.Delete Shift:=xlUp
End If
End If
End With
End Sub
Suppose in a worksheet the formula of R4 cell is =B1+B2, and its current value is 10.
A VBA command Range("R4").Value = 5 will change both its formula and its value to 5.
Does anyone know if there exists a VBA command which changes the value of R4 to 5, but does not change its formula, such that its formula is still =B1+B2?
PS: we can also achieve the same state in another way: 1) do a Range("R4").Value = 5 2) change the formula of R4 to =B1+B2 but without evaluating it. In this case, does there exist a VBA command which change the formula of a cell without evaluating it?
Edit: What I want to do is...
I would like to write a function, which takes a worksheet where some cells may be out of date (the formula does not match its value), and generates automatically a VBA Sub, this VBA Sub can reproduce this worksheet. The VBA Sub may look like:
Sub Initiate()
Cells(2,3).Value = 5
Cells(4,5).Value = 10
...
Cells(2,3).Formula = "=2+3"
Cells(4,5).Formula = "=C2+C2"
...
End Sub
Such that running Initiate() builds one worksheet with same values and formulas.
Without the VBA command I am asking, this Initiate() will be hard to generated.
You cannot change the value of a cell to something different than what the cell formula computes to.
Regarding your p.s.: You can probably change the formula of a cell without re-evaluation by changing the calculation mode to manual. But that would of course apply to the entire workbook, not just this one cell
EDIT: maybe a solution would be to temporarily save the formula of the cell in either a tag of that cell, or a hidden worksheet?
It is quite simple to change the result of a formula without changing the formula itself:
Change the value of of its argument(s). This is a Solver-type approach:
Sub ForceDesiredResult()
Dim r As Range
Set r = Range("B2")
With r
If r.HasFormula Then
.Formula = .Formula & "-5"
Else
.Value = .Value - 5
End If
End With
End Sub
Here is some very dirty code that will save all values of all formulas on the active sheet as custom properties of the sheet, and a 2nd sub that will mark red all cells where the value has changed from it's original value, while preserving all formulas. It will need some error-checking routines (property already exists, property doesn't exist,...) but should give you something to work with. Since I don't really understand your problem it's a bit hard to say ;)
Sub AddCustomProperty()
Dim mysheet As Worksheet
Dim mycell2 As Range
Dim myProperty As CustomProperty
Set mysheet = ActiveWorkbook.ActiveSheet
For Each objcell In mysheet.UsedRange.Cells
Debug.Print objcell.Address
If objcell.HasFormula Then Set myProperty = mysheet.CustomProperties.Add(objcell.Address, objcell.Value)
Next objcell
End Sub
Sub CompareTags()
Dim mysheet As Worksheet
Dim mycell2 As Range
Dim myProperty As CustomProperty
Set mysheet = ActiveWorkbook.ActiveSheet
For Each objcell In mysheet.UsedRange.Cells
Debug.Print objcell.Address
If objcell.HasFormula Then
On Error Resume Next
If mysheet.CustomProperties(objcell.Address).Value <> objcell.Value Then
objcell.Font.ColorIndex = 3
On Error GoTo 0
End If
End If
Next objcell
End Sub