Selecting column range with specific header - excel

I have a macro code but it runs on specific column and on range of 500 only. I wish it should dynamically select column of header 'PRODUCTS' is present. if possible can we increase the limit of 500 to all the data present in column 'PRODUCTS'.
Sub Pats()
myCheck = MsgBox("Do you have Patent Numbers in Column - B ?", vbYesNo)
If myCheck = vbNo Then Exit Sub
endrw = Range("B500").End(xlUp).Row
Application.ScreenUpdating = False
For i = 2 To endrw
PatNum = Cells(i, 2).Value
If Left(Cells(i, 2), 2) = "US" Then
link = "http://www.google.com/patents/" & PatNum
Cells(i, 2).Select
ActiveSheet.Hyperlinks.Add Anchor:=Selection, Address:="http://www.google.com/patents/" & PatNum, ScreenTip:="Click to View", TextToDisplay:=PatNum
With Selection.Font
.Name = "Arial"
.Size = 10
End With
ElseIf Left(Cells(i, 2), 2) = "EP" Then
link = "http://www.google.com/patents/" & PatNum
Cells(i, 2).Select
ActiveSheet.Hyperlinks.Add Anchor:=Selection, Address:="http://www.google.com/patents/" & PatNum, ScreenTip:="Click to View", TextToDisplay:=PatNum
With Selection.Font
.Name = "Arial"
.Size = 10
End With
End If
Next i
End Sub

I would first extract the link building part into a separate subroutine ...
Sub AddLink(c As Range)
Dim link As String
Dim patNum As String
Dim test As String
patNum = c.Value
test = UCase(Left(patNum, 2))
If test = "US" Or test = "EP" Then
link = "http://www.google.com/patents/" & patNum
Else
link = "http://www.www.hyperlink.com/" & patNum
End If
c.Hyperlinks.Add Anchor:=c, Address:=link, ScreenTip:="Click to View", TextToDisplay:=patNum
With c.Font
.Name = "Arial"
.Size = 10
End With
End Sub
Then I would add a function to find the column...
Function FindColumn(searchFor As String) As Integer
Dim i As Integer
'Search row 1 for searchFor
FindColumn = 0
For i = 1 To ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Column
If ActiveSheet.Cells(1, i).Value = searchFor Then
FindColumn = i
Exit For
End If
Next i
End Function
Finally I would put it all together ...
Sub Pats()
Dim col As Integer
Dim i As Integer
col = FindColumn("PRODUCTS")
If col = 0 Then Exit Sub
For i = 2 To ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
AddLink ActiveSheet.Cells(i, col)
Next i
End Sub
I'll admit I have to use SO to remind myself how to get the last used cell on a worksheet (see Find Last cell from Range VBA).

The code below will find which column has the header PRODUCTS and then find the last row in that column and store it in variable lrProdCol.
Sub FindProductLR()
Dim col As Range
Dim endrw As Long
Set col = Rows(1).Find("PRODUCTS")
If Not col Is Nothing Then
endrw = Cells(Rows.count, col.Column).End(xlUp).Row
Else
MsgBox "The 'PRODUCTS' Column was not found in row 1"
End If
End Sub
So replace the following bit of code
myCheck = MsgBox("Do you have Patent Numbers in Column - B ?", vbYesNo)
If myCheck = vbNo Then Exit Sub
endrw = Range("B500").End(xlUp).Row
With the lines above. Hope that helps

Related

Previous and Next Button function to VBA Data Entry form is not working

Previous Record and Next Record sub routine is not working. I marked with 1 and 2. These two navigation bars (1&2) works on the what is entered on WaypointId.
Say for example, if I say waypoint id=1235, then next record should appear in a data entry form. My vba code is first search the row number of waypoint id in observation sheet and then I decrease the row number by 1 for displaying previous record and increase the row number by 1 for next record. Depends on the functionality it shows data in the Data Entry Form.
My VBA code is not working for those two things. Attach workbook with name Problem-1.xlsm See Navigation Control Module.
Sub FindRecord(WyPt)
Dim Value As String
WyPtRow = 0
ReadRow = 2
Value = Cells(ReadRow, 2)
While Value <> ""
If WyPt = Value Then
WyPtRow = ReadRow
Exit Sub
End If
ReadRow = ReadRow + 1
Value = Cells(ReadRow, 2)
Wend
End Sub
Sub ViewPreviousRecord()
Set DEFrm = Sheets("DataEntryForm")
Set ObsData = Sheets("Observations")
Dim WyPt As String
WyPt = Trim(DEFrm.Cells(6, 2))
Call FindRecord(WyPt)
LastRow = WyPtRow - 1
With DEFrm
.Cells(6, 2).Value = ObsData.Cells(LastRow, 2).Value 'WaypointID
.Cells(6, 4).Value = ObsData.Cells(LastRow, 3).Value 'ObsType
.Cells(8, 2).Value = ObsData.Cells(LastRow, 4).Value 'Date
.Cells(8, 4).Value = ObsData.Cells(LastRow, 5).Value 'LoggedBy
End With
End Sub
Sub ViewNextRecord()
Set DEFrm = Sheets("DataEntryForm")
Set ObsData = Sheets("Observations")
Dim WyPt As String
WyPt = Trim(DEFrm.Cells(6, 2))
Call FindRecord(WyPt)
LastRow = WyPtRow + 1
With DEFrm
.Cells(6, 2).Value = ObsData.Cells(LastRow, 2).Value 'WaypointID
.Cells(6, 4).Value = ObsData.Cells(LastRow, 3).Value 'ObsType
.Cells(35, 10).Value = ObsData.Cells(LastRow, 115) 'Photo4Desc
End With
End Sub
This is the most important procedure in your project.
Sub DisplayRecord(ByVal Rs As Long)
' 235
Dim Arr As Variant ' Data from row Rs in database
Dim Target() As String ' Dashboard addresses matching Arr
Dim i As Long ' loop counter: Arr(Index)
' cell addresses are aligned with column numbers in database (-2)
Arr = "B6,D6,B8,D8,G6,H6,G7,H7,G8,H8,B11,C11,D11,E11,F11,G11,H11,I11"
Arr = Arr & ",B14,C14,D14,E14,F14,G14,B17,C17,D17,E17,F17,G17"
Arr = Arr & ",I14,J14,I15,J15,I16,J16,I17,J17,B20,C20,D20,E20,F20,G20"
Arr = Arr & ",B23,C23,D23,E23,F23"
Arr = Arr & ",I20,J20,K20,I21,J21,K21,I2,J22,K22,I23,J23,K23"
Arr = Arr & ",B26,C26,D26,E26,F26,G26,H26,I26,J26,K26"
Arr = Arr & ",B27,C27,D27,E27,F27,G27,H27,I27,J27,K27"
Arr = Arr & ",B28,C28,D28,E28,F28,G28,H28,I28,J28,K28"
Arr = Arr & ",B29,C29,D29,E29,F29,G29,H29,I29,J29,K29"
Arr = Arr & ",B32,H32,I32,J32,H33,I33,J33,H34,I34,J34,H35,I35,J35"
Target = Split(Arr, ",")
With Sheets("Observations")
Arr = .Range(.Cells(Rs, 1), .Cells(Rs, 115)).Value
End With
Application.ScreenUpdating = False ' speed up execution
For i = 2 To UBound(Arr, 2) ' skip first database column
Sheets("DataEntryForm").Range(Target(i - 2)).Value = Arr(1, i)
Next i
Application.ScreenUpdating = True
End Sub
It displays the data of the row Rs given to it as an argument. You already have a function that finds the row number needed by the above procedure. Below please find an improvement.
Function RecordRow(ByVal WyPt As String) As Long
' 235
' return the row number where WyP was found or 0
Dim Fnd As Range
With Worksheets("Observations")
Set Fnd = .Range(.Cells(2, "B"), .Cells(.Rows.Count, "B").End(xlUp))
Set Fnd = Fnd.Find(WyPt, , LookIn:=xlValues, lookat:=xlWhole)
If Not Fnd Is Nothing Then
RecordRow = Fnd.Row
End If
End With
End Function
The deal is simple: you give the Waypoint ID and receive the row number where it was found. If it isn't found the function returns 0, and that is how you avoid crashes.
With these two procedures in place you can easily call up the first and the last records.
Sub ViewFirstRecord()
' 235
DisplayRecord 2
End Sub
Sub ViewLastRecord()
' 235
With Worksheets("Observations")
DisplayRecord .Cells(.Rows.Count, "A").End(xlUp).Row
End With
End Sub
The next and previous records are just a matter of finding the row number and displaying its data.
Sub ViewNextRecord()
' 235
Dim Rs As Long ' data source row
Rs = RecordRow(Trim(Cells(6, 2).Value)) + 1
If Rs > 1 Then
With Worksheets("Observations")
If Rs <= .Cells(.Rows.Count, "A").End(xlUp).Row Then
DisplayRecord Rs
Else
MsgBox "No more records to show.", vbInformation, "Last record"
End If
End With
End If
End Sub
Sub ViewPreviousRecord()
' 235
Dim Rs As Long ' data source row
Rs = RecordRow(Trim(Cells(6, 2).Value)) - 1
If Rs > 1 Then
DisplayRecord Rs
Else
MsgBox "No more records to show.", vbInformation, "First record"
End If
End Sub
If that's the whole code, you may be finding a problem with scope. It seems ViewPreviousRecord() is not able to see WyPtRow.
You can try adding
dim WyPtRow
Before the Sub FindRecord(WyPt) definition.
Another implementation would be changing the Sub for a function, and returning the WyPtRow value.

Merge cells with same year in a row

I need to merge the cells one above the months.
Cells Should be merged from 01 to 12 showing year in cell.
Look for the picture for more clarification.
I have below code, but which show months after run in cell row1.
My idea is to convert above cells to years through vba and apply merge same year at the end.
which is shown in desired output.
Note.
ROW 4 and 5 are just my thinking, which will help year to merge.
Dim a(), i As Long, j As Long, m As Long, x As Range
With Range("b1:qaz1")
.MergeCells = False
.ClearContents
a() = .Offset(1).Value
m = Month(a(1, 1))
j = UBound(a, 2)
Set x = .Cells(1)
For i = 2 To j
If m <> Month(a(1, i)) Or i = j Then
With Range(x, .Cells(i - IIf(i = j, 0, 1)))
.MergeCells = True
.HorizontalAlignment = xlCenter
End With
x.Value = Format(DateSerial(2000, m, 1), "MMMM")
m = Month(a(1, i))
Set x = .Cells(i)
End If
Next
End With
End Sub
After running new program output look like
Since you have true dates in your caption row the month and year can be extracted from there. However, the code below converts dates that might have been created using formulas to hard dates before processing them.
Sub MergeCaptionsByYear()
' 031
Const CapsRow As Long = 1 ' change to suit
Const StartClm As Long = 2 ' change to suit
Dim Rng As Range ' working range
Dim Tmp As Variant ' current cell's value
Dim Cl As Long ' last used column
Dim Cstart As Long ' first column in Rng
Dim C As Long ' working column
Dim Yr As Integer ' year
Cl = Cells(CapsRow, Columns.Count).End(xlToLeft).Column
Range(Cells(CapsRow, StartClm), Cells(CapsRow, Cl)).Copy
Cells(CapsRow, StartClm).PasteSpecial xlValues
Application.CutCopyMode = False
C = StartClm - 1
Application.DisplayAlerts = False
Do
Tmp = Cells(CapsRow, C + 1).Value
If Not IsDate(Tmp) And (C <> Cl) Then
MsgBox "Cell " & Cells(CapsRow, C + 1).Address(0, 0) & _
" doesn't contain a date." & vbCr & _
"This macro will be terminated.", _
vbInformation, "Invalid cell content"
Exit Do
End If
If (Yr <> Year(CDate(Tmp))) Or (C = Cl) Then
If Yr Then
Set Rng = Range(Cells(CapsRow, Cstart), _
Cells(CapsRow, C))
With Rng
.Merge
.HorizontalAlignment = xlCenter
.NumberFormat = "yyyy"
End With
SetBorder Rng, xlEdgeLeft
SetBorder Rng, xlEdgeRight
End If
If C > (Cl - 1) Then Exit Do
Cstart = C + 1
Yr = Year(Tmp)
End If
C = C + 1
Loop
Application.DisplayAlerts = True
End Sub
Private Sub SetBorder(Rng As Range, _
Bord As XlBordersIndex)
' 031
With Rng.Borders(Bord)
.LineStyle = xlContinuous
.ColorIndex = xlAutomatic
.TintAndShade = 0
.Weight = xlMedium ' xlThin
End With
End Sub
Assuming the months range is "B5:AH5"
Sub test()
Dim monthsRng As Range
Set monthsRng = Range("B5:AH5")
monthsRng.Cells(1, 1).Offset(-1, 0).Select
For j = 1 To Int((monthsRng.Cells.Count / 12) + 2)
If ActiveCell.Offset(1, 0) <> 0 Then
For i = 1 To 12
ActiveCell.Value = Year(ActiveCell.Offset(1, 0))
If Year(ActiveCell.Offset(1, i)) = ActiveCell Then
Selection.Resize(1, i + 1).Select
Else
Exit For
End If
Next
With Selection
.HorizontalAlignment = xlCenter
.MergeCells = True
End With
Selection.Offset(0, 1).Select
Else
Exit For
End If
Next
End Sub
Replacing the inner for loop with below code will work irrespective of whether the dates in the Range("B5:AH5") in above procedure are formatted as dates or not.
For i = 1 To 12
ActiveCell.Value = Right(Format(ActiveCell.Offset(1, 0), "DD.MM.YYYY"), 4)
If Right(Format(ActiveCell.Offset(1, i), "DD.MM.YYYY"), 4) = Format(ActiveCell, Text) Then
Selection.Resize(1, i + 1).Select
Else
Exit For
End If
Next
However, in any case you need to format the output in excel as number (without 1000 separator and decimal places) and not date.

VBA why am i getting error or popup saying "16"

In the code shown below, i am in the first section moving data from sheet "Ark2" to the sheet "Ark1". in the second section, i transpose from vertical to horizontal. Now i am rinning it in module, but i am getting an popup saying "16" and it is deleting data from my sheet "Ark2" and therefor also data on ark2.
it is not adding data from the first sheet to the second or horizonting the colums.
hope you can help!!
Sub MyProcedure()
a = Worksheets("ark1").Cells(Rows.Count, 1).End(xlUp).Row
MsgBox (a)
End Sub
Private Sub CommandButton1_Click()
Dim nøgletal As String, år As Integer
Worksheets("Ark2").Select
nøgletal = Range("B2")
år = Range("C2")
Worksheets("Ark1").Select
Worksheets("Ark1").Range("A4").Select
ThisWorkbook.Worksheets("Ark1").Range("C1:C100").Value = ThisWorkbook.Worksheets("Ark2").Range("C12:C100").Value
ThisWorkbook.Worksheets("Ark1").Range("D1:D100").Value = ThisWorkbook.Worksheets("Ark2").Range("D12:D100").Value
ThisWorkbook.Worksheets("Ark1").Range("E1:E100").Value = ThisWorkbook.Worksheets("Ark2").Range("M12:M100").Value
ThisWorkbook.Worksheets("Ark1").Range("F1:F100").Value = ThisWorkbook.Worksheets("Ark2").Range("N12:N100").Value
ThisWorkbook.Worksheets("Ark1").Range("G1:G100").Value = ThisWorkbook.Worksheets("Ark2").Range("O12:O100").Value
ThisWorkbook.Worksheets("Ark1").Range("A1:A16").Value = ThisWorkbook.Worksheets("Ark2").Range("A12:A16").Value
If Worksheets("Ark1").Range("A4").Offset(1, 0) <> "" Then
Worksheets("Ark1").Range("A4").End(xlDown).Select
End If
ActiveCell.Offset(1, 0).Select
ActiveCell.Value = nøgletal
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = år
Worksheets("Ark2").Select
Worksheets("Ark2").Range("B2", "B16").Select
End Sub
Sub x()
Dim lngDataColumns As Long
Dim lngDataRows As Long
lngDataColumns = 3
lngDataRows = 4
For t = 1 To lngDataRows
Range("l2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("e1:g1").Value)
Range("M2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("e1:g1").Offset(t).Value)
Next t
End Sub
why am i getting error or popup saying “16”
Should be evident why if you add a value in say ark1!A17 and rerun:
Sub MyProcedure()
a = Worksheets("ark1").Cells(Rows.Count, 1).End(xlUp).Row
MsgBox (a)
End Sub
If not, try adding also into ark1!A18 and rerunning.

VBA Userform Listbox Conditional Logic Not Working as Intended

I have a Userform with a listbox for which I am using conditional logic to determine output values to the sheet of selected or non-selected items in the listbox. The issue is that when the Textbox (Tbl_AliasName) is blank, the code executes this:
ElseIf .Selected(k) = True And Tbl_AliasName = vbNullString Then
lstbxRow = lstbxRow + 1
Worksheets("New TRAX").Cells(lstbxRow, 3) = Trim(Cells(2, 1).Value2) & "." & .Column(1, k)
But if Tbl_AliasName is not blank then the code does nothing, but it is supposed to do this:
ElseIf .Selected(k) = True And Tbl_AliasName <> vbNullString Then
lstbxRow = lstbxRow + 1
Worksheets("New TRAX").Cells(lstbxRow, 3) = Tbl_AliasName & "." & .Column(1, k)
I have used several variations of If statements, and non of which have worked.
Below is My Code:
Option Explicit
Public Tbl_AliasName As String
Tbl_AliasName = Trim(UserForm_Finder.txtConcat.Value)
Private Sub BtnConcat_Click()
Dim k As Long, lstbxRow As Long, LR As Long
lstbxRow = 1
'****************
'This if statement works perfectly
If (Cells(2, 1).Value2 = vbNullString Or Cells(2, 2).Value2 = vbNullString) _
And Tbl_AliasName = vbNullString Then
MsgBox "You must Search for a Table or Column first.", _
vbExclamation, "Error Encountered"
Exit Sub
ElseIf (UserForm_Finder.ListBx_TblsCols.ListCount = 0 And Tbl_AliasName <> vbNullString) Then
MsgBox "You must Search for a Table or Column first.", _
vbExclamation, "Error Encountered"
'(Cells(2, 1).Value2 = vbNullString Or Cells(2, 2).Value2 = vbNullString) And _
Exit Sub
End If
With UserForm_Finder.ListBx_TblsCols
For k = 0 To .ListCount - 1
'****************
This is where the problems begin
If .Selected(k) = False Then
MsgBox "You must Select 1 or more items from the list box.", _
vbExclamation, "Error Encountered"
Exit Sub
ElseIf .Selected(k) = True And Tbl_AliasName <> vbNullString Then
lstbxRow = lstbxRow + 1
Worksheets("New TRAX").Cells(lstbxRow, 3) = Tbl_AliasName & "." & .Column(1, k)
ElseIf .Selected(k) = True And Tbl_AliasName = vbNullString Then
lstbxRow = lstbxRow + 1
Worksheets("New TRAX").Cells(lstbxRow, 3) = Trim(Cells(2, 1).Value2) & "." & .Column(1, k)
End If
Next k
End With
End Sub
My goal is to do the following:
If a Textbox (Tbl_AliasName) is not blank and the user has selected one or more items in the listbox (ListBx_TbleCols) then concatenate the Tbl_AliasName to the selected items in the listbox
If Tbl_AliasName is blank, then use the value in Cells(2,1) to concatenate to the selected Items in the list box.
I have tried the following additions:
Dim LstBxItemSelected As Boolean
'This was placed in the for loop
LstBxItemSelected = True
'this was placed outside the for loop
If LstBxItemSelected = False Then
MsgBox "You must Select 1 or more items from the list box.", _
vbExclamation, "Error Encountered"
Exit Sub
End If
Is there a better way to tell if items are selected, because I feel that the way I have it structured in my loop, the code will throw the error if everything isn't selected? Thank you in advance for any ideas, answers, or suggestions!
Note: The Listbox is populated by the click of another button on the userform which calls the following sub:
Sub FillLstBxCols()
Dim ListBx_Target As MSForms.ListBox
Dim rngSource As Range
Dim LR As Long
If Cells(2, 1).Value2 <> vbNullString Then
LR = Worksheets("New TRAX").Cells(Rows.Count, 2).End(xlUp).Row
'Set reference to the range of data to be filled
Set rngSource = Worksheets("New Trax").Range("A" & 2 & ":" & "B" & LR)
'Fill the listbox
Set ListBx_Target = UserForm_Finder.ListBx_TblsCols
With ListBx_Target
.RowSource = rngSource.Address
End With
End If
End Sub
Hard to say without sample data and expected results, but I think this is what you're looking for:
Private Sub btnConcat_Click()
Dim ws As Worksheet
Dim bSelected As Boolean
Dim sConcat As String
Dim i As Long, lRowIndex As Long
Set ws = ActiveWorkbook.Sheets("New TRAX")
lRowIndex = 1
bSelected = False
sConcat = Trim(Me.txtConcat.Text)
If Len(sConcat) = 0 Then sConcat = Trim(ws.Cells(2, "A").Value)
If Len(sConcat) = 0 Then
MsgBox "You must Search for a Table or Column first.", vbExclamation, "Error Encountered"
Exit Sub
End If
For i = 0 To Me.ListBx_TblsCols.ListCount - 1
If Me.ListBx_TblsCols.Selected(i) Then
If bSelected = False Then
bSelected = True
ws.Range("C2", ws.Cells(ws.Rows.Count, "C")).Clear 'clear previous concat results (delete this line if not needed)
End If
lRowIndex = lRowIndex + 1
ws.Cells(lRowIndex, "C").Value = sConcat & "." & Me.ListBx_TblsCols.List(i)
End If
Next i
If bSelected = False Then MsgBox "Must select at least one item from the list"
End Sub

copying rows with checked checkboxes

I would like to consolidate rows with checked checkboxes from three sheets (“Liver”, ”Lung” and “Kidney”) into one sheet "Report". I would like to grab rows that do not contain word "sample" in column A. When I paste the data into "Report" I would like to label each group of rows with the corresponding originating sheet name by adding a row in between that contains the sheet name, in column A.
I came up with this code which goes into an infinite loop and I have to kill Excel to stop it. This is just for "Lung" sheet only but I'm hoping to reproduce it for the other two sheets.
Ideally, I would like to use arrays to transfer the data but I'm not sure how to work it out. Any suggestions on how to fix what I already have or to improve it would be greatly appreciated.
Thank you
For Each chkbx In ActiveSheet.CheckBoxes
If chkbx.Value = 1 Then
For r = 2 To Rows.count
If Cells(r, 1).Top = chkbx.Top And InStr(Cells(r, 1).Value, "Sample") < 0 Then
'
With Worksheets("Report")
LRow = .Range("A" & Rows.count).End(xlUp).Row + 1
.Range("A" & LRow & ":P" & LRow) = _
Worksheets("Lung").Range("A" & r & ":P" & r).Value
End With
Exit For
End If
Next r
End If
Next
The code bellow will generate the following reports (details bellow):
.
There are 3 sections, but all code should be pasted into one user module:
.
Subs to execute:
Option Explicit
Private Const REPORT As String = "Report_"
Private Const EXCLUDE As String = "Sample"
Private Const L_COL As String = "P"
Private wsRep As Worksheet
Private lRowR As Long
Public Sub updateSet1()
updateSet 1
End Sub
Public Sub updateSet2()
updateSet 2
End Sub
Public Sub updateSet3()
updateSet 3
End Sub
Public Sub updateSet(ByVal id As Byte)
Application.ScreenUpdating = False
showSet id
Application.ScreenUpdating = True
End Sub
Public Sub consolidateAllSheets()
Application.ScreenUpdating = False
With ThisWorkbook
consolidateReport .Worksheets("COLON"), True 'time stamp to 1st line of report
consolidateReport .Worksheets("LUNG")
consolidateReport .Worksheets("MELANOMA")
wsRep.Rows(lRowR).Borders(xlEdgeBottom).LineStyle = xlContinuous
End With
Application.ScreenUpdating = True
End Sub
.
showSet() - use 1 for Set1, 2 for Set2, 3 for Set2 edited:
Public Sub showSet(ByVal id As Byte)
Dim ws As Worksheet, cb As Shape, lft As Double, mid As Double, thisWs As Worksheet
Dim lRed As Long, lBlu As Long, cn As String, cbo As Object, s1 As Boolean
If id <> 1 And id <> 2 And id <> 3 Then Exit Sub
lRed = RGB(255, 155, 155): lBlu = RGB(155, 155, 255)
Set thisWs = ThisWorkbook.ActiveSheet
For Each ws In ThisWorkbook.Worksheets
If InStr(1, ws.Name, REPORT, vbTextCompare) = 0 Then
lft = ws.Cells(1, 2).Left
mid = lft + ((ws.Cells(1, 2).Width / 2) - 5)
For Each cb In ws.Shapes
cn = cb.Name
Set cbo = cb.OLEFormat.Object
s1 = InStr(1, cn, "set1", 1) > 0
If id < 3 Then
cb.Visible = IIf(s1, (id = 1), (id <> 1))
cb.Left = IIf(cb.Visible, mid, lft)
cbo.Interior.Color = IIf(s1, lBlu, lRed)
Else
cb.Visible = True
cb.Left = IIf(s1, lft + 3, mid + 6.5)
cbo.Interior.Color = IIf(s1, lBlu, lRed)
End If: ws.Activate
With cbo
.Width = 15
.Height = 15
End With
Next
Else
ws.Visible = IIf((id = 3), -1, IIf(InStr(1, ws.Name, id) = 0, 0, -1))
End If
Next
thisWs.Activate 'to properly update checkbox visibility
End Sub
.
consolidateReport()
Public Sub consolidateReport(ByRef ws As Worksheet, Optional dt As Boolean = False)
Dim fRowR As Long, vSetID As Byte, vSetName As String
Dim lRow As Long, thisRow As Long, cb As Variant
vSetID = IIf(ws.Shapes("cbSet2_03").Visible, 2, 1)
vSetName = "Set" & vSetID
Set wsRep = ThisWorkbook.Worksheets(REPORT & vSetID)
fRowR = wsRep.Range("A" & wsRep.Rows.count).End(xlUp).Row
If Not ws Is Nothing Then
With ws
lRow = .Range("A" & .Rows.count).End(xlUp).Row
lRowR = fRowR + 1
With wsRep.Cells(lRowR, 1)
.Value2 = ws.name
.Interior.Color = vbYellow
If dt Then .Offset(0, 2) = Format(Now, "mmm dd yyyy, hh:mm AMPM")
End With
For Each cb In .Shapes
If InStr(1, cb.name, vSetName, 0) Then
If cb.OLEFormat.Object.Value = 1 Then
thisRow = cb.TopLeftCell.Row
If InStr(1, .Cells(thisRow, 1).Value2, EXCLUDE, 1) = 0 Then
lRowR = lRowR + 1
wsRep.Range("A" & lRowR & ":" & L_COL & lRowR).Value2 = _
.Range("A" & thisRow & ":" & L_COL & thisRow).Value2
End If
End If
End If
Next
If fRowR = lRowR - 1 Then
wsRep.Cells(lRowR, 1).EntireRow.Delete
lRowR = lRowR - 1
MsgBox "No checkboxes checked for sheet " & ws.name
End If
End With
End If
End Sub
.
The process starts with one file, expected to have 2 sets of checkboxes on each sheet (column 2):
cbSet1_01, cbSet1_02, cbSet1_03...
cbSet2_01, cbSet2_02, cbSet2_03...
as in this image
(check-box colors will be reset by code as long as they follow the naming convention above)
.
Generate two files, one for Set1, the other for Set2 by running Sub updateSet()
showSet 1 hides Set2 (Report_2 and all checkboxes, on all sheets) - Save File1
showSet 2 hides Set1 (Report_1 and all checkboxes, on all sheets) - Save File2
Distribute, then retrieve the updated files
Open File1 and run Sub consolidateAllSheets() to generate Report_1
Open File2 and run Sub consolidateAllSheets() to generate Report_2
Compare Report_1 to Report_2
Generate Set 2 for editing by running Sub updateSet()
showSet 3 shows Set1 and Set2 (all checkboxes, and both reports) - Save File3
Compare File1, File2, and File3

Resources