How to use VBA to change if an Excel file is visible (minimized) based on changes to the grand totals in a pivot table? - excel

I have a live report in Excel that shows if cranes are currently delayed. What I would like to do, by using VBA, is to make it so that when a crane either starts a delay, or ends one, the file will go from being minimized to being expanded so that a user can be signalled for when a crane has gone on delay. I would also like this to only occur for the cranes that are present within the table after being filtered.
I have attached an image of the data along with the relevant filter for cranes.
Crane Delay Data with Crane Filter
My thinking was to scan the Grand Total column, and if the value has changed from being empty to having a figure greater than 0 (and vice versa) to trigger a Macro that will make the file visible.
If possible, what code would I need to use and how would I go about doing this?
Many thanks.

For those interested, I have come up with a solution. Please leave a comment if you want me to talk through it. Code is below:
Option Explicit
Private Sub Worksheet_PivotTableAfterValueChange(ByVal TargetPivotTable As PivotTable, ByVal TargetRange As Range)
End Sub
Public Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
Dim pt As PivotTable
Dim wsBackup As Worksheet
Dim c As Range
Dim rngPivot As Range
Dim lastCol As Long
Dim strCrane As String
Dim sValues As Variant
sValues = ArrayListOfSelectedAndVisibleSlicerItems("Slicer_QC1")
'Change to suit
Set pt = Me.PivotTables("PivotTable1")
'Where has a copy of table been saved?
Set wsBackup = ThisWorkbook.Worksheets("Pivot Copy")
Set rngPivot = pt.DataBodyRange
'How many columns?
lastCol = rngPivot.Columns.Count
Application.ScreenUpdating = False
'Check each cell in last column/grand total
For Each c In rngPivot.Columns(lastCol).Cells
'What item is this?
strCrane = c.Offset(0, -lastCol).Value
'Escape clause
If strCrane = "Grand Total" Then Exit For
If c.Value = 0 Then
'Use a function that won't throw an error
'Note we add 1 to account for row labels
If WorksheetFunction.SumIfs(wsBackup.Columns(1 + lastCol), _
wsBackup.Range("A:A"), strCrane) <> 0 Then
If IsInArray(strCrane, sValues) = True Then
ActiveWindow.WindowState = xlMaximized
MsgBox strCrane & " has ended a delay" & vbCrLf & vbCrLf & "(Minimise Excel after using file)"
End If
End If
ElseIf c.Value > 0 Then
If WorksheetFunction.SumIfs(wsBackup.Columns(1 + lastCol), _
wsBackup.Range("A:A"), strCrane) = 0 Then
If IsInArray(strCrane, sValues) = True Then
ActiveWindow.WindowState = xlMaximized
MsgBox strCrane & " has started a delay" & vbCrLf & vbCrLf & "(Minimise Excel after using file)"
End If
End If
End If
Next c
'Save our new backup
wsBackup.Cells.Clear
pt.TableRange2.Copy
wsBackup.Range("A1").PasteSpecial xlPasteValues
'Clean up
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Function ArrayListOfSelectedAndVisibleSlicerItems(MySlicerName As String) As Variant
'This function returns an array of the limited set of items in Slicer A
'Limitation is due to both:
'(1) direct selection of items by user in slicer A
'(2) selection of items in slicer B which in consequence limits the number of items in slicer A
Dim ShortList() As Variant
Dim i As Integer: i = 0 'for iterate
Dim sC As SlicerCache
Dim sI As SlicerItem 'for iterate
Set sC = ThisWorkbook.SlicerCaches(MySlicerName)
For Each sI In sC.SlicerItems
If sI.Selected = True Then
' Debug.Print sI.Name
ReDim Preserve ShortList(i)
ShortList(i) = sI.Value
i = i + 1
End If
Next sI
ArrayListOfSelectedAndVisibleSlicerItems = ShortList
End Function
Private Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = UBound(Filter(arr, stringToBeFound)) > -1
End Function

Related

Macro that Hides Rows Doesn't Update When Named Range Changes Sizes

I compiled some code that hides rows based on some certain criteria. At the beginning of the code, I unhide all the rows so that when the sheet recalculates the correct rows hide. Here is the code:
Private Sub Worksheet_Calculate()
Dim ws As Worksheet
Dim primaryarray As Range
Dim rw As Range
Set ws = ThisWorkbook.Sheets("Experience Rating Sheet")
Set primaryarray = ws.Range("B9:M322")
Application.ScreenUpdating = False
' unhide all rows before we begin
primaryarray.EntireRow.Hidden = False
For Each rw In primaryarray.Rows
rw.EntireRow.Hidden = BlankOrZero(rw.Cells(4)) And BlankOrZero(rw.Cells(8))
Next rw
Application.ScreenUpdating = True
End Sub
Function BlankOrZero(c As Range)
BlankOrZero = Len(c.Value) = 0 Or c.Value = 0
End Function
The range that it is checking is a named range that shows
=IF(Expected_Actual_Losses="","",Expected_Actual_Losses)
in order to get rid of random zeros.
I have to manually press the the calculate worksheet each time to fix it because the calculation is on manual.
I have tried putting Worksheet.Calculate in the Module to compensate for this but it has not worked.
By compensate, I mean automate this calculation in order to change how many rows are hidden.
Note: The source for the named range is also 2 different sections that have dynamic formulas that change sizes based on criteria I set. Using index/match for one and filter/sortby formulas for the other.
PotterFan,
I beg to differ, the following code has no problem hiding/unhiding rows on a non-active sheet.
Option Explicit
Sub HideFilter(lFilter As Long)
Dim wksHide As Worksheet
Dim lCntr As Long
Dim lFirstRow As Long
Dim lLastRow As Long
Sheets("Sheet1").Select 'Just to make sure not running from Sheet2!
Set wksHide = Sheets("Sheet2")
lFirstRow = Range("HideRange").Row 'Return 1st row
lLastRow = (Range("HideRange").Count - 1) + lFirstRow
wksHide.Range("HideRange").EntireRow.Hidden = False
For lCntr = lLastRow To lFirstRow Step -1
If wksHide.Cells(lCntr, 1).Value = lFilter Then wksHide.Cells(lCntr, 1).EntireRow.Hidden = True
Next lCntr
End Sub
Before:
After:
Turns out when I tried to calculate the worksheet on my other macro it was in-between an Application.EnableEvents command so the Worksheet_Calculate wouldn't trigger when it was supposed to. Here is the other Macro:
Sub UpdateReport()
Application.ScreenUpdating = False
Application.EnableEvents = False
'Puts in the effective date and member name
Dim ws As Worksheet
Dim Report As Variant
Dim xprating As Variant
Set Report = ThisWorkbook.Sheets(Array("Yearly Breakdown", "Loss Template", "Codes", "Yearly Breakdown", "Cover Sheet", "Ag Loss Sensitivity", "Experience Rating Sheet", "Loss Ratio Analysis", "Mod Analysis&Strategy Proposal", "Mod Snapshot", "Mod & Potential Savings"))
Set xprating = ThisWorkbook.Sheets("Experience Rating Sheet")
For Each ws In Report
ws.Calculate
Next ws
For Each ws In Report
ws.Calculate
ws.PageSetup.RightFooter = Sheet17.Range("B3").Text & Chr(10) & "Mod Effective Date: " & Sheet17.Range("B4")
Next ws
Application.EnableEvents = True
xprating.Calculate
Application.ScreenUpdating = True
I just stuck xprating.Calculate after Application.EnableEvents = True and it started updating the rows automatically.

VBA Filter Multiple Columns At Same Time

Jim L from Ontario was a tremendous help in solving my first challenge. You can review that at this link : Previous Discussion
I thought it would be a simple matter to add filters for additional columns once the DATE FILTER QUESTION was solved. Nope.
I've tried adding additional filters within the same confines as the DATE filter ... I've tried adding the additional filters in the same sub but below the DATE filter ... even placing the additional filters in separate subs. Nothing is working.
The example workbook may be downloaded here : Download Workbook
The end users will have a need to filter on one or more columns at the same time. How can I work that in with the existing code in the workbook ?
I'm stumped !
Thanks.
Try adding the auto-filter across all the columns and then use each button to set the criteria for one column only. Here is an example for the fist 3 columns that you can expand to the others.
COL_FILTER is an integer parameter to the sub filterCol which is generic to all the columns you want to add a filter to (except the date which is a special case). Assign your "UNIT" filter button to the sub FilterB, "Call RCVD" button to sub FilterC etc. When you first press any button the filter drop downs appear across all columns but only 1 column will have criteria applied. Pressing further buttons will set criteria for those additional columns and retain the previous filters. Entering a blank search term will remove the criteria for that column only
Option Explicit
Sub ResetFilters()
Dim Wks As Worksheet
Set Wks = Sheets("Call Log File")
With Wks
On Error Resume Next
If Wks.AutoFilterMode Then
Wks.AutoFilterMode = False
End If
End With
End Sub
Sub FilterB()
Call filterCol(2)
End Sub
Sub FilterC()
Call filterCol(3)
End Sub
Sub filterCol(COL_FILTER As Integer)
Dim wb As Workbook, ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Sheets("Call Log File")
' set auto filter to all columns if not already on
Dim rngFilter As Range
Set rngFilter = ws.Range("A2:K2")
If ws.AutoFilterMode = False Then
rngFilter.AutoFilter
End If
'Debug.Print rngFilter.Address
' get filter criteria
Dim sColname As String
sColname = ws.Cells(2, COL_FILTER)
Dim sPrompt As String, sUserInput As String, n As Integer
sPrompt = "Enter " & sColname
sUserInput = InputBox$(sPrompt)
Dim criteria(2) As String
criteria(1) = "*" & sUserInput & "*"
' apply filter to the select column
If ws.AutoFilterMode = True Then
rngFilter.AutoFilter COL_FILTER, "=" & criteria(1)
End If
End Sub
Sub FilterDate()
Const COL_FILTER As Integer = 1 ' A
Dim wb As Workbook, ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Sheets("Call Log File")
' set auto filter to all columns if not already on
Dim rngFilter As Range
Set rngFilter = ws.Range("A2:K2")
If ws.AutoFilterMode = False Then
rngFilter.AutoFilter
End If
'Debug.Print rngFilter.Address
Dim sPrompt As String, sUserInput As String, n As Integer
sPrompt = "Enter DATE" & vbCrLf & _
"For YEAR ONLY: YY" & vbCrLf & _
"For YEAR & MONTH: YYMM" & vbCrLf & _
"For YEAR & MONTH & DAY: YYMMDD"
sUserInput = InputBox$(sPrompt)
n = Len(sUserInput)
If n = 0 Then
rngFilter.AutoFilter COL_FILTER ' clear filter
Exit Sub
ElseIf Not (n = 2 Or n = 4 Or n = 6) Then
MsgBox sUserInput & " is not correct", vbExclamation, "Wrong Format"
Exit Sub
End If
Dim mydate As Variant
mydate = dateRange(sUserInput)
'Debug.Print sUserInput, mydate(1), mydate(2)
If ws.AutoFilterMode = True Then
rngFilter.AutoFilter COL_FILTER, ">=" & mydate(1), 1, "<=" & mydate(2)
End If
End Sub
Function dateRange(s As String)
Dim s1 As String, s2 As String
s1 = "000"
s2 = "999"
Select Case Len(s)
Case 2
s1 = "0101" & s1
s2 = "1231" & s2
Case 4
s1 = "01" & s1
s2 = "31" & s2
Case 6
' nothing to add
Case Else
dateRange = ""
Exit Function
End Select
Dim rng(2) As Long
rng(1) = CLng(s + s1)
rng(2) = CLng(s + s2)
dateRange = rng
End Function
Fo the benefit of others ... this following macro will search for a term in Col B, after the table was filtered by Col A. Although this is not a "filtering approach" in Col B, it is very effective and does precisely what I was looking for.
Thank you to all for your assistance.
Sub FilterB()
Dim cl As Range, rng As Range
Dim sPrompt As String, sUserInput As String
Set rng = Range("B3:B100")
sPrompt = "Enter SEARCH TERM"
sUserInput = InputBox$(sPrompt)
For Each cl In rng.SpecialCells(xlCellTypeVisible)
If cl.Value <> sUserInput Then
cl.Rows.Hidden = True
End If
Next cl
End Sub
And this can be duplicated as many times as required to further "filter down" additional columns.

Copy and paste data from one sheet to multiple where range matches sheet names

I have an API call that pulls data relating to 34 individual sites. Each site has a varying number of assets within it, each with a unique identifier.
I am trying to write a macro that will copy and paste the data for specific sites into their own individual worksheet within the file. The basic concept of this I am familiar with but I am struggling with the ranges I need to specify.
So basically, I need the macro to work its way down Column A of the sheet called Raw Data and identify any rows where the Site name (Value in column A) matches one of the Sheet names. It should then copy the Rows from A to H with that site name and paste into the respective site sheet in rows A to H.
The values in Column A will always match one of the other sheets in the workbook.
Example image that might help explain a bit better:
Apologies in advance if my explanation is not very clear. I have very limited experience using macros so I am not sure if my way of explaining what I want to achieve is understandable or if at all possible.
I am very keen to learn however and any guidance you fine folk could offer would be very much appreciated.
Welcome!
Try this one
Function ChkSheet(SheetName As String) As Boolean
For i = 1 To Worksheets.Count
If Worksheets(i).Name = SheetName Then
ChkSheet = True
Exit Function
End If
Next
ChkSheet = False
End Function
Sub test()
Dim i, j, k As Long
Dim wsRaw As Worksheet
Dim Aux As String
Set wsRaw = Worksheets("Raw Data")
For i = 1 To wsRaw.Range("A:A").SpecialCells(xlCellTypeLastCell).Row
If ChkSheet(wsRaw.Cells(i, 1).Value2) Then
Aux = wsRaw.Cells(i, 1).Value2
k = Worksheets(Aux).Range("A:A").SpecialCells(xlCellTypeLastCell).Row + 1
For j = 1 To 8
Worksheets(Aux).Cells(i + k, j).Value2 = wsRaw.Cells(i, j).Value2
Next
Else
Worksheets.Add.Name = wsRaw.Cells(i, 1).Value2
Aux = wsRaw.Cells(i, 1).Value2
k = 2
For j = 1 To 8
Worksheets(Aux).Cells(i + k, j).Value2 = wsRaw.Cells(i, j).Value2
Next
End If
Next
End Sub
So the Function ChkSheet will check if the sheet exist (you don´t need to create them) and the procedure test will follow all the items that you have in your "Raw Data" worksheet and it will copy to the last used row of every sheet.
And please, even for a newbie, google, read, get some information and when you get stacked, ask for help. This forum is not for giving solutions with not effort.
Good morning all,
David, thanks very much for your help with this. I really didn't want you to think I was trying to get someone to give me the answer and I had tried a few other things before asking the question, but I neglected to show any evidence of my workings. Rookie mistake and I apologise for this.
Having done a bit more research online and with a good dollop of help from a much more experienced colleague I have got the below code using advance filter which works perfectly for what I need.
I thought I would share it here in case it is of any use to others in the future.
Option Explicit
Dim RawDataCol As String
Dim ListCol As String
Dim AdvRng As String
Dim RawDataRng As String
Dim SiteAbrRng As String
Dim ShiftCols As String
Private Sub SetParameters()
'Cell Address where RawData is pasted to each of the site sheets
RawDataCol = "A2"
'Column where the Unique List is cleared and pasted
ListCol = "L"
'Advanced Filter Range
AdvRng = "A1:K2"
'Pasted Raw Data Columns on each sheet
RawDataRng = "A2:K"
'Site Abr gets pasted to the address during loop
SiteAbrRng = "A2"
'Range that gets deleted after pasting Raw Data to each sheet
ShiftCols = "A2:K2"
End Sub
Sub CopyDataToSheets()
On Error GoTo ErrorHandler
AppSettings (True)
Dim StartTime As Double
Dim SecondsElapsed As Double
StartTime = Timer
Dim wbk As Workbook
Dim sht_RawData As Worksheet, sht_target As Worksheet, sht_AdvancedFilter As Worksheet, sht_TurbineData As Worksheet
Dim tbl_RawData As ListObject
Dim LastRow1 As Long, LastRow2 As Long, UniqueListCount As Long
Dim MyArr As Variant
Dim ArrTest As Boolean
Dim x As Long, AdvRowNo As Long
Set wbk = ThisWorkbook
SetParameters
Set sht_RawData = wbk.Worksheets("Raw Data")
Set sht_AdvancedFilter = wbk.Worksheets("Advanced Filter")
Set sht_TurbineData = wbk.Worksheets("Turbine Data")
Set tbl_RawData = sht_RawData.ListObjects("_00")
'clear unqie list of SiteAbr
With sht_TurbineData
LastRow1 = .Cells(Rows.Count, 12).End(xlUp).Row
If LastRow1 > 1 Then
'sht_TurbineData.Range("L1:L" & LastRow1).ClearContents
sht_TurbineData.Range(ListCol & 1 & ":" & ListCol & LastRow1).ClearContents
End If
End With
'Copy Unqiue list of SiteAbr to Turbie Data Sheet
tbl_RawData.Range.Columns(1).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=sht_TurbineData.Range(ListCol & 1), _
Unique:=True
LastRow1 = sht_TurbineData.Cells(Rows.Count, sht_TurbineData.Range(ListCol & 1).Column).End(xlUp).Row
'Sort Unique List
sht_TurbineData.Range("L1:L" & LastRow1).Sort _
Key1:=sht_TurbineData.Range("L1"), _
Order1:=xlAscending, _
Header:=xlYes
'Load unique site Abr to array
With sht_TurbineData
'MyArr = Application.Transpose(.Range("L2:L" & LastRow1))
MyArr = Application.Transpose(.Range(ListCol & 2 & ":" & ListCol & LastRow1))
UniqueListCount = LastRow1 - 1
End With
'Test Array conditions for 0 items or 1 item
ArrTest = IsArray(MyArr)
If UniqueListCount = 1 Then
MyArr = Array(MyArr)
ElseIf UniqueListCount = 0 Then
GoTo ExitSub
End If
For x = LBound(MyArr) To UBound(MyArr)
Set sht_target = wbk.Worksheets(MyArr(x))
With sht_target
'Find the last non blank row of the target paste sheet
LastRow2 = .Cells(Rows.Count, 1).End(xlUp).Row
'Clear contents if the Last Row is not the header row
If LastRow2 > 1 Then
.Range(RawDataRng & LastRow2).ClearContents
End If
sht_AdvancedFilter.Range(SiteAbrRng) = MyArr(x)
'Filter Source Data and Copy to Target Sheet
tbl_RawData.Range.AdvancedFilter _
Action:=xlFilterCopy, _
CriteriaRange:=sht_AdvancedFilter.Range(AdvRng), _
CopyToRange:=.Range(RawDataCol), _
Unique:=False
'Remove the first row as this contains the headers
.Range(ShiftCols).Delete xlShiftUp
End With
Next x
ExitSub:
SecondsElapsed = Round(Timer - StartTime, 3)
AppSettings (False)
'Notify user in seconds
MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
Exit Sub
ErrorHandler:
MsgBox (Err.Number & vbNewLine & Err.Description)
GoTo ExitSub
End Sub
Sub ClearAllSheets()
Dim tbl_SiteList As ListObject
Dim wbk As Workbook
Dim sht_target As Worksheet, sht_TurbineData As Worksheet
Dim MyArray As Variant
Dim x As Long, LastRow As Long
Set wbk = ThisWorkbook
Set sht_TurbineData = wbk.Worksheets("Turbine Data")
Set tbl_SiteList = sht_TurbineData.ListObjects("SiteList")
SetParameters
MyArray = Application.Transpose(tbl_SiteList.DataBodyRange)
For x = LBound(MyArray) To UBound(MyArray)
Set sht_target = wbk.Worksheets(MyArray(x))
LastRow = sht_target.Cells(Rows.Count, 1).End(xlUp).Row
If LastRow > 1 Then
sht_target.Range("A2:K" & LastRow).ClearContents
End If
Next x
End Sub
Private Sub AppSettings(Opt As Boolean)
If Opt = True Then
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
ElseIf Opt = False Then
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End If
End Sub
Thanks again to all who answered and especially to you David. Although I have only used the basic principles from what you offered, it was extremely useful to help me understand what I needed to do in order to get the data to copy into the correct sheets.
Many thanks,
MrChrisP

Excel Macro: Lose line breaks pasting multiple (non-adjacent) rows into a different workbook

This is odd, because it doesn't always happen as described here.
This Macro allows me to select multiple (non-adjacent) rows in any Workbook or Worksheet, copy them to clipboard and delete the rows.
Sub CopytoClipboardandDelete()
Dim obj As New MSForms.DataObject
Dim X, str As String
Dim count As Integer
count = 0
For Each X In Selection
count = count + 1
If X <> "" Then
If count = 1 Then
str = str & X
Else
str = str & Chr(9) & X
End If
End If
If count = 16384 Then
str = str & Chr(13)
count = 0
End If
Next
obj.SetText str
obj.PutInClipboard
Selection.Delete Shift:=xlUp
End Sub
Now, often, when I get to the Active Workbook or Worksheet to paste the row values the row line breaks are lost and all the data goes into the first single row.
Since this occurs so often, I setup a Macro to easily deal with this.
The problem is that this ONLY works when I happen to paste from the clipboard into a blank Worksheet with all the row data now in Row 1.
If I manually insert 4 rows in the other Worksheet or Workbook at a random point, say into Row 20 to Row 24, since there's 4 rows of data in the clipboard; of course this Macro won't work.
Sub FixAllOnLine1OneRowAtATimeToFirstEmpty()
Application.ScreenUpdating = False
Dim copySheet As Worksheet
Dim pasteSheet As Worksheet
Set copySheet = ActiveSheet
Set pasteSheet = ActiveSheet
copySheet.Range("Q1:AF1").Copy
pasteSheet.Cells(Rows.count, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
Columns("Q:AF").Select
Selection.Delete Shift:=xlToLeft
End Sub
This solution is also close, but again lacks the random flexibility.
Split single row into multiple rows based on cell value in excel
So potentially I'm looking for either solution or both if possible. I am oddly curious why certain times pasting from the clipboard using the Sub CopytoClipboardandDelete the rows preserve their line breaks.
I have a clue to when this occurs, but no idea why. When I use the Sub CopytoClipboardandDelete from the source file that was saved as a text file (.txt or .csv) I rarely lose the row line breaks. But when I use the Sub and paste to a new workbook or worksheet, then use the Sub again from this new dataset and paste it on to another new workbook or worksheet it loses the row line-breaks nearly every time.
UPDATE: When using the Tab delimiter setting, I replace all the preexisting Tabs with 4 spaces.
Copy multiple (non-adjacent) ranges to Clip Board as Comma, Tab Or HTML Delimited Table
Notes:
Areas outside the worksheets UsedRange are cropped from source ange
Each Area in the source range is is broken into rows. Range("C1:D1,F1") will result in 2 rows C1:D1 and F1. 8:8,4:4,6:6 will add 3 rows with the first row being row 8 followed by row 4 and finally row 6.
Sample Data
Option Explicit
Enum ClipTableEnum
eCSV
eHTML
eTab
End Enum
Sub PutRangeIntoClipBoard(rSource As Range, Optional clipEnum As ClipTableEnum = eTab, Optional DebugPrint As Boolean = False)
Dim a, arr
Dim x As Long, rwCount As Long
Dim r As Range, rngRow As Range
Dim s As String
With rSource.Worksheet
Set r = Intersect(rSource, .UsedRange)
If InStr(r.Address(False, False), ",") Then
arr = Split(r.Address(False, False), ",")
Else
ReDim arr(0)
arr(0) = r.Address(False, False)
End If
For Each a In arr
rwCount = .Range(a).Rows.count
For x = 1 To rwCount
Set rngRow = .Range(a).Rows(x)
s = s & get1dRangeToString(rngRow, clipEnum)
Next
Next
End With
If DebugPrint Then Debug.Print vbCrLf & s
PutInClipBoard s
End Sub
Function get1dRangeToString(rSource As Range, Optional clipEnum As ClipTableEnum = eTab) As String
Dim arr
Dim s As String
Dim x As Long
If rSource.Cells.count = 1 Then
ReDim arr(0)
arr(0) = rSource.Value
Else
arr = WorksheetFunction.Transpose(rSource)
arr = WorksheetFunction.Transpose(arr)
End If
Select Case clipEnum
Case ClipTableEnum.eCSV
s = """" & Join(arr, """,""") & """" & vbCrLf
Case ClipTableEnum.eHTML
s = "<TR><TD>" & Join(arr, "</TD><TD>") & "</TD></TR>" & vbCrLf
Case ClipTableEnum.eTab
For x = LBound(arr) To UBound(arr)
arr(x) = Replace(arr(x), vbTab, " ")
Next
s = Join(arr, vbTab)
s = s & vbCrLf
End Select
get1dRangeToString = s
End Function
Sub PutInClipBoard(s As String)
Dim clip As DataObject
Set clip = New DataObject
clip.SetText s
clip.PutInClipBoard
Set clip = Nothing
End Sub
Ok I got it to work, sort-of. Now I can highlight any row that has the multiple rows pasted in; e.g. Highlight Row 10 with Row A10-P10 + Row Q10-AF10 + Row AG10-AV10 etc...and it copies Column Q10-AF10, inserts into Column A11-P11 and deletes Columns("Q:AF").
What I need the Macro to do is loop this process until there's no data outside Column A-P.
Sub FixAllOnLine1OneRowAtATimeInsertToNextRow()
Application.ScreenUpdating = False
Dim copySheet As Worksheet
Dim pasteSheet As Worksheet
Set copySheet = ActiveSheet
Set pasteSheet = ActiveSheet
copySheet.Range("Q" & ActiveCell.Row & ":AF" & ActiveCell.Row).Copy
Range("Q" & ActiveCell.Row & ":AF" & ActiveCell.Row).Offset(1).Select
pasteSheet.Cells(ActiveCell.Row, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
Columns("Q:AF").Select
Selection.Delete Shift:=xlToLeft
End Sub

Defining a range from values in another range

I have an excel file of tasks which have either been completed or not, indicated by a Yes or No in a column. Ultimately I am interested in data in a different column but I want to set up the code so it ignores those rows where the task has been completed. So far I have defined the column range containing the yes/no's but I don't know which command to run on this range. I imagine I want to define a new range based on the value in column C.
Option Explicit
Sub Notify()
Dim Chk As Range
Dim ChkLRow As Long
Dim WS1 As Worksheet
On Error GoTo WhatWentWrong
Application.ScreenUpdating = False
'--> If the text in column C is Yes then Ignore (CountIF ?)
'--> Find last cell in the column, set column C range as "Chk"
Set WS1 = Sheets("2011")
With WS1
ChkLRow = .Range("C" & Rows.Count).End(xlUp).Row
Set Chk = .Range("C1:C" & ChkLRow)
End With
'--> Else Check date in column H
'--> Count days from that date until today
'--> Display list in Message Box
Reenter:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Exit Sub
WhatWentWrong:
MsgBox Err.Description
Resume Reenter
Application.ScreenUpdating = True
End Sub
Would it perhaps be easier to simply define one range based on the values in column C rather than first defining column C as the range and then redefining it?
Thanks
Yes Column H has the date the task 'arrived' and I want to display a count from then to the current date. The tasks are identified by a 4 digit code in Column A. I envisage the message box saying Task '1234' outstanding for xx days. – Alistair Weir 1 min ago
Is this what you are trying? Added Col I for visualization purpose. It holds no significance otherwise.
Option Explicit
Sub Notify()
Dim WS1 As Worksheet
Dim Chk As Range, FltrdRange As Range, aCell As Range
Dim ChkLRow As Long
Dim msg As String
On Error GoTo WhatWentWrong
Application.ScreenUpdating = False
Set WS1 = Sheets("2011")
With WS1
ChkLRow = .Range("C" & Rows.Count).End(xlUp).Row
'~~> Set your relevant range here
Set Chk = .Range("A1:H" & ChkLRow)
'~~> Remove any filters
ActiveSheet.AutoFilterMode = False
With Chk
'~~> Filter,
.AutoFilter Field:=3, Criteria1:="NO"
'~~> Offset(to exclude headers)
Set FltrdRange = .Offset(1, 0).SpecialCells(xlCellTypeVisible)
'~~> Remove any filters
ActiveSheet.AutoFilterMode = False
For Each aCell In FltrdRange
If aCell.Column = 8 And _
Len(Trim(.Range("A" & aCell.Row).Value)) <> 0 And _
Len(Trim(aCell.Value)) <> 0 Then
msg = msg & vbNewLine & _
"Task " & .Range("A" & aCell.Row).Value & _
" outstanding for " & _
DateDiff("d", aCell.Value, Date) & "days."
End If
Next
End With
End With
'~~> Show message
MsgBox msg
Reenter:
Application.ScreenUpdating = True
Exit Sub
WhatWentWrong:
MsgBox Err.Description
Resume Reenter
End Sub
SNAPSHOT
Why not brute force it.
Dim r_table as Range, i as Integer, N as Integer
' Start from the top
Set r_table = Sheets("2011").Range("C1")
' Find the last entry on column C and count the # of cells
N = Sheets("2011").Range(r_table, r_table.End(xlDown)).Rows.Count
Dim table_values() as Variant
' This will transfer all the values from the spreadsheet into an VBA array
' and it works super fast. Access values with A(row,col) notation.
table_values = r_table.Resize(N, 5).Value2 ' No. of columns is 5 ?
For i=1 to N
If table_values(i,1)="Yes" Then 'Check Column C
Else
... table_values(i,5) ' Column H
End if
Next i
MsgBox ....
This will be super fast, with no flicker on the screen.

Resources