The code takes an active cell and if it is in the appropriate column, and has the value "YES" it runs one of two codes (depending on whether it is a summary or an individual value). This done on 'raw' data that is not in a table or pivot table.
About half the time that I double click on any cell in that sheet it jumps my active cell to either the top or bottom of the range of cells. What is causing this? What can I do to fix it?
This happens on both "YES" and "NO" cells.
Edit: Figured it out. It's an excel shortcut I was not aware of (I don't use the mouse much on excel). Double clicking a cells border jumps you to the top or bottom of that section. Is there a way in VBA to disable this 'feature' for a specific sheet. I can't seem to find any info on Google about it...
Edit 2: Found this: https://superuser.com/questions/610805/disable-navigate-to-end-of-list-when-double-clicking-on-border-of-selected-cell
But I do not want to disable drag and drop in the worksheet AND I want to do it with VBA.
Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Target.Value <> "YES" Then
Exit Sub
Else
If Target.Column <> 11 Then
Exit Sub
Else
Cancel = False
Dim j As String
Dim k As String
Dim i As Range
Application.ScreenUpdating = False
Set i = Target
k = i.Offset(0, -7).Value 'First value for filter
Worksheets("Comments").Activate
If Worksheets("Comments").AutoFilterMode = True Then
Worksheets("Comments").AutoFilterMode = False
End If
If i.Offset(-1, 0).Value = "Comments" Then
j = i.Offset(-1, -9).Value
Worksheets("Comments").Range("C2").AutoFilter Field:=3, Criteria1:=j
Else
j = i.Offset(0, -9).Value
Worksheets("Comments").Range("C2").AutoFilter Field:=4, Criteria1:=k
Worksheets("Comments").Range("C2").AutoFilter Field:=3, Criteria1:=j
End If
Application.ScreenUpdating = True
Worksheets("Comments").Range("A1").Activate
End If
End If
Cancel = True
End Sub
First of all, let me organize your code, it is not very easy to read. Hope this works, I cannot try it right now.
Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim j As String
Dim k As String
Dim i As Range
Application.ScreenUpdating = False
Cancel = False
Set i = Target
If Target.Value <> "YES" and Target.Column <> 11 Then
Application.ScreenUpdating = True
Exit Sub
Else
Application.CellDragAndDrop = False
k = i.Offset(0, -7).Value 'First value for filter
Worksheets("Comments").Activate
If Worksheets("Comments").AutoFilterMode = True Then
Worksheets("Comments").AutoFilterMode = False
End If
If i.Offset(-1, 0).Value = "Comments" Then
j = i.Offset(-1, -9).Value
Worksheets("Comments").Range("C:C").AutoFilter Field:=3, Criteria1:=j
Else
j = i.Offset(0, -9).Value
Worksheets("Comments").Range("C:C").AutoFilter Field:=4, Criteria1:=k
Worksheets("Comments").Range("C:C").AutoFilter Field:=3, Criteria1:=j
End If
Application.ScreenUpdating = True
Worksheets("Comments").Range("A1").select
End If
Application.CellDragAndDrop = true
Cancel = True
End Sub
Related
I found this Code on the internet, it should make those little arrows from the dropdownmenu visible. This works, but I would like to make only the following cells visible:
B2,B11,B12,B13
Sub ShowArrowsExceptOne()
'shows all arrows except
' in specified field number
Dim c As Range
Dim rng As Range
Dim i As Long
Dim iHide As Long
Set rng = ActiveSheet.AutoFilter.Range.Rows(1)
i = 1
iHide = 3 'leave this field's arrow hidden
Application.ScreenUpdating = False
For Each c In rng.Cells
If i = iHide Then
c.AutoFilter Field:=i, _
Visibledropdown:=False
Else
c.AutoFilter Field:=i, _
Visibledropdown:=True
End If
i = i + 1
Next
Application.ScreenUpdating = True
End Sub
I tried it the following way:
Dim i As Long
Dim iHide As Long
i = 1
iHide = 3 'leave this field's arrow hidden
Application.ScreenUpdating = False
With Intro.Range("B2")
.AutoFilter Field:=2, _
Visibledropdown:=True
End With
Application.ScreenUpdating = True
But it always makes the dropdowns visible on B1,C1 and D1
Can anybody help me on this?
I have a worksheet that count the number of days between a designated date in column A and today() date in column B which stops the counting in column C if there is the word "CLOSED" in Column D. But I have a problem where I want to reapply back the formula if column D is blank again. I'm not sure how to make the column rows appear at the right place for the formula to be used
Below is the VBA code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells = "CLOSED" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row) = Range("C" & Target.Row).Value
Range("B" & Target.Row) = Range("B" & Target.Row).Value
Application.EnableEvents = True
End If
End If
If Target.Cells = "" Then
'Run only when change is made in Column D
If Target.Column = 4 Then
Application.EnableEvents = False
'Replace the formula with the current result
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
Range("B" & Target.Row).Value = "=Today()"
Application.EnableEvents = True
End If
End If
End Sub
I would really appreciate it if someone can teach me how to properly change the code:
Range("C" & Target.Row).Formula = "=TRUNC($B2 - $A2)"
as I am still new to VBA programming and would like to learn from my mistake
Below will do what you want. Learn that you can use the .FormulaR1C1 similar to effect of filling up/down. The potential issues including more than 1 cells is changed. Have not put checks if the cells in columns A/B are empty.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim oRng As Range
Application.EnableEvents = False
For Each oRng In Target.Cells
With oRng
If .Column = 4 Then
If UCase(Trim(.Value)) = "CLOSED" Then
.Worksheet.Cells(.Row, "B").Value = .Worksheet.Cells(.Row, "B").Value
.Worksheet.Cells(.Row, "C").Value = .Worksheet.Cells(.Row, "C").Value
ElseIf Len(Trim(.Value)) = 0 Then
.Worksheet.Cells(.Row, "B").Formula = "=Today()"
.Worksheet.Cells(.Row, "C").FormulaR1C1 = "=TRUNC(RC[-2]-RC[-3])"
End If
End If
End With
Next oRng
Application.EnableEvents = True
End Sub
My understanding is that:
you need to act for any column 4 cell change, only
there can be more than one changed cell in column 4
so I'd go like follows (explanations in comments):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rangeToProcess As Range
Set rangeToProcess = Intersect(Target, Columns(4)) 'mind edited cells in column 4 only
If rangeToProcess Is Nothing Then Exit Sub
Dim cell As Range
Application.EnableEvents = False
For Each cell In rangeToProcess 'loop through edited cells in column 4
With cell.Offset(, -2).Resize(, 2) ' reference a 2-cells range at the left of current cell
Select Case cell.Value 'process current cell value
Case "CLOSED" ' if it's "CLOSED" ...
.Value = .Value ' ... then leave values in referenced cells
Case "" ' if it's "" ...
.FormulaR1C1 = Array("=Today()", "=TRUNC(RC[-1]-RC[-2])") ' ... then restore formulas
End Select
End With
Next
Application.EnableEvents = True
End Sub
I have an excel document which has a lot of info and statistics and i am trying to figure out how to solve the following issue:
If a cell on column E, in the interval E5:E70, contains the "N/A" text (without quotes), i want to automatically input the "N/A" text on several specific cells in the same row
Added an image for reference.
Any help would be much appreciated, Thanks !
Latest edit:
I have attached a copy of the excel, maybe it will be a lot more helpful, for me it just won't work...it's so frustrating...
excel file
Paste the code below into the code sheet of the worksheet on which you want to have the action.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim C As Long
If Not Application.Intersect(Target, Range("E5:E70")) Is Nothing Then
SetApplication False
With Target
If StrComp(Trim(.Value), "N/A", vbTextCompare) = 0 Then
' recognises "n/a" as "N/A" and corrects entry
For C = Columns("E").Column To Columns("AL").Column
Cells(.Row, C).Value = "N/A"
Next C
End If
End With
SetApplication True
End If
End Sub
Private Sub SetApplication(ByVal AppMode As Boolean)
With Application
.EnableEvents = AppMode
.ScreenUpdating = AppMode
End With
End Sub
I assumed (based on the picture) that you want paste N/A's in this way: F - paste, G - don't paste, H - paste - and repeat this three further: paste, don't paste, paste, paste, don't paste, paste, etc.
So this code works accordingly to this rule. You just need to specify very last column instead of Column.Count - 2 - this bit says just that program should fill until the last column in a sheet.
Sub FillNAs()
Application.EnableEvents = False
Application.ScreenUpdating = False
Dim i, j As Long
For i = 5 To 70
If UCase(Cells(i, 5).Value) = "N/A" Then
j = 6
Do While j < Columns.Count - 2
Cells(i, j).Value = "N/A"
Cells(i, j + 2).Value = "N/A"
j = j + 3
Loop
End If
Next i
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Try
Sub Demo()
Dim ws As Worksheet
Dim cel As Range
Set ws = ThisWorkbook.Sheets("Sheet1") 'change Sheet1 to your data sheet
For Each cel In ws.Range("E5:E70")
If CVErr(cel.Value) = CVErr(xlErrNA) Then
ws.Range("F" & cel.Row & ":I" & cel.Row) = CVErr(xlErrNA) 'mention desired range instead of (F:I)
End If
Next cel
End Sub
Is there a way to speed this code up? I need it to remove and write the same content to the cell to force other VBA code to run that's on another column. Which is what it does, just super damn slow. And there is sometimes 2000 entries/rows on this sheet. Its about 3 seconds per cell, and it almost maxes my CPU out lol. (i7 6850k # 4.4ghz).
Reason for it, is sometimes the data is copied from an old version of the spreadsheet to a new version, and the VBA updated columns wont update, unless I physically change the cell its checking.
Sub ForceUpdate()
On Error GoTo Cleanup
Application.ScreenUpdating = False ' etc..
ThisWorkbook.Sheets("Sales Entry").Unprotect "password!"
Dim cell As Range, r As Long
r = 2
For Each cell In ThisWorkbook.Sheets("Sales Entry").Range("E2:E10")
If Len(cell) > 0 Then
Dim old As String
old = cell.Value
ThisWorkbook.Sheets("Sales Entry").Range("E" & r).Value = ""
ThisWorkbook.Sheets("Sales Entry").Range("E" & r).Value = old
r = r + 1
End If
Next cell
Cleanup:
Application.ScreenUpdating = True ' etc..
ThisWorkbook.Sheets("Sales Entry").Protect "password!", _
AllowSorting:=True, AllowFiltering:=True
End Sub
The code in the other VBA section is
If StrComp("pp voice", Target.Value, vbTextCompare) = 0 Then
Target.Value = "PP Voice"
Target.Offset(0, 8).Value = "N\A"
Target.Offset(0, 8).Locked = True
Target.Offset(0, 10).Value = "N\A"
Target.Offset(0, 10).Locked = True
End If
Target.Value is referring to the E column in the first piece of code. At the moment I have the first piece attached to a button, but it's way to slow. And the target machines are no where near as powerful as mine.
Use application.enableevents = false and application.calculation = xlcalculationmanual. Turn them back on before exiting. You must be either triggering an large event or complex calculation cycle if it it taking 3 seconds per cell.
Change,
Dim cell As Range, r As Long
r = 2
For Each cell In ThisWorkbook.Sheets("Sales Entry").Range("E2:E10")
If Len(cell) > 0 Then
Dim old As String
old = cell.Value
ThisWorkbook.Sheets("Sales Entry").Range("E" & r).Value = ""
ThisWorkbook.Sheets("Sales Entry").Range("E" & r).Value = old
r = r + 1
End If
Next cell
... to,
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Dim cell As Range
With ThisWorkbook.Sheets("Sales Entry")
For Each cell In .Range("E2:E10")
If CBool(Len(cell.Value2)) Then
cell = cell.Value2
End If
Next cell
End With
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Try this
Option Explicit
Sub ForceUpdate()
On Error GoTo Cleanup
Dim SalesEntrySheet As Worksheet
Set SalesEntrySheet = ThisWorkbook.Sheets("Sales Entry")
Application.ScreenUpdating = False ' etc..
SalesEntrySheet.Unprotect "password!"
Dim cell As Range, r As Long
Dim ArrayPos As Long
Dim SalesEntrySheetArray As Variant
With SalesEntrySheet
'Starting with row one into the array to ease up the referencing _
so Array entry 2 will be for row 2
SalesEntrySheetArray = .Range("E1:E" & .Cells(.Rows.Count, "E").End(xlUp).Row)
'Clearing the used range in Col E
'If you are using a WorkSheet_Change for the second part of your code then you should rather make this a loop
.Range("E1:E" & .Cells(.Rows.Count, "E").End(xlUp).Row).Value = ""
'Putting the values back into the sheet
For ArrayPos = 2 To UBound(SalesEntrySheetArray, 1)
.Cells(ArrayPos, "E").Value = SalesEntrySheetArray(ArrayPos, 1)
Next ArrayPos
End With
Cleanup:
Application.ScreenUpdating = True ' etc..
ThisWorkbook.Sheets("Sales Entry").Protect "password!", AllowSorting:=True, _
AllowFiltering:=True
End Sub
Try to use with statement.
and take a look at Optimizing VBA macro
Sub ForceUpdate()
On Error GoTo Cleanup
Application.ScreenUpdating = False ' etc..
ThisWorkbook.Sheets("Sales Entry").Unprotect "password!"
Dim cell As Range, r As Long
r = 2
With ThisWorkbook.Sheets("Sales Entry")
For Each cell In .Range("E2:E10")
If Len(cell) > 0 Then
Dim old As String
old = cell.Value
.Cells(4, r) = ""
.Cells(4, r) = old
r = r + 1
End If
Next cell
End With
Cleanup:
Application.ScreenUpdating = True ' etc..
ThisWorkbook.Sheets("Sales Entry").Protect "password!", AllowSorting:=True, AllowFiltering:=True
End Sub
I could use some assistance correcting the code below as what show when activated is the first image while I want to do the second image.
Also if you have other code to do the same job, please do. thanks in advance for your assistance.
Private Sub Worksheet_Activate()
Dim rng As Range, cell As Range
Dim a As Range, az As Range
Application.EnableEvents = False
Set rng = Range("A2:AE2")
Set az = Range("A3:AE6")
For Each cell In rng
For Each a In az
If cell.Value = "Fri" Then
a.Value = "Fri"
ElseIf cell.Value = "Sat" Then
a.Value = "Sat"
End If
Next a
Next cell
Application.EnableEvents = True
End Sub
Use the { and the } in the styling/headers section, above where you type, to insert formatted code next time please so that it looks like this. :)
Edited with your answer:
Private Sub Worksheet_Activate()
Dim rng As Range, cell As Range
Dim a As Range, az As Long 'set az = number of rows you want filled with fri/sat
Application.EnableEvents = False
Set rng = Range("A2:AE2")
az = 4
For Each cell In rng
If cell.Value = "fri" Then
For i = 1 To az
cell.Offset(i).Value = "fri"
Next i
ElseIf cell.Value = "sat" Then
For i = 1 To az
cell.Offset(i).Value = "sat"
Next i
End If
Next cell
Application.EnableEvents = True
End Sub
You get the result because you do it for each cell in az, but you dont wan't to do it so, you have to fill just the column of the found Fri or Sat.
Private Sub Worksheet_Activate()
Dim rng As Range, cell As Range
Application.EnableEvents = False
Set rng = Range("B2:BE2")
For Each cell In rng
If cell.value = "Fri" Then
For i as Integer = 3 To 6 Step 1
Cells(i,cell.column).Value = "Fri"
Next
End If
If cells.value = "Sat" Then
For i as Integer = 3 To 6 Step 1
Cells(i,cell.column).Value = "Sat"
Next
End If
Next cell
Application.EnableEvents = True
End Sub
It should be something like that i think
Also if you have other code to do the same job, please do.
The following will ask to build a new calendar worksheet based upon the current month every time you create a new worksheet.
ThisWorkbook code sheet:
Option Explicit
Private Sub Workbook_NewSheet(ByVal Sh As Object)
If MsgBox("Create new calendar?", vbYesNo, "AutoBuild") <> vbYes Then Exit Sub
'the following DELETES ANY WORKSHEET WITH THE SAME MONTH/YEAR NAME
On Error Resume Next
Application.DisplayAlerts = False
Worksheets(Format(Date, "mmm yyyy")).Delete
Application.DisplayAlerts = True
On Error GoTo 0
'create a new calendar worksheet based on the current month
With Sh
Dim c As Long
.Name = Format(Date, "mmm yyyy")
With .Cells(1, 1).Resize(6, Day(DateSerial(Year(Date), Month(Date) + 1, 0)))
.Formula = "=DATE(" & Year(Date) & ", " & Month(Date) & ", COLUMN())"
.Value = .Value
.Rows(1).NumberFormat = "d"
.Rows(2).Resize(.Rows.Count - 1, .Columns.Count).NumberFormat = "ddd"
.EntireColumn.ColumnWidth = 5 'AutoFit
.HorizontalAlignment = xlCenter
With .Resize(.Rows.Count - 1, .Columns.Count).Offset(1, 0)
With .FormatConditions
.Delete
.Add Type:=xlExpression, Formula1:="=AND(ROW()>2, WEEKDAY(A2, 15)>2)"
.Add Type:=xlExpression, Formula1:="=WEEKDAY(A2, 15)<3"
.Add Type:=xlExpression, Formula1:="=AND(ROW()=2, WEEKDAY(A2, 15)>2)"
End With
.FormatConditions(1).NumberFormat = ";;;"
.FormatConditions(2).Interior.Color = 5287936
.FormatConditions(3).Interior.Color = 14281213
End With
End With
With ActiveWindow
.SplitColumn = 0
.SplitRow = 1
.FreezePanes = True
.Zoom = 80
End With
End With
End Sub
You will likely want to make adjustments but this may be a good framework to get started. I've taken the approach of using the actual dates and displying their day-of-the-month and day-of-the-week through cell Number Format Codes. This leaves the raw underlying date value(s) available for calculation and lookup. Similarly, the dates that appear blank are not actually blank; the custom number format that has been applied through Conditional Formatting simply shows no value at all in the cell.
I've found an answer to part of the question, but I need help to complete the code as it applies to one row only.
Private Sub Worksheet_Activate()
Dim cell As Range, rng As Range
Application.EnableEvents = False
Set rng = Range("A2:AE2")
For Each cell In rng
If Cells(2, cell.Column) = "Fri" Then
Cells(3, cell.Column) = "Fri"
ElseIf Cells(2, cell.Column) = "Sat" Then
Cells(3, cell.Column) = "Sat"
End If
Next cell
Application.EnableEvents = True
End Sub