The problem with the error bars seems to be resolved, but now I am gettng a error 5. The error line is:
ActiveChart.SeriesCollection(1).ApplyDataLabels AutoText:=False, LegendKey:=False, ShowSeriesName:=False, ShowCategoryName:=False, ShowValue:=True, _
ShowPercentage:=False, ShowBubbleSize:=False
'resize chart
WS.ChartObjects(1).Width = 500
WS.ChartObjects(1).Height = chartmultipl * (rowcnt - 1 - minscale)
WS.ChartObjects(1).Left = chartleftpos
WS.ChartObjects(1).Top = 70
'Rescale values to positions in chart so that labels can be succesfully moved
minchar = ActiveChart.Axes(xlCategory).MinimumScale
maxchar = ActiveChart.Axes(xlCategory).MaximumScale
midchar = (maxchar + minchar) / 2
'datalabels
ActiveChart.SeriesCollection(1).ApplyDataLabels AutoText:=False, LegendKey:=False, ShowSeriesName:=False, ShowCategoryName:=False, ShowValue:=True, _
ShowPercentage:=False, ShowBubbleSize:=False
For i = 1 To rowcnt - 1
If WS.Cells(i + 1, labelcol) <> "" Then
With ActiveChart.SeriesCollection(1).Points(i).DataLabel
.Characters.Text = Left(WS.Cells(i + 1, labelcol).Value, 28)
.AutoScaleFont = False
With .Characters(Start:=1, Length:=100).Font
.Name = "Arial"
If WS.Cells(i + 1, labelcol).Font.Italic = True Then
.FontStyle = "Italic"
ElseIf WS.Cells(i + 1, labelcol).Font.Bold = True Or Not ptype Then
.FontStyle = "Bold"
Else
.FontStyle = "Normal"
End If
.Size = labelsize
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ColorIndex = xlAutomatic
End With
'move labels wherever there is enough space to display them or to the beginning of the graph
If ptype Then
textsize = Application.WorksheetFunction.Min(Len(WS.Cells(i + 1, labelcol).Value), 28)
If WS.Cells(i + 1, int1).Value <= midchar Then
.Left = 15 + Round(ActiveChart.PlotArea.Width * (WS.Cells(i + 1, 6).Value - minchar) / (maxchar - minchar))
Else
.Left = -textsize * 3 + Round(ActiveChart.PlotArea.Width * (WS.Cells(i + 1, 5).Value - minchar) / (maxchar - minchar))
End If
Else
.Left = 20
End If
End With
End If
Next i
'if it's an outcome graph use set square sizes, if a final MA graph use study weights
If Not ptype Then
For i = 1 To resultcount
With ActiveChart.SeriesCollection(1).Points(i)
.MarkerSize = Round(sqsize(i), 0)
End With
Next i
End If
'send chart to back for future merging
WS.ChartObjects(1).SendToBack
'ActiveChart.ChartArea.Select
'Selection.ShapeRange.ZOrder msoSendToBack
'deselect graph so that I can add the rest of the shapes but first save things that are needed
minsc = ActiveChart.Axes(xlCategory).MinimumScale
maxsc = ActiveChart.Axes(xlCategory).MaximumScale
WS.Range("A1").Select
'if it is the final scatterplot add the diamonds
If Not ptype Then
Dim plarealeft, plarearight As Double
Dim dheight, incrh As Double
Dim origleft, origlength, transleft As Double
Dim diampos, diamlength As Double
Dim grtop As Double
'left and right edge of plot area in pixels
plarealeft = 371
plarearight = 827
'diamond statistics
dheight = 10
'vertical alignment of diamonds - increment from one to another
incrh = WS.ChartObjects(1).Height / ((rowcnt - 1) - minscale + 2)
'top of the graph
grtop = WS.ChartObjects(1).Top
'get all info in tables so that I can use in loops
mu(1) = fe_mu
mu(2) = dl_mu
mu(3) = ml_mu
mu(4) = pl_mu
mu(5) = T_mu
mvar(1) = fe_var
mvar(2) = dl_var
mvar(3) = ml_var
mvar(4) = pl_var
mvar(5) = T_var
For i = 1 To 4
tmargin(i) = 1.96
Next i
tmargin(5) = Excel.WorksheetFunction.TInv(0.05, resultcount - 1)
tlabel(1) = "FE"
tlabel(2) = "DL"
tlabel(3) = "ML"
tlabel(4) = "PL"
tlabel(5) = "T"
'go through all 5 diamonds
For i = 1 To 5
'original length and far left position
origleft = mu(i) - tmargin(i) * (mvar(i) ^ (1 / 2))
origlength = 2 * tmargin(i) * (mvar(i) ^ (1 / 2))
'transform to [0,1] scale
transleft = (origleft - minsc) / (maxsc - minsc)
'transform to points
diampos = plarealeft + (plarearight - plarealeft) * transleft + 1
diamlength = (plarearight - plarealeft) * origlength / (maxsc - minsc)
ActiveSheet.Shapes.AddShape(msoShapeDiamond, diampos, grtop + (rowcnt - 1.5 + i + 1) * incrh - dheight / 2, diamlength, dheight).Select
Selection.ShapeRange.Fill.ForeColor.RGB = RGB(0, 0, 0)
ActiveSheet.Shapes.AddTextbox(msoTextOrientationHorizontal, diampos + diamlength + 10, grtop + (rowcnt - 1.5 + i + 1) * incrh - dheight / 2, 20, 12).Select
Selection.Characters.Text = tlabel(i)
With Selection.ShapeRange
.Fill.Visible = msoFalse
.Line.Visible = msoFalse
End With
With Selection.Font
.Name = "Arial"
.FontStyle = "Bold"
.Size = 9
End With
Next i
End If
'add text files with study information
If ptype Then
tboxend = rowcnt * 10
tboxstep = (tboxend - 80) / (rowcnt - 2)
For i = 2 To rowcnt
If (WS.Cells(i, 1).Value <> "" And WS.Cells(i - 1, 1).Value = "") Or i = 2 Then
'find how many outcomes there are in each study to better align the text boxes
j = i
Do
j = j + 1
Loop Until WS.Cells(j, 1).Value = ""
cntr = j - i
'create textbox
tboxpos = tboxend - (i - 2) * tboxstep - (cntr - 1) * tboxstep / 2
ActiveSheet.Shapes.AddTextbox(msoTextOrientationHorizontal, 500, tboxpos, 60, 25).Select
Selection.Characters.Text = WS.Cells(i, 1).Value
With Selection.ShapeRange
.Fill.Visible = msoFalse
.Line.Visible = msoFalse
End With
With Selection.Font
.Name = "Arial"
.FontStyle = "Bold"
.Size = 10
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ColorIndex = xlAutomatic
End With
End If
Next i
End If
'create a list with all the shapes that need to be selected and group them
j = 0
For Each Sh In WS.Shapes
If Not Left(Sh.Name, 7) = "Comment" Then
j = j + 1
ReDim Preserve sharray(j)
sharray(j) = Sh.Name
End If
Next Sh
WS.Shapes.Range(sharray).Group
'deselect shape
WS.Range("A1").Select
Application.ScreenUpdating = True
End Sub
First thing to do, to help track down the error is to define all your variables properly.
Example: your first line
Dim rowcnt, textsize, cntr, labeltop As Integer
is actually the same as this:
Dim rowcnt as Variant
Dim textsize as Variant
dim cntr as Variant
dim labeltop As Integer
doing this may bring up other errors that can help you track down what is causing the line to fail
Declare Option Explicit at the top of your code, it will help you write better code by forcing you to declare all variables and help you identify bugs more easily.
This is probably causing your Invalid Call or Argument error:
'get the last row of data
rowcnt = LASTINCOLUMN2(6, k)
Unless you have a custom function called LASTINCOLUMN2 that you didn't post?
To get the last row use:
rowcnt = WS.Range("B" & Rows.Count).End(xlUp).Row
Declare rowcnt as Long not an integer.
You need to define:
ptype
resultcount
vareffects
Edit: I am still running through your code and identifying many unidentified subs/functions. Is there a second part to the code?
Related
' Set wrdTable1 = objDoc.Tables.Add(objDoc.Range, 20, 2)
Set wrdTable1 = objDoc.Tables.Add(Range:=objWord.Selection.Range, NumRows:=20, NumColumns:=2, _
DefaulttableBehavior:=wdWord9TableBehavior, AutoFitBehavior:=wdAutoFitFixed)
wrdTable1.Borders.Enable = False
With wrdTable1.Rows(1)
.Cells(1).Range.Text = "Tele: ####"
.Cells(1).Range.ParagraphFormat.Alignment = wdAlignParagraphLeft
.Cells(2).Range.Text = "!##########"
.Cells(2).Range.ParagraphFormat.Alignment = wdAlignParagraphLeft
End With
wrdTable1.Rows(2).Cells(2).Range.Text = "PIN- 9#####"
wrdTable1.Rows(3).Cells(2).Range.Text = "##########"
wrdTable1.Rows(20).Cells.Merge
wrdTable1.Rows(20).Cells(1).Range.Text = "2. It is under ref :-"
wrdTable1.Rows(20).Cells(1).Range.ParagraphFormat.Alignment = wdAlignParagraphJustify
wrdTable1.Range.InsertParagraphAfter
Set wrdTable2 = objDoc.Tables.Add(wrdTable1.Range.Next, ntotalRecords, ntotalColumns)
Dim intRow As Integer
Dim intCol As Integer
With wrdTable2
intCtr = 1: intRow = 1
While (Sheets("SummaryDVBan").Cells(intCtr, 11).FormulaR1C1 <> "")
For intCol = 1 To ntotalColumns
.cell(intRow, intCol).Range.InsertAfter Sheets("SummaryDVBan").Cells(intCtr, intCol + 10).FormulaR1C1
Next intCol
intCtr = intCtr + 1
intRow = intRow + 1
Wend
.Columns(1).SetWidth 40, wdAdjustFirstColumn
.Columns(2).SetWidth 120, wdAdjustFirstColumn
.Columns(3).SetWidth 60, wdAdjustFirstColumn
.Columns(4).SetWidth 90, wdAdjustFirstColumn
.Columns(5).SetWidth 65, wdAdjustFirstColumn
.Columns(6).SetWidth 60, wdAdjustFirstColumn
.Columns(7).SetWidth 90, wdAdjustFirstColumn
.Style = "Table Grid"
.Borders.Enable = True
.Rows(1).Range.ParagraphFormat.Alignment = wdAlignParagraphCenter
.Rows(1).Range.Bold = True
.Rows(1).HeadingFormat = True
.Range.ParagraphFormat.Alignment = wdAlignParagraphJustify
.Borders.InsideLineStyle = wdLineStyleSingle
End With
wrdTable2.Range.InsertParagraphAfter
Set wrdTable3 = objDoc.Tables.Add(wrdTable2.Range.Next, 7, 4) ' insert table 3
wrdTable3.Borders.Enable = False
w = wrdTable3.Rows(1).Cells(1).Width * 4
w1 = w * 0.26
For X = 1 To 7
With wrdTable3.Rows(X)
.Cells(1).Width = w1
.Cells(2).Width = w1
.Cells(3).Width = w1
.Cells(4).Width = w1
.Height = 16
End With
Next X
wrdTable3.Rows(1).Cells.Merge
wrdTable3.Rows(1).Cells(1).Range.Text = "3. The confirmation at the earliest pl."
wrdTable3.Rows(1).Cells(1).Range.ParagraphFormat.Alignment = wdAlignParagraphJustify
wrdTable3.Rows(1).Cells(1).Range.ParagraphFormat.LineSpacingRule = wdLineSpaceAtLeast
wrdTable3.Rows(1).Cells(1).Range.ParagraphFormat.LineSpacing = 18
With objDoc.Sections(1).Headers(wdHeaderFooterPrimary).Range
.Text = "REQUEST REMINDER"
.ParagraphFormat.Alignment = wdAlignParagraphCenter
.Font.Bold = True
.Font.Name = "Arial"
.Font.Size = 12
.Font.Underline = wdUnderlineSingle
.InsertParagraphAfter
.ParagraphFormat.SpaceAfter = 12 ' twice the font size for 1 "blank line"
End With
End Sub
the above code adds three tables into the word document however, the output document is showing the first two tables as joint. Also the when the table2 is spilling over the next page the output word document has the first table being repeated again on the second page. the first table is also being shown with gridlines despite the gridlines set as false.
In the output first and third table is to be without gridlines. first and second table needs to have space between them. the second table is with gridlines. and the first table is not required to repeat itself
Use the document to insert the paragraph and a section break, and also use the document to reference the range to add the next table
objDoc.Paragraphs.Last.Range.InsertParagraphAfter
objDoc.Paragraphs.Last.Range.InsertBreak Type:=wdSectionBreakContinuous
Dim rng As Range
Set rng = objDoc.Range(objDoc.Paragraphs.Last.Range.Start, objDoc.Paragraphs.Last.Range.End)
Set wrdTable2 = objDoc.Tables.Add(rng, ntotalrecords, ntotalColumns)
Dim intRow As Integer
Dim intCol As Integer
I'm working on a sub where, after doing a whole bunch of other things, it just selects all the cells in the active sheet and sets the rows to auto-fit height. For some reason it won't work! I've tried to the autofit row height command in various different places, but it seems that so long as it's part of the larger sub, or called within it, it won't work. However, if I write a separate sub that is run separately, it will work just fine. Does anyone know why this could be?
Below is the sub where it's misbehaving, plus the other sub I made that I can run separately. Any suggestions on how to make this all more efficient is also very welcome! (I also kind of learned coding in the wild, so I don't really know best practices...)
Option Explicit
Sub WriteToIndex(ByRef rowsArray() As Variant, ByRef Indexes() As Integer, ByRef HeaderNames() As String, myTable As ListObject, sheetName As String)
Debug.Print sheetName
Sheets(sheetName).Activate
Dim i, j As Variant
Dim count As Integer
'If no rows, no write
If (Not Not rowsArray) <> 0 Then
Else:
'If the index is longer than 5000 rows, this will need to be updated!
Range("B4:L5000").Clear
MsgBox "Sheet " & sheetName & " was not populated because there is nothing attributed to it"
Exit Sub
End If
'If nothing in Int/Ext section, no write
count = 0
For i = LBound(rowsArray) To UBound(rowsArray)
For j = LBound(Indexes) To UBound(Indexes)
If myTable.DataBodyRange(rowsArray(i), Indexes(j)).Value = "n" Then count = count + 1
Next
Next
If count = 0 Then
'If the index is longer than 5000 rows, this will need to be updated!
Range("B4:L5000").Clear
MsgBox "Sheet " & sheetName & " was not populated because there is nothing attributed to it"
Exit Sub
End If
Sheets(sheetName).Activate
'Pulls desired index fonts and sizes from Settings tab
Dim IndexFont As String, HeaderFSize, BodyFSize As Integer, HeaderBold As Boolean
IndexFont = Worksheets("Settings").Cells(10, 11).Value
HeaderFSize = Worksheets("Settings").Cells(11, 11).Value
HeaderBold = Worksheets("Settings").Cells(12, 11).Value
BodyFSize = Worksheets("Settings").Cells(13, 11).Value
'Remove headers from array if there are no items for the index
Dim loopno, pos, zeroloops(), zeroloopstart As Integer
count = 0
zeroloopstart = 0
loopno = 1
ReDim Preserve zeroloops(zeroloopstart)
For i = LBound(Indexes) To UBound(Indexes)
For j = LBound(rowsArray) To UBound(rowsArray)
If myTable.DataBodyRange(rowsArray(j), Indexes(i)).Text = "n" Then count = count + 1
Next
If count = 0 Then
pos = loopno - 1
ReDim Preserve zeroloops(0 To zeroloopstart)
zeroloops(zeroloopstart) = pos
zeroloopstart = zeroloopstart + 1
End If
count = 0
loopno = loopno + 1
Next
'If a header is in the zeroloops array, it gets removed from the Header array
If IsEmpty(zeroloops(0)) Then
Debug.Print "Empty"
Else
For i = LBound(zeroloops) To UBound(zeroloops)
For j = zeroloops(i) To UBound(Indexes) - 1
Indexes(j) = Indexes(j + 1)
Next j
For j = zeroloops(i) To UBound(HeaderNames) - 1
HeaderNames(j) = HeaderNames(j + 1)
Next j
For j = LBound(zeroloops) To UBound(zeroloops)
zeroloops(j) = zeroloops(j) - 1
Next j
Debug.Print
ReDim Preserve Indexes(0 To (UBound(Indexes) - 1))
ReDim Preserve HeaderNames(0 To (UBound(HeaderNames) - 1))
Next i
End If
'If the index is longer than 5000 rows, this will need to be updated!
Range("B4:L5000").Clear
'Apply preferred font to entire sheet
Cells.Font.Name = IndexFont
Dim KeyIDCol, DescCol, SourceCol, ProductCol, CatCol, ColorCol, FinishCol, SizeCol, ContactCol, SpecCol, RemarkCol As Integer
'Index for each value to report
'If additional column needs to be reported, add the line and swap out the name in the Listcolumns definition
KeyIDCol = Worksheets("Database").ListObjects("Database").ListColumns("KEYNOTE #").Index
DescCol = Worksheets("Database").ListObjects("Database").ListColumns("KEYNOTE DESCRIPTION").Index
SourceCol = Worksheets("Database").ListObjects("Database").ListColumns("SOURCE").Index
ProductCol = Worksheets("Database").ListObjects("Database").ListColumns("PRODUCT").Index
CatCol = Worksheets("Database").ListObjects("Database").ListColumns("CAT. NO.").Index
ColorCol = Worksheets("Database").ListObjects("Database").ListColumns("COLOR").Index
FinishCol = Worksheets("Database").ListObjects("Database").ListColumns("FINISH").Index
SizeCol = Worksheets("Database").ListObjects("Database").ListColumns("SIZE").Index
ContactCol = Worksheets("Database").ListObjects("Database").ListColumns("CONTACT").Index
SpecCol = Worksheets("Database").ListObjects("Database").ListColumns("SECTION #").Index
RemarkCol = Worksheets("Database").ListObjects("Database").ListColumns("REMARKS").Index
'Definitions for write loop
Dim NextWriteRow, HeaderListIndex As Integer
Dim ArrayItem As Variant
Dim WriteStartCell, Cell As Range
NextWriteRow = 4
HeaderListIndex = 0
i = 1 ' for moving to the next KeyID
j = 0 ' start counter for steps
Set WriteStartCell = Cells(NextWriteRow, 2)
Dim k As Variant
'Outer loop puts in headers
For Each ArrayItem In Indexes
With Cells(NextWriteRow, 2)
.Value = HeaderNames(HeaderListIndex)
.VerticalAlignment = xlBottom
.Font.Size = HeaderFSize
.Font.Bold = HeaderBold
End With
HeaderListIndex = HeaderListIndex + 1
'Second loop puts in KeynoteID with all pertinent info
For k = LBound(rowsArray) To UBound(rowsArray)
If myTable.DataBodyRange(rowsArray(k), ArrayItem).Value = "n" Then
With WriteStartCell
.Offset(i, 0).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, KeyIDCol - ArrayItem).Value
.Offset(i, 1).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, DescCol - ArrayItem).Value
.Offset(i, 2).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, SourceCol - ArrayItem).Value
.Offset(i, 3).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, ProductCol - ArrayItem).Value
.Offset(i, 4).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, CatCol - ArrayItem).Value
.Offset(i, 5).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, ColorCol - ArrayItem).Value
.Offset(i, 6).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, FinishCol - ArrayItem).Value
.Offset(i, 7).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, SizeCol - ArrayItem).Value
.Offset(i, 8).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, ContactCol - ArrayItem).Value
With .Offset(i, 9)
.NumberFormat = "000000"
.HorizontalAlignment = xlCenter
.Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, SpecCol - ArrayItem).Value
End With
.Offset(i, 10).Value = myTable.DataBodyRange(rowsArray(k), ArrayItem).Offset(, RemarkCol - ArrayItem).Value
End With
With Range(WriteStartCell.Offset(i, 0), WriteStartCell.Offset(i, 10))
.VerticalAlignment = xlTop
.WrapText = True
.Borders(xlDiagonalDown).LineStyle = xlNone
.Borders(xlDiagonalUp).LineStyle = xlNone
.Font.Size = BodyFSize
With .Borders
.LineStyle = xlContinuous
.ColorIndex = xlAutomatic
.TintAndShade = 0
.Weight = xlThin
End With
End With
i = i + 1
j = j + 1
End If
Next
j = j + 2
NextWriteRow = NextWriteRow + j
i = i + 2
j = 0
Next
'This is the autofit that won't work for some reason
Cells.Rows.Autofit
Debug.Print "Works"
End Sub
'---
Sub AutofitRowHeight()
Dim sheetnames() As String
ReDim sheetnames(0 To 17)
sheetnames(0) = "SF-ALL-I"
sheetnames(1) = "SF-ALL-E"
sheetnames(2) = "SF-H-I"
sheetnames(3) = "SF-H-E"
sheetnames(4) = "SF-CUP-I"
sheetnames(5) = "SF-CUP-E"
sheetnames(6) = "SF-GB-I"
sheetnames(7) = "SF-GB-E"
sheetnames(8) = "LM-ALL-I"
sheetnames(9) = "LM-ALL-E"
sheetnames(10) = "LM-H-I"
sheetnames(11) = "LM-H-E"
sheetnames(12) = "LM-CC-I"
sheetnames(13) = "LM-CC-E"
sheetnames(14) = "LM-SCC-I"
sheetnames(15) = "LM-SCC-E"
sheetnames(16) = "LM-GB-I"
sheetnames(17) = "LM-GB-E"
Dim i As Variant
For i = LBound(sheetnames) To UBound(sheetnames)
Sheets(sheetnames(i)).Activate
Cells.Rows.AutoFit
Next
Sheets("Database").Activate
Cells(1, 1).Select
End Sub
this code not select the print area OF several pages thanks where the total of pages into the array Addresss
Sub PagePrintArea()
Dim Addresss(1 To 32) As Variant
Dim P As Long
For P = 1 To UBound(Addresss)
r = (((Application.Ceiling(P, 2) / 2) - 1) * 39) + 1
c = (((P - 1) Mod 2) * 11) + 1
Addresss(P) = Cells(r, c).Resize(38, 10).Address
Next
With ActiveSheet.PageSetup
.PrintArea = ""
.PrintArea = Addresss
.Zoom = False
.FitToPagesWide = 1
.FitToPagesTall = 1
End With
End Sub
This is the first time I've done something this complicated in UserForms using VBA. I'm not sure if this is even the correct way to do this or not.
The layout of the form
The form as a MultiPage with 5 pages.
Each Page has 5 survey questions with 4 option buttons per question (Low, Medium, High, Don't know)
4 option buttons per question are grouped
Low option button should have a value of 1, Medium 3, and High 5. Don't know should be 0 but if more
Then values from these option buttons are averaged for each page. e.g. Page 1 has 5 questions, the user selects 1. Low, 2. Low, 3. Medium, 4. Don't know, 5. High. Then the average for this page should be 2. And this average is the only one I care about and needs to be save in a sheet range (which I can do later). I don't need to store other responses.
Because the pages in the Multipage can change in the future, I created a loop to create the page dynamically based on items added in the table in a separate sheet.
Also, because questions can be added or removed for each page, I also created the labels for the question and radio buttons using the loop.
What I don't know how to do next
The layout is complete and works. What I need to do now is the following:
Make the option buttons mandatory, i.e. the user must select one option button per group.
Get the value of the option buttons for each group and calculate the average for each page
I don't know yet how to get the value of the option button when it's used in the loop. I just learnt that VBA is an event driven program, so now I'm concerned whether I can salvage the time and effort I put in creating the form using loop the following way.
In this case, I also tried to create a dictionary, store the values. But I need to store this in a collection?
Private Sub CreateAssessmentForm()
'Range variable for data from table
Dim rngTable As Range
Dim itemTable As Range
'UI forms and multipage
'Dim multiPage As MSForms.multiPage
'Labels
Dim itemLblBackground As Object
Dim itemLbl As Object
Dim lowRatingLabelBg As Object
Dim medRatingLabelBg As Object
Dim highRatingLabelBg As Object
Dim unknownRatingLabelBg As Object
Dim lowRatingLabel As Object
Dim medRatingLabel As Object
Dim highRatingLabel As Object
Dim unknownRatingLabel As Object
'Misc
Dim lblName As String
Dim lblBackground As String
Dim JobGrade As Integer
Dim itemTopPosition As Integer
Dim altBgClr As Long
'Leader Role table ID to keep track of for the Multipage tabs
Dim activeLeaderRoleId As String
'Radio buttons
Dim lowRadioButton As MSForms.OptionButton
Dim medRadioButton As MSForms.OptionButton
Dim highRadioButton As MSForms.OptionButton
Dim unknownRadioButton As MSForms.OptionButton
Set RadioDictionary = New Dictionary
'================================================================
Me.drName = Sheets("var").Range("Y2").Value
'Declaration
JobGrade = Sheets("var").Range("z2").Value
Me.dateLabel.Caption = DateValue(Now)
Me.ManagerView_SubmitAssessment.Enabled = True
'Define source range, referring to the table data range
Set rngTable = ThisWorkbook.Worksheets("LeaderRoles2").Range("leaderRoleTable2")
Set itemTable = ThisWorkbook.Worksheets("Items").Range("itemTable")
'Create a tabbed multipage to add the leader role information
Set multiPage = AssessmentForm.DriverTabs
multiPage.Font.Bold = False
multiPage.Font.Name = "Verdana"
multiPage.Font.Size = 9
multiPage.Style = fmSpecialEffectFlat
multiPage.ForeColor = RGB(0, 40, 85)
'Total page counts that may already exist
PageCount = multiPage.Pages.Count
Dim itemLabelWidth As Integer
itemLabelWidth = 325
'rngTable rows have different count than rngTable.Count if multiple columns are selected
For i = 1 To rngTable.Rows.Count
itemTopPosition = (multiPage.Height - (32 * 5)) / 2
'get leader role id
activeLeaderRoleId = rngTable.Item(i, 1).Value
If (i <= PageCount) = True Then
multiPage.Pages(i - 1).Caption = rngTable.Item(i, 2).Value
Else
multiPage.Pages.Add
Me.DriverTabs.Pages(i - 1).Name = "Page" & i
Me.DriverTabs.Pages(i - 1).Caption = rngTable.Item(i, 2).Value
End If
'Tab height
multiPage.TabFixedHeight = 25
lblName = "lr" & i & "Item" & j
lblBackground = "lblBkgrnd" & i & j
'Multipage page background
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.BackColor = RGB(255, 255, 255)
.Width = multiPage.Width
.Height = multiPage.Height
.Top = 0
.Left = 0
End With
'For alternating the background in the item labels
Dim k As Integer
k = 1
'Loop through item table to add items to the multipage page
For j = 1 To itemTable.Rows.Count
If itemTable.Item(j, 2).Value = activeLeaderRoleId And itemTable.Item(j, 3) = JobGrade Then
Set itemLblBackground = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1", lblBackground)
Set itemLbl = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1", lblName)
altBgClr = RGB(250, 250, 250)
If (k Mod 2 = 0) Then altBgClr = RGB(255, 255, 255)
'Alternate background
With itemLblBackground
.Caption = ""
.BorderStyle = fmBorderStyleNone
.BackColor = altBgClr
.Left = 0
.Width = multiPage.Width
.Height = 35
.Top = itemTopPosition
End With
'display items
With itemLbl
.Caption = itemTable.Item(j, 4).Value
.BackStyle = fmBackStyleTransparent
.Font.Name = "Verdana"
.AutoSize = True
.Font.Size = 10
.Left = 6
.Width = itemLabelWidth
.Height = 30
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2) 'itemLblBackground.Top
End With
'==============================================================================================================
'
' LOW RADIO BUTTON
'
'==============================================================================================================
'Low radio button
Dim lowLabelName As String
Dim medLabelName As String
Dim highLabelName As String
Dim unknownLabelName As String
lowLabelName = "lowRadioGroup" & i & "_" & j
medLabelName = "medRadioGroup" & i & "_" & j
highLabelName = "highRadioGroup" & i & "_" & j
unknownLabelName = "unknownRadioGroup" & i & "_" & j
Set lowRadioButton = multiPage.Pages(i - 1).Controls.Add("Forms.OptionButton.1", lowLabelName)
With lowRadioButton
.Width = 20
.BackStyle = fmBackStyleTransparent
.Left = itemLabelWidth + 40
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2)
.GroupName = "RatingButton" & j
End With
RadioDictionary("Name") = lowLabelName
RadioDictionary("GroupName") = lowRadioButton.GroupName
RadioDictionary("Value") = lowRadioButton.Value
'==============================================================================================================
'
' MEDIUM RADIO BUTTON
'
'==============================================================================================================
Set medRadioButton = multiPage.Pages(i - 1).Controls.Add("Forms.OptionButton.1", medLabelName)
With medRadioButton
.Width = 20
.BackStyle = fmBackStyleTransparent
.Left = lowRadioButton.Left + lowRadioButton.Width + 40
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2)
.GroupName = "RatingButton" & j
End With
RadioDictionary("Name") = medLabelName
RadioDictionary("GroupName") = medRadioButton.GroupName
RadioDictionary("Value") = medRadioButton.Value
'==============================================================================================================
'
' HIGH RADIO BUTTON
'
'==============================================================================================================
Set highRadioButton = multiPage.Pages(i - 1).Controls.Add("Forms.OptionButton.1", highLabelName)
With highRadioButton
.Width = 20
.BackStyle = fmBackStyleTransparent
.Left = medRadioButton.Left + medRadioButton.Width + 40
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2)
.GroupName = "RatingButton" & j
End With
RadioDictionary("Name") = highLabelName
RadioDictionary("GroupName") = highRadioButton.GroupName
RadioDictionary("Value") = highRadioButton.Value
'==============================================================================================================
'
' DON'T KNOW RADIO BUTTON
'
'==============================================================================================================
Set unknownRadioButton = multiPage.Pages(i - 1).Controls.Add("Forms.OptionButton.1", unknownLabelName)
With unknownRadioButton
.Width = 22
.BackStyle = fmBackStyleTransparent
.Left = highRadioButton.Left + highRadioButton.Width + 45
.Top = (itemLblBackground.Top + (itemLblBackground.Height - itemLbl.Height) / 2)
.GroupName = "RatingButton" & j
End With
RadioDictionary("Name") = unknownLabelName
RadioDictionary("GroupName") = unknownRadioButton.GroupName
RadioDictionary("Value") = unknownRadioButton.Value
itemTopPosition = itemTopPosition + itemLblBackground.Height
k = k + 1
End If
Next j 'End item table range
'==============================================================================================================
'
' DISPLAY RATING OPTIONS AND LINE BOUNDARIES
'
'==============================================================================================================
'Adding a line in the headers
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = multiPage.Width - 10
.Height = 1
.Top = multiPage.TabFixedHeight + 16
.Left = multiPage.Left - 10
End With
'Adding a line between items and control
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = 1
.Height = multiPage.Height - multiPage.TabFixedHeight
.Top = 10
.Left = itemLabelWidth + 10
End With
'==============================================================================================================
'
' LOW
'
'==============================================================================================================
Set lowRatingLabelBg = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
'Low rating instruction background
With lowRatingLabelBg
.BackColor = RGB(244, 67, 54)
.Left = itemLabelWidth + 20
.Top = 12
.Width = 50
.Height = 25
End With
'Low rating instruction label
Set lowRatingLabel = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
With lowRatingLabel
.Caption = "LOW"
.BackColor = RGB(244, 67, 54)
.Width = 24
.Height = 12
.Left = lowRatingLabelBg.Left + (lowRatingLabelBg.Width - lowRatingLabel.Width) / 2
.Top = lowRatingLabelBg.Top + (lowRatingLabelBg.Height - lowRatingLabel.Height) / 2
.ForeColor = RGB(255, 255, 255)
End With
'Adding a line between items and control
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = 1
.Height = multiPage.Height - multiPage.TabFixedHeight
.Top = 10
.Left = lowRatingLabelBg.Width + lowRatingLabelBg.Left + 5
End With
'==============================================================================================================
'
' MEDIUM
'
'==============================================================================================================
Set medRatingLabelBg = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
'Med rating instruction
With medRatingLabelBg
.BackColor = RGB(255, 193, 7)
.Left = lowRatingLabelBg.Left + lowRatingLabelBg.Width + 10
.Top = 12
.Width = 50
.Height = 25
End With
'Low rating instruction label
Set medRatingLabel = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
With medRatingLabel
.Caption = "MEDIUM"
.BackStyle = fmBackStyleTransparent
.Width = 42
.Height = 12
.Left = medRatingLabelBg.Left + (medRatingLabelBg.Width - medRatingLabel.Width) / 2
.Top = medRatingLabelBg.Top + (medRatingLabelBg.Height - medRatingLabel.Height) / 2
.ForeColor = RGB(9, 9, 9)
End With
'Adding a line between items and control
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = 1
.Height = multiPage.Height - multiPage.TabFixedHeight
.Top = 10
.Left = medRatingLabelBg.Width + medRatingLabelBg.Left + 5
End With
'==============================================================================================================
'
' HIGH
'
'==============================================================================================================
Set highRatingLabelBg = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
'Med rating instruction
With highRatingLabelBg
.BackColor = RGB(46, 125, 50)
.Left = medRatingLabelBg.Left + medRatingLabelBg.Width + 10
.Top = 12
.Width = 50
.Height = 25
End With
Set highRatingLabel = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
With highRatingLabel
.Caption = "HIGH"
.BackStyle = fmBackStyleTransparent
.Width = 26
.Height = 12
.Left = highRatingLabelBg.Left + (highRatingLabelBg.Width - highRatingLabel.Width) / 2
.Top = highRatingLabelBg.Top + (highRatingLabelBg.Height - highRatingLabel.Height) / 2
.ForeColor = RGB(255, 255, 255)
End With
'Adding a line between items and control
With multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
.Width = 1
.Height = multiPage.Height - multiPage.TabFixedHeight
.Top = 10
.Left = highRatingLabelBg.Width + highRatingLabelBg.Left + 5
End With
'==============================================================================================================
'
' Don't Know
'
'==============================================================================================================
Set unknownRatingLabelBg = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
'Dont know rating instruction
With unknownRatingLabelBg
.BackColor = RGB(148, 176, 182)
.Left = highRatingLabelBg.Left + highRatingLabelBg.Width + 10
.Top = 12
.Width = 65
.Height = 25
End With
Set unknownRatingLabel = multiPage.Pages(i - 1).Controls.Add("Forms.Label.1")
With unknownRatingLabel
.Caption = "DON'T KNOW"
.BackStyle = fmBackStyleTransparent
.Width = 80
.Height = 12
.Left = unknownRatingLabelBg.Left + 9 + (unknownRatingLabelBg.Width - unknownRatingLabel.Width) / 2
.Top = unknownRatingLabelBg.Top + (unknownRatingLabelBg.Height - unknownRatingLabel.Height) / 2
.ForeColor = RGB(255, 255, 255)
End With
Next i 'End leader role table range
'Finally, get the actual page count
PageCount = multiPage.Pages.Count
End Sub
In regards of what I tried to suggest (in comments) I prepared a simple event wrapper class, which must be built in this way:
Insert a class module, name it optBClass and paste the next code inside it:
Option Explicit
Public WithEvents optEvent As MSForms.OptionButton
Private Sub optEvent_Change()
If optEvent.Name = "Opt1" Then
If optEvent.Value = True Then
testOptCreate.boolOpt1 = True
testOptCreate.boolOpt2 = False: testOptCreate.boolOpt3 = False
Else
testOptCreate.boolOpt1 = False
testOptCreate.boolOpt2 = False: testOptCreate.boolOpt3 = False
End If
ElseIf optEvent.Name = "Opt2" Then
If optEvent.Value = True Then
testOptCreate.boolOpt2 = True
testOptCreate.boolOpt1 = False: testOptCreate.boolOpt3 = False
Else
testOptCreate.boolOpt1 = False
testOptCreate.boolOpt2 = False: testOptCreate.boolOpt3 = False
End If
ElseIf optEvent.Name = "Opt3" Then
If optEvent.Value = True Then
testOptCreate.boolOpt3 = True
testOptCreate.boolOpt1 = False: testOptCreate.boolOpt2 = False
Else
testOptCreate.boolOpt1 = False
testOptCreate.boolOpt2 = False: testOptCreate.boolOpt3 = False
End If
End If
MsgBox optEvent.Name & " - " & optEvent.Value & vbCrLf & _
"boolOpt1 = " & testOptCreate.boolOpt1 & vbCrLf & _
"boolOpt2 = " & testOptCreate.boolOpt2 & vbCrLf & _
"boolOpt3 = " & testOptCreate.boolOpt3
End Sub
On top of the the form (module) you want to create option buttons, on the fly (testOptCreate in my exammple), please create the next variable (in the declarations part):
Option Explicit
Private optBColl As New Collection
Private OptionB() As New optBClass
Public boolOpt1 As Boolean, boolOpt2 As Boolean, boolOpt3 As Boolean
Create a button (btCreateOptB) and use this code for its Click event:
Private Sub btCreateOptB_Click()
Dim optCount As Long, theOptB As control, i As Long
optCount = 3
ReDim OptionB(0 To optCount)
For i = 1 To optCount
Set theOptB = Me.Controls.aDD("Forms.OptionButton.1", "Opt" & i, True)
With theOptB
.height = 17
.Caption = "Opt" & i
.left = 50 * i
End With
optBColl.aDD theOptB, theOptB.Name
Set OptionB(i).optEvent = theOptB
Next i
End Sub
Show the form and press btCreateOptB button!
Check each newly created option buttons. When first of them is clicked, the message box being shown display the clicked option button name, its value and the boolean variables associated to the group values.
Starting from the second option button click, the message will be shown twice. One time triggered by the previous option button change (its value becomes false) and second time referring to the last option button clicked.
Please, try understanding of its logic and try to apply it on your project.
If something not clear, do not hesitate to ask, even if I believe that it should be clear enough...
You can also use a Dictionary to automatically create boolean variables and use it to keep all of them and check when needed. Look, please at this test Sub:
Sub testDictionaryBooleanVar()
'it needs a reference to 'Microsoft Scripting Runtime`,
'or `dict` variable must be created `As Object` and create through `Set dict = CreateObject("scripting.dictionary")`
Dim it As Variant, dict As New Scripting.Dictionary, i As Long
With dict
For i = 1 To 10
.Item("boolOpt" & i) = False
Next i
End With
dict.Item("boolOpt2") = True: dict.Item("boolOpt5") = True
Debug.Print Join(dict.Items, "|")
Debug.Print dict("boolOpt2"), dict("boolOpt3")
End Sub
Presented this option in order to suggest a way to avoid manually creating boolean variables to be checked in the Option button Change event...
I'm trying to hide columns if their headings match a checkbox name. These ActiveX checkboxes have been created based on the column headings provided.
For iCol = colNum To totalColumns
Set colCheckbox = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CheckBox.1")
With colCheckbox
.Left = Cells(iCol + 2, 1).Left
.Top = Cells(iCol + 2, 1).Top
.Width = Cells(iCol + 2, 1).Width * 0.8
.Height = Cells(iCol + 2, 1).Height * 0.8
.Name = "cbx" & iCol
.Object.Caption = Cells(RowNum, iCol).Value
End With
Next iCol
When the checkboxes are selected / deselected the code below will find the column heading and hide the column.
Private Sub CheckBox1_Click()
Set matchingAddress = Rows("4").Find(CheckBox1.Caption, LookIn:=xlFormulas)
If matchingAddress Is Nothing Then
MsgBox ("Column Not Found")
Else
cellAddressSplit = Split(matchingAddress.Address, "$")
Columns(cellAddressSplit(1)).EntireColumn.Hidden = Not CheckBox1
End If
End Sub
I'm trying to move this code to a module, so that I can just pass the checkbox name (CheckBox1.Name) to the module function and manipulate the checkbox's visibility. I'm looking at 40 plus columns on the sheet and I want the same code in all Click methods. I'm trying to replace CheckBox1 with
Set cBox = ActiveSheet.CheckBoxes(Application.Caller)
or
Set cBox = ActiveSheet.Shapes(Application.Caller)
These are not working. Please provide directions. Should I be using forms instead of ActiveX checkboxes?
A sample error I get is "Unable to get checkboxes property of the worksheet class"
Sub CreateCheckBox()
colNum = 1
totalColumns = 3
RowNum = 8
For iCol = colNum To totalColumns
Set colCheckBox = ActiveSheet.CheckBoxes.Add(305.25, 158.25, 62.25, 17.25)
With colCheckBox
.Left = Cells(iCol + 2, 1).Left
.Top = Cells(iCol + 2, 1).Top
.Width = Cells(iCol + 2, 1).Width * 0.8
.Height = Cells(iCol + 2, 1).Height * 0.8
.Name = "cbx" & iCol
.Characters.Text = Cells(RowNum, iCol).Value
.OnAction = "HideColumn"
End With
Next
End Sub
Sub HideColumn()
Set cBox = ActiveSheet.CheckBoxes(Application.Caller)
Set matchingAddress = Rows(8).Find(cBox.Caption, LookIn:=xlFormulas)
If matchingAddress Is Nothing Then
MsgBox ("Column Not Found")
Else
If Columns(matchingAddress.Column).EntireColumn.Hidden = True Then
Columns(matchingAddress.Column).EntireColumn.Hidden = False
Else
Columns(matchingAddress.Column).EntireColumn.Hidden = True
End If
End If
End Sub