I am trying to get my VBA to select values that are "0" in my table and clear the contents of that cell.
So far I have been able to get look up the table column I want to see.
Sheets("formulas").Select
Range("machine_schedule[days ]").Select
If the days are 0 Then ' <---- this is where I am having trouble.
cell.Clear
End If
It's advisable to avoid any kind of .Select when working with VBA. So the followinfg two lines are not needed (you can provide references without .Select).
Sheets("formulas").Select
Range("machine_schedule[days ]").Select
The following script checks every cell one by one in the provided range. If a zero is found, the cell is cleared. .Clear not only deletes the contents, it clears format too. If could use .ClearContents to only clear the contents.
Sub clear_zero()
Dim cell As Range
For Each cell In Sheets("formulas").Range("machine_schedule[days ]")
If cell.Value = 0 Then
cell.Clear
End If
Next
End Sub
If you only want to clear the 0 values from the cells you could try this.
Sub ClearZeroes()
Dim arrData As Variant
Dim idx As Long
With Sheets("formulas").Range("machine_schedule[days ]")
arrData = .Value
For idx = LBound(arrData, 1) To UBound(arrData, 2)
If arrData(idx, 1) = 0 Then
arrData(idxrow, 1) = ""
End If
Next idx
.Value = arrData
End With
End Sub
Related
I have this function which manages to remove all numbers stored as text:
Public Function find_numbers_formated_as_text(ByVal sh As Worksheet)
Dim c As Range
On Error GoTo A
''''For Each r In sh.UsedRange.Cells.SpecialCells(xlCellTypeConstants, xlTextValues)
For Each c In sh.ListObjects(1).DataBodyRange
''''For Each c In sh.UsedRange.Cells.SpecialCells(xlCellTypeConstants, xlNumbers)
''''For Each c In sh.ListObjects(1).DataBodyRange.Cells.SpecialCells(xlCellTypeConstants, xlNumbers)
If IsNumeric(c.Value) = True Then
c.Value = c.Value
End If
Next c
Exit Function
A:
On Error GoTo 0
End Function
But it is really slow... Does anyone have any suggestion on how to make it faster?
I did try some other things which is why there are some of the comments in the source code. But comments didn't work, because range was also empty in my case (even if table was full of data).
Please, replace this part of your code:
For Each C In sh.ListObjects(1).DataBodyRange
''''For Each c In sh.UsedRange.Cells.SpecialCells(xlCellTypeConstants, xlNumbers)
''''For Each c In sh.ListObjects(1).DataBodyRange.Cells.SpecialCells(xlCellTypeConstants, xlNumbers)
If IsNumeric(C.Value) = True Then
C.Value = C.Value
End If
Next C
with this one:
Dim lRng As Range, arr, i As Long, j As Long
Set lRng = sh.ListObjects(1).DataBodyRange
arr = lRng.Value2
For i = 1 To UBound(arr)
For j = 1 To UBound(arr, 2)
If IsNumeric(arr(i, j)) Then arr(i, j) = CDbl(arr(i, j))
Next j
Next i
With lRng
.NumberFormat = "General"
.Value2 = arr
End With
It places the range in an array and all process take place only in memory, the modified array content being dropped at the end of the code, at once.
The most time consuming is the iteration between each cell and writing cell bay cell...
If "General" formatting may bother your list object format, please state in which columns the conversion should be done, and I will adapt the code to format only the respective table columns.
Now I could see one of your comments saying that in the range to be processed exist (and must remain) formulas. The above code does not deal with such a situation. You should state it in your question, I think...
Edited:
If the formulas used to return a numeric value (not a string) and, by mistake the respective range has been formatted as Text, you can try the next way (to maintain the formulas):
With sh.ListObjects(1).DataBodyRange
.NumberFormat = "General"
.Formula = .Formula
End With
There are lots of answers to this question. This is a simple thing to try. Add this before:
Application.Calculation = xlManual
and this after:
Application.Calculation = xlAutomatic
It's faster to store the range as array than changing values in the sheet.
sh.ListObjects(1).DataBodyRange.formula = sh.ListObjects(1).DataBodyRange.formula
The numbers will default to numbers if they were text so you don't need to test if it's number.
(You will not lose formulas using this method.)
I'm trying to get my code to search column D for cells that are not blank. When it finds one that isn't blank it copies that cell and fills the series beneath. Then I want it to repeat this code until "D3020".
However each time I run my code it takes the copied cell and continuously pastes it all the way down to "D3020". There are different values that also need to be copied so I need to fix this. I have tried using the .offset property. I have tried using .range.copy property.
Sub Fill()
Dim SRng As Range
Dim SCell As Range
Set SRng = Range("D1101:D3020")
For Each SCell In SRng
If SCell <> "" Then
SCell.Copy
Range(SCell, SCell.Offset(10, 0)).PasteSpecial(xlPasteAll)
End If
Next SCell
End Sub
I'd like this code to search Range("D1101:D3020") for cells that <> "". When one is found, fill the series beneath it, stopping at the next cell with a number in it.
For example
D1101 = 1601166 (see picture) I want to copy this and fill the series beneath it. All are exactly ten rows apart. Then D1121 = 1601168 (see picture) I want to copy/fill series for this as well.
No need for a loop; just fill the blanks with the value above.
sub fillBlanks()
dim brng as range
on error resume next
set brng = Range("D1101:D3020").specialcells(xlcelltypeblanks)
on error goto 0
if not brng is nothing then
brng.formular1c1 = "=r[-1]c"
Range("D1101:D3020") = Range("D1101:D3020").value
end if
end sub
Option Explicit
Sub Test()
FillEmptyFromTop [D1101:D3020]
End Sub
Sub FillEmptyFromTop(oRng As Range)
Dim v, a, i
With oRng.Columns(1)
a = .Value
For i = LBound(a, 1) To UBound(a, 1)
If IsEmpty(a(i, 1)) Then a(i, 1) = v Else v = a(i, 1)
Next
.Value = a
End With
End Sub
I have a column of numbers in an Excel spreadsheet, which have been produced by an accelerometer and recorded by a data logger. The problem with the accelerometer is that when it is stationary it produces a lot of 'noise' values, which are always the same: 1.2753, 1.6677, 2.0601, 2.5506, 2.943, and 3.4335.
The first value in this column which is NOT one of the above numbers represents when the accelerometer begins to detect motion. Equally, the last value which is not one of the above numbers represents when the accelerometer stops detecting motion.
I have VBA code that produces an Acceleration vs Time graph using the above column, but it also includes all these 'noise' values. I am trying to trim these beginning and end noise values out of the column so that only motion is shown on the graph.
Is there some way of using VBA to determine the first value in the column that is NOT one of the above noise values? I'm guessing the same code can be tweaked to find the last.
I hope that I've explained this clearly. I wasn't able to find any answers to this one.
Thanks!
Here is an example for column A. We make an array of "bad" values and then loop down the column examining each item until we find one that is not "bad"
Sub FirstGood()
Dim v As Double, FoundIt As Boolean
bad = Array(1.2753, 1.6677, 2.0601, 2.5506, 2.943, 3.4335)
For i = 1 To 9999
v = Cells(i, "A").Value
FoundIt = True
For j = 0 To 5
If bad(j) = v Then FoundIt = False
Next j
If FoundIt Then
MsgBox "Found valid data on row # " & i
Exit For
End If
Next i
End Sub
This is only demo code. You must adapt it by fixing the loop limits, the column id, the response, etc.
this is time and motion coding.
Sub StartWatch()
' store time in start column
Dim rngTemp As Range
Set rngTemp = ActiveSheet.Range("A65536").End(xlUp).Offset(1, 0)
rngTemp = Now()
End Sub
Sub StopWatch()
' store time in stop column
' copy previous formula down
Dim rngTemp As Range
Set rngTemp = ActiveSheet.Range("B65536").End(xlUp).Offset(1, 0)
rngTemp = Now()
rngTemp.Offset(-1, 1).AutoFill Destination:=Range(rngTemp.Offset(-1, 1), rngTemp.Offset(0, 1)), Type:=xlFillDefault
Range("D65536").End(xlUp).Offset(1, 0).Select
End Sub
Dim PASSWORD As String
On Error GoTo ERRORH:
PASSWORD = InputBox("Enter Password to Close file")
If PASSWORD = "learnmore" Then
Else
Cancel = True
End
If ERRORH:
If Err.Number = 13 Then
Err.Clear
Cancel = True
End If
You don't even necessarily need to use VBA---you could have the "noise" values in a specific range of your spreadsheet, and add a is_noise column to your data, which uses a VLOOKUP or COUNTIF function to see if the value appears in your table of noise values. Then your chart would just exclude those values. That way, your spreadsheet would also be more flexible: If new noise values pop up, you just have to change the spreadsheet rather than updating your VBA code.
Option Explicit
Sub StartWatch()
' store time in start column
Dim rngTemp As Range
Set rngTemp = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
rngTemp = Now()
End Sub
Sub StopWatch()
' store time in stop column
' copy previous formula down
Dim rngTemp As Range
Set rngTemp = ActiveSheet.Range("B" & Rows.Count).End(xlUp).Offset(1, 0)
rngTemp = Now()
If rngTemp.Row <> 2 Then
rngTemp.Offset(-1, 1).AutoFill Destination:=Range(rngTemp.Offset(-1, 1), rngTemp.Offset(0, 1)), Type:=xlFillDefault
Range("D65536").End(xlUp).Offset(1, 0).Select
Else
rngTemp.Offset(, 1).Formula = "=$B2-$A2"
End If
End Sub
I want to delete the entire rows for cell that contain 'Total' and 'Nett' in column C.
I have tried the macro recording using Auto Filter but it only delete rows up to a specified range (which may differ if I use other set of data).
Appreciate your help!
Here you go. Just copy and paste this sub into your file. To use it, select the SINGLE column that you want to evaluate. This will go through every cell that has been selected, and if it matches the criteria, it will delete the entire row. Let me know if you have any questions. Good luck!
Sub DeleteRows()
'Enter the text you want to use for your criteria
Const DELETE_CRITERIA = "Test"
Dim myCell As Range
Dim numRows As Long, Counter As Long, r As Long
'Make sure that we've only selected a single column
If Selection.Columns.Count > 1 Then
MsgBox ("This only works for a single row or a single column. Try again.")
Exit Sub
End If
numRows = Selection.Rows.Count - 1
ReDim arrCells(0 To 1, 0 To numRows) As Variant
'Store data in array for ease of knowing what to delete
Counter = 0
For Each myCell In Selection
arrCells(0, Counter) = myCell
arrCells(1, Counter) = myCell.Row
Counter = Counter + 1
Next myCell
'Loop backwards through array and delete row as you go
For r = numRows To 0 Step -1
If InStr(1, UCase(arrCells(0, r)), UCase(DELETE_CRITERIA)) > 0 Then
Rows(arrCells(1, r)).EntireRow.Delete
End If
Next r
End Sub
This will loop through cells in Column C and delete the entire row if the cell contains either "Total" or "Nett". Keep in mind that it is case sensitive, so the first letter of "Nett" or "Total" would need to be capitalized for this to find it. There can be other text in the cell however. Also note that the references are not fully qualified (ie Workbook().Worksheet().Range()) because you did not provide a workbook or worksheet name. Let me know if this does not work for you.
Sub Delete()
Dim i as Integer
For i = Range("c" & Rows.Count).End(xlUp).Row To 1 Step -1
If Instr(1, Cells(i, 3), "Total") <> 0 Or Instr(1, Cells(i,3),"Nett") <> 0 Then
Cells(i,3).EntireRow.Delete
End If
Next i
End Sub
I'm trying to create a time line via Excel and VBA, having the hours (1-24) listed in the range A1:A24; I created a ComboBox, filled the list with that very range and now I'm trying to link these two, so that if I choose a certain hour in the ComboBox, Excel will display "Test" one cell to the right of that specific cell from the given range (e.g. if I select "8" in the ComboBox, then Excel will display "Test" in B8, since the value of A8 is "8")
This is how far I got with the little knowledge about VBA that I have:
Private Sub Combobox1_Change()
For Each cell In Range("A1:A24")
If cell.Value = Me.ComboBox1.Value Then
cell.Offset(0, 1).Value = "Test"
End If
Next
End Sub
It would be great if someone could help me work this out!
If the list is ordered 1 - 24, simply use
Private Sub ComboBox1_Change()
Dim MyRange As Range
Set MyRange = [A1] ' or wherever your list starts
MyRange(ComboBox1.Value, 2) = "Test" ' address the range object by row, column
End Sub
Be carefull with If cell.Value = Me.ComboBox1.Value Then ... ComboBox1 returns a String, your Cell may contain numbers and the If may not work (at least here this is the case).
A more generalized routine scanning the whole list and not relying on its ascending sort order (you may soon have a list with "Apple", "Banana", "Cherimoya", ...)
Private Sub ComboBox1_Change()
Dim MyRange As Range, Idx As Integer
Set MyRange = [A1] ' or whereever your list starts
Idx = 1
Do While MyRange(Idx, 1) <> "" ' start processing
If Str(MyRange(Idx, 1)) = Str(ComboBox1) Then
If MyRange(Idx, 2) = "" Then ' bonus: do a toggle
MyRange(Idx, 2) = "Test"
Else
MyRange(Idx, 2) = ""
End If
Exit Do ' or not for full list processing
End If
Idx = Idx + 1
Loop
End Sub