Change module - one click to toggle button vba excel - excel

I have the following code in a module in Excel, however i'd like to assign it to a toggle button.
Sub Weeks3Hide()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Weekly Hoist Hours")
wsLR = ws.Cells(Rows.Count, 7).End(xlUp).Row
For x = 14 To wsLR
'analyze date, see if it's 3 weeks or older
If ws.Cells(x, 7) <= Date - 21 Then
'hide
ws.Range("a" & x).EntireRow.Hidden = True
End If
Next x
End Sub
I've so far got this: However there is an error in it.
Private Sub ToggleButton4_Click()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Weekly Hoist Hours")
WsLR = ws.Cells(Rows.Count, 7).End(xlUp).Row
If ToggleButton4.Value = True Then
For x = 14 To WsLR
'analyze date, see if it's 3 weeks or older
If ws.Cells(x, 7) <= Date - 21 Then
'hide
ws.Range("a" & x).EntireRow.Hidden = True
End If
Next x
Else
ws.Range(WsLR).EntireRow.Hidden = False
End If
End Sub
Would appreciate any help! Thanks in advance

This line ws.Range(WsLR).EntireRow.Hidden = False.
You cannot refer to range simply with a number. If you are trying to hide a row you can use ws.Rows(WsLR).EntireRow.Hidden = False or something like ws.Rows("A2:A" & WsLR).EntireRow.Hidden = False.

The first thing to do is unhide any hidden rows. I would then iterate over the cells and use Union to create a Range of target Rows. In this way, you can hide all the Rows at once.
Private Sub ToggleButton4_Click()
Dim cell As Range, Rows As Range
With ThisWorkbook.Sheets("Weekly Hoist Hours")
For Each cell In .Range(Cells(14, 7), .Cells(Rows.Count, 7).End(xlUp))
.Rows.Hidden = False
If Not .ToggleButton1.Value Then Exit Sub
If cell.Value <= Date - 21 Then
If Rows Is Nothing Then
Set Rows = cell.EntireRow
Else
Set Rows = Union(Rows, cell.EntireRow)
End If
End If
Next
Rows.Hidden = False
End With
End Sub

Related

Getting error in condition formatting using VBA

I am working on a project in which I am comparing column D with column C of sheet("Backend") and the difference is shown in column E (in %). I'd like to highlight the % difference (column E) in RED color, where the difference is less than -10.00% and greater than 10.00%. Then would like to copy those items from column B corresponding each highlighted cell and paste it in sheet("UPDATER") beneath cell A7.
Attached is the screenshot for your reference
Sub check_date()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim wsData As Worksheet, Datasht As Worksheet, lRow As Integer
Set wsData = Sheets("UPDATER")
Set Datasht = Sheets("Backend")
lRow = Datasht.Cells(Rows.Count, 13).End(xlUp).Row
wsData.Range("M8:M" & lRow).Interior.ColorIndex = xlNone
wsData.Range("M8:M" & lRow).FormatConditions.Add Type:=xlExpression, Formula1:="=AND(M8>=EOMONTH(TODAY(),-2)+1,M8<EOMONTH(TODAY(),-1))"
wsData.Range("M8:M" & lRow).FormatConditions(wsData.Range("M8:M" & lRow).FormatConditions.Count).SetFirstPriority
With wsData.Range("M8:M" & lRow).FormatConditions(1).Interior
.Color = RGB(255, 255, 0)
.TintAndShade = 0
End With
wsData.Range("M8:M" & lRow).FormatConditions(1).StopIfTrue = False
Range("M8").Select
End Sub
Here's what I got. It's a bit of a drastic change but I'm hoping this is actually what you're going for.
Sub formatcondition()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim wsData As Worksheet, Datasht As Worksheet, lRow As Integer, My_Range As Range, i As Integer, iRow As Integer, cell As Variant, RowNum As Long, lRowUpdater As Long
Set wsData = Sheets("UPDATER")
Set Datasht = Sheets("Backend")
lRow = Datasht.Cells(Rows.Count, 5).End(xlUp).Row
lRowUpdater = wsData.Cells(Rows.Count, 1).End(xlUp).Row
RowNum = 8 'setting the first row in the UPDATER sheet
Datasht.Range("E1:E" & lRow).Interior.ColorIndex = xlNone 'Reset the color before running
wsData.Range("A8:D" & lRowUpdater + 8).ClearContents 'clear your updater sheet. Remove if not needed.
For i = 1 To lRow
On Error GoTo Continue
If Datasht.Range("E" & i).Value < -0.1 Or Datasht.Range("E" & i).Value > 0.1 Then 'If greater than or less than
Datasht.Range("E" & i).Interior.ColorIndex = 6 'Change the color of affected cells if you need that
wsData.Range(wsData.Cells(RowNum, 1), wsData.Cells(RowNum, 4)).Value = _
Datasht.Range(Datasht.Cells(i, 2), Datasht.Cells(i, 5)).Value 'straight copy the values from the cells as it loops rather than using copy/paste
wsData.Range(wsData.Cells(RowNum, 2), wsData.Cells(RowNum, 4)).NumberFormat = "0.00%" 'change the number format of outputted cells to percentages (if needed)
RowNum = RowNum + 1 'move to the next row in the output
End If
Continue:
Resume Nexti
Nexti:
Next i
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
EDIT:
For the date to add a year my version would be just adding to what I gave earlier. Instead we now add an AND function to contain the OR, then checking if the YEAR in the cell is the current year. If you're only wanting this year then we can also forgo the IF statement which was checking that if the current month was January it would incorporate December. But if thats not needed then:
=AND(OR(MONTH(NOW())=MONTH(M8),MONTH(NOW())-1=MONTH(M8)),YEAR(M8)=YEAR(NOW()))
Or
=AND(MONTH(M8)>=MONTH(NOW())-1,MONTH(M8)<MONTH(NOW())+1,YEAR(M8)=YEAR(NOW()))
Both the same length and do the same thing just in different way.

Macro to hide certain rows

Column A will always have the date and time in the pictured format, in 1 minute intervals for a whole month.
My first goal is to hide any rows that have a number less than 50 in column B.
Sub HideRows()
Application.ScreenUpdating = False
Application.Calculation = xlManual
For Each c In Range("B:B")
If c.Value < 50 And c.Value <> "" Then Rows(c.Row).Hidden = True
Next
Application.Calculation = xlAutomatic
Application.ScreenUpdating = True
End Sub
That Macro works.
Then, I would also like to hide any consecutive rows that are between the first row starting with a number higher than 50, and the last row higher than 50.
Essentially, it would give me a start and stop time in column A for the flows over 50 in column B.
I don't know enough about coding to hide the times in-between the start and stop times.
Any help/suggestions are greatly appreciated!
Not the most elegant solution, but try this out
Sub StartEnd()
Dim ws As Worksheet
Dim lRow As Long
Dim rng As Range
Dim c As Range
Dim cnt As Long
Dim cntTotal As Long
Set ws = ActiveSheet 'change sheet here if you want
With ws
lRow = .Cells(.Rows.Count, "A").End(xlUp).Row 'last row
Set rng = .Range("B2:B" & lRow) 'excluding headers
cntTotal = Application.CountIf(rng, ">50") 'total occurences >50
For Each c In rng
If IsNumeric(c.value) And c.value > 50 Then
cnt = cnt + 1
Select Case cnt
Case 1, cntTotal: 'do nothing if first or last occurence
Case Else: .Rows(c.Row).Hidden = True 'else hide row
End Select
Else
.Rows(c.Row).Hidden = True 'hide row if <50
End If
Next
End With
End Sub
Here's one way, just for the main logic you're looking for:
Dim in50Block As Boolean
in50Block = False
For Each c In Range("B2:B10000")
If c.Value < 50 And c.Value <> "" Then
Rows(c.Row).Hidden = True
in50Block = False
Else
If in50Block = True And c.Offset(1, 0).Value >= 50 Then
Rows(c.Row).Hidden = True
Else
in50Block = True
End If
End If
Next

Excel VBA macro works randomly

i need some advice regarding this macro.
This macro cuts and copies from "LATURAP" sheet, rows if specific conditions are met. exmpl. starts with number 170889 and so on.
Problem is that, when i run this macro, it will only works once when i have imported this to excel.
Can somebody explain what i'm missing here?
Sub Laturap()
Dim i As Integer
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.EnableEvents = False
a = Worksheets("LATURAP").Cells(Rows.Count, "A").End(xlUp).Row
For i = 3 To a
'selection from LATURAP to 1708
If Left(Range("A" & i), 6) = 170889
Then
Worksheets("LATURAP").Range("A:J").Rows(i).Cut
Worksheets("1708").Activate
b = Worksheets("1708").Cells(Rows.Count, "A").End(xlUp).Row
Worksheets("1708").Cells(b + 1, 1).Select
Worksheets("1708").Paste
Worksheets("LATURAP").Activate
.........
You could try this(comments added in code)...
Sub Laturap()
Dim ws1 As Worksheet, ws2 As Worksheet, i As Long
Set ws1 = ThisWorkbook.Sheets("LATURAP")
Set ws2 = ThisWorkbook.Sheets("1708")
x = 1
With ws1 'wrap your code in the worksheet variable
For i = 3 To .Cells(.Rows.Count, 1).End(xlUp).Row 'you can assign the last row as a variable and use it, this cuts down the lines of code
If Left(.Range("A" & i), 6) = 170889 Then 'check the first 6 characters in each cell in Col A for the value
With .Range("A" & i).Resize(, 10) 'if a match select the range in the row from Col A to Col J using resize.
.Copy Destination:=ws2.Cells(Rows.Count, 1).End(xlUp).Offset(x, 1) 'copy the range pan paste to the first cell in ColB in ws2
.Clear 'clear the range in ws1
x = x + 1 'increases 1 to paste to the next empty row, must be within the If statement
End With
End If
Next i
End With
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.EnableEvents = True
End Sub

Insert a column then put a formula in the blank column 500 times

Here is the code that I am using
Sub insert_column_every_other()
Dim colx As Long
Dim H As Worksheet
Set H = Sheets("Sheet1") 'Replace H3 with the sheet that contains your data
For colx = 9 To 1200 Step 2
Call H.Columns(colx).Insert(Shift:=xlToRight)
H.Range(H.Cells(2, colx), H.Cells(21, colx)).FormulaR1C1 = "=
((OFFSET(RC[-1])-(OFFSET(RC[-3]))/(OFFSET(RC[-3]))*SQRT(252))"
Next colx
End Sub
Getting an error in the following line,
H.Range(H.Cells(2, colx), H.Cells(21, colx)).FormulaR1C1 = "=
((OFFSET(RC[-1])-(OFFSET(RC[-3]))/(OFFSET(RC[-3]))*SQRT(252))"
The error is Application-defined error.
The macro will create a column after the 9th column till the 500th column and then in the blank column will calculate the percentage difference of the stock price of two consecutive days so that's why I went with that particular offset formula.
I think this is what you are looking for
Option Explicit
Sub insert_column_every_other()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
Dim i As Long
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
For i = 9 To 1200 Step 2
ws.Columns(i).Insert
ws.Range(ws.Cells(2, i), ws.Cells(21, i)).Formula = "=(" & ws.Cells(2, i - 1).Address(False, False) & "-" & ws.Cells(2, i - 2).Address(False, False) & ")/(" & ws.Cells(2, i - 2).Address(False, False) & ")*SQRT(252)"
Next i
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub

Excel VBA Range Merge Cells and offset

This can be copied and pasted directly into excel module and run
The issue is in the AddCalendarMonthHeader()
The month cell should be merged, centered, and style but it is not. My only thought is the range.offset() in Main() is affecting it but I dont know why or how to fix it.
Public Sub Main()
'Remove existing worksheets
Call RemoveExistingSheets
'Add new worksheets with specified names
Dim arrWsNames() As String
arrWsNames = Split("BDaily,BSaturday", ",")
For Each wsName In arrWsNames
AddSheet (wsName)
Next wsName
'Format worksheets columns
For Each ws In ThisWorkbook.Worksheets
If ws.name <> "How-To" Then
Call ColWidth(ws)
End If
Next ws
'Insert worksheet header
For Each ws In ThisWorkbook.Worksheets
If ws.name <> "How-To" Then
Call AddSheetHeaders(ws, 2013)
End If
Next ws
'Insert calendars
For Each ws In ThisWorkbook.Worksheets
If ws.name <> "How-To" Then
Call AddCalendars(ws, 2013)
End If
Next ws
End Sub
Public Sub AddCalendars(ByVal ws As Worksheet, year As Integer)
Dim startCol As Integer, startRow As Integer
Dim month1 As Integer, month2 As Integer
month1 = 1
month2 = 2
Dim date1 As Date
Dim range As range
Dim rowOffset As Integer, colOffset As Integer
Set range = ws.range("B1:H1")
'Loop through all months
For i = 1 To 12 Step 2
Set range = range.Offset(1, 0)
date1 = DateSerial(year, i, 1)
'Add month header
Call AddCalendarMonthHeader(monthName(i), range)
'Add weekdays header
Set range = range.Offset(1, 0)
Call AddCalendarWeekdaysHeader(ws, range)
'Loop through all days in the month
'Add days to calendar ' For j = 1 To DaysInMonth(date1)
Dim isFirstWeek As Boolean: isFirstWeek = True
Dim firstWeekOffset As Integer: firstWeekOffset = Weekday(DateSerial(year, i, 1))
For j = 1 To 6 'Weeks in month
Set range = range.Offset(1, 0)
range.Cells(1, 1).Value = "Week " & j
For k = 1 To 7 'Days in week
If isFirstWeek Then
isFirstWeek = False
k = Weekday(DateSerial(year, i, 1))
End If
Next k
'Exit For 'k
Next j
'Exit For 'j
'Exit For 'i
Set range = range.Offset(1, 0)
Next i
End Sub
Public Sub AddCalendarMonthHeader(month As String, range As range)
With range
.Merge
.HorizontalAlignment = xlCenter
' .Interior.ColorIndex = 34
.Style = "40% - Accent1"
'.Cells(1, 1).Font = 10
.Font.Bold = True
.Value = month
End With
End Sub
Public Sub AddCalendarWeekdaysHeader(ws As Worksheet, range As range)
For i = 1 To 7
Select Case i
Case 1, 7
range.Cells(1, i).Value = "S"
Case 2
range.Cells(1, i).Value = "M"
Case 3, 5
range.Cells(1, i).Value = "T"
Case 4
range.Cells(1, i).Value = "W"
Case 6
range.Cells(1, i).Value = "F"
End Select
range.Cells(1, i).Style = "40% - Accent1"
Next i
End Sub
Public Function DaysInMonth(date1 As Date) As Integer
DaysInMonth = CInt(DateSerial(year(date1), month(date1) + 1, 1) - DateSerial(year(date1), month(date1), 1))
End Function
'Remove all sheets but the how-to sheet
Public Sub RemoveExistingSheets()
Application.DisplayAlerts = False
On Error GoTo Error:
For Each ws In ThisWorkbook.Sheets
If ws.name <> "How-To" Then
ws.Delete
End If
Next ws
Error:
Application.DisplayAlerts = True
End Sub
'Add a new sheet to end with given name
Public Sub AddSheet(name As String)
ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count)).name = name
End Sub
'Set sheet column widths
Public Sub ColWidth(ByVal ws As Worksheet)
Application.ScreenUpdating = False
On Error GoTo Error:
Dim i As Long
For i = 1 To 26
ws.Columns(i).ColumnWidth = 4.43
Next i
Error:
Application.ScreenUpdating = True
End Sub
Public Sub AddSheetHeaders(ByVal ws As Worksheet, year As Integer)
Dim range As range
Set range = ws.range("B1", "P1")
With range
.Merge
.HorizontalAlignment = xlCenter
.Font.ColorIndex = 11
.Font.Bold = True
.Font.Size = 26
.Value = year
End With
End Sub
The issue you are having is that after the first range is merged, the length of the range becomes one column on offsetting. So after that, the next ranges are messed up.
For i = 1 To 12 Step 2
Set range = range.Offset(1, 0) ' Range is 7 columns wide
date1 = DateSerial(year, i, 1)
'Add month header
Call AddCalendarMonthHeader(MonthName(i), range) ' We merge and range is now 1 column
'Add weekdays header
Set range = range.Offset(1, 0) ' Fix here to make it 7 columns
.
.
.
To Fix this, all you need to do is change the size of the range before adding the weekdays header
'Add weekdays header
Set range = range.Offset(1, 0).Resize(1, 7)
Woah, I'm really surprised this works at all! Range is a keyword in VBA and Excel, so it is very surprising to me you are able to use that as a variable name without problems.
You can troubleshoot problems like this a lot easier by adding a debug statement:
'Add month header
Debug.Print "Range Address: " & range.Address & vbTab & "i:" & i
Call AddCalendarMonthHeader(MonthName(i), range)
Debug.Print "Range updated00: " & range.Address
'Add weekdays header
Debug.Print "Range updated0: " & range.Address
Set range = range.Offset(1, 0) `<---- this is the line where the Offset loses the entire row
Debug.Print "Range updated1: " & range.Address
This results in the following:
Range Address: $B$2:$H$2 i:1
Range updated00: $B$2:$H$2
Range updated0: $B$2:$H$2
Range updated1: $B$3
So after the second offset, your range variable is only a single cell, which means it cannot be merged. Interestingly this is the case even if your range variable is renamed.
Now, this behavior ONLY occurs when the .Merge function from your method AddCalendarMonthHeader is invoked (commenting this out shows your range addresses are accurate for each iteration).
It seems this is directly caused by using .Merge - a fair bit of messing around on my part indicates even the following code will still have the same problem (note: I renamed your range variable to mrange):
Debug.Print "Range updated First: " & mrange.Address
Set mrange = mrange.Offset(1, 0)
date1 = DateSerial(year, i, 1)
'Add month header
Debug.Print "Range Address: " & mrange.Address & vbTab & "i:" & i
Dim mStr As String
mStr = mrange.Address
AddCalendarMonthHeader MonthName(i), mrange
Debug.Print "Range updated00: " & mrange.Address
'Add weekdays header
Debug.Print "Range updated0: " & mrange.Address
Set mrange = range(mStr)
Set mrange = mrange.Offset(1, 0)
Debug.Print "Range updated1: " & mrange.Address
TL;DR
Using .Merge causes abnormal functionality with VBA when using .Offset. I would recommend trying to modify your code to not use merge, perhaps as Alexander says or some other formatting strategy.

Resources