Modifying ActiveX controls through custom add-in in Excel - vba

I'm working on moving a worksheet into an add-in so I can make updates to the code without having to give new workbooks to everyone. The process has been fairly straightforward until I got to the area where add-in code needs to modify ActiveX controls present on the sheet.
The previous code I was using to modify these:
If Sheet1.Range(RowHighlightToggle.LinkedCell).Value = True Then
RowHighlightToggle.Caption = "Row Highlight - On"
HighlightStatus = 0
Else
RowHighlightToggle.Caption = "Row Highlight - Off"
HighlightStatus = 1
End If
RowHightlightToggle being the ActiveX control in question. I'm not sure how to refer to this button when coding inside the add-in. I've tried doing Sheet1.RowHighlightToggle.LinkedCell and that is giving me an error as well. I'm not using Sheet1 inside the add-in as I have a function to get codenames from the target workbook so Sheet1 is usually something like AWSheet1 but it is a Worksheet variable so that is not the issue either. I can read the linked cell value quite easy but I have no way of changing the button caption without somehow referring to the button inside the code.
This button will always be present in the workbook that this add-in is being made for, I have additional code to make sure the add-in is only visible in that workbook as well and hides itself for any others.
Is there a way to refer to the button through the add-in or possibly a way to link the caption to a cell so I can change the cell value to update the caption?

After a bit more research I found out I can refer to it by using OLEObjects, working code including the rest of the sub is below.
Sub RowHighlightToggle()
'-----Startup Code--------
With Application
.ScreenUpdating = False
.DisplayStatusBar = False
.DisplayAlerts = False
End With
'------------------------
Dim HighlightStatus As Long, AWSheet1 As Worksheet, ThisButton As Object
If TargetWorkbook Is Nothing Then Set TargetWorkbook = ActiveWorkbook
Set AWSheet1 = GetWsFromCodeName(TargetWorkbook, "Sheet1")
Set ThisButton = AWSheet1.OLEObjects("RowHighlightToggle")
Call Common_Functions.StartUnlock
If AWSheet1.Range(ThisButton.LinkedCell).Value = True Then
ThisButton.Object.Caption = "Row Highlight - On"
HighlightStatus = 0
Else
ThisButton.Object.Caption = "Row Highlight - Off"
HighlightStatus = 1
End If
Call Common_Functions.StartLock
If Worksheets.Count > 6 Then
Call Common_Functions.SheetArrayBuild(TargetWorkbook)
For i = LBound(SheetArray) To UBound(SheetArray)
Sheets(SheetArray(i, 1)).Range("Z1").Value = HighlightStatus
Next i
End If
'-----Finish Code--------
With Application
.ScreenUpdating = True
.DisplayStatusBar = True
.DisplayAlerts = True
.EnableEvents = True
End With
'------------------------
End Sub
And the function to get the worksheet from the workbook
Function GetWsFromCodeName(wb As Workbook, CodeName As String) As Excel.Worksheet
Dim ws As Excel.Worksheet
For Each ws In wb.Worksheets
If ws.CodeName = CodeName Then
Set GetWsFromCodeName = ws
Exit For
End If
Next ws
End Function

Assuming the control is on Sheet1, you should be able to use:
Sheet1.RowHightlightToggle.Caption = "Row Highlight - On"
But you can also get at the control using the shapes collection:
Sheet1.Shapes("RowHightlightToggle").DrawingObject.Object.Caption = "Row Highlight - On"
Or, with a more generic workbook variable:
Dim userWorkbook as Workbook
Set userWorkbook = Workbooks("UserData.xlsm")
userWorkbook.Worksheets("Foo").Shapes("RowHightlightToggle").DrawingObject.Object.Caption = "Row Highlight - On"

Related

Excel VBA - Export a copy of current workbook

The Task
I am working on a chart generator from a data sheet. As part of my spec, I need to be able to extract this chart into its separate workbook.
My Functions
This is the function I currently have:
Sub EWbtn()
'''Extract Worksheet Button Function
Dim OriginalWB As Workbook, NewCRCWB As Workbook
Set OriginalWB = ThisWorkbook
Set NewCRCWB = Workbooks.Add
OriginalWB.Sheets("Generator").Copy Before:=NewCRCWB.Sheets("Sheet1")
OriginalWB.Sheets("Module Part Number Tracker").Copy Before:=NewCRCWB.Sheets("Generator")
OriginalWB.Sheets("CRC").Copy Before:=NewCRCWB.Sheets("Module Part Number Tracker")
Application.DisplayAlerts = False
NewCRCWB.Worksheets("Generator").Visible = False
NewCRCWB.Worksheets("Module Part Number Tracker").Visible = False
NewCRCWB.Worksheets("Sheet1").Delete
Application.DisplayAlerts = True
End Sub
I copy through the 2 sheets from which the data for the chart is used, and make them hidden in the new workbook. The CRC sheet has quite a few macros that are run on the chart and can also be called via buttons on the chart. For example this function is for a button which hides 5 columns of data on the chart:
Public Function SHGSbtn()
'''Show Hides Gateway Stages Function
Dim wsCRC As Worksheet
Set wsCRC = Worksheets("CRC")
If wsCRC.Buttons("SHGateway").Caption = "Hide Gateway Stages" Then
Range(Cells(9, 9), Cells(9, 13)).EntireColumn.Hidden = True
wsCRC.Buttons("SHGateway").Caption = "Show Gateway Stages"
ElseIf wsCRC.Buttons("SHGateway").Caption = "Show Gateway Stages" Then
Range(Cells(9, 9), Cells(9, 13)).EntireColumn.Hidden = False
wsCRC.Buttons("SHGateway").Caption = "Hide Gateway Stages"
End If
End Function
My Issue
The workbook copies over with no errors, however when i try and use one of the buttons, it uses the code in the original workbook, even if its closed it will open up the original workbook. Anyone know why this is and how do I get around it?

Excel VBA - Copy Workbook into a new Workbook with the macros

So I have a worksheet that generates a chart type of thing using information on 2 other worksheets. On It I have an extract button which should copy the entire workbook into a new workbook whilst making the sheets where the data is pulled from invisible to the user. My issue is, the chart worksheet has other features which require macros to be run, for example buttons that hide some of it etc. The issue is I cannot find whether its actually possible to copy through macros from a workbook into the new copied workbook? Anyone have an answer to this and if so, how would you do this? Here is the code I currently have which copies the workbook into a new workbook:
Sub EWbtn()
Dim OriginalWB As Workbook, NewCRCWB As Workbook
Set OriginalWB = ThisWorkbook
Set NewCRCWB = Workbooks.Add
OriginalWB.Sheets("Generator").Copy Before:=NewCRCWB.Sheets("Sheet1")
OriginalWB.Sheets("Module Part Number Tracker").Copy Before:=NewCRCWB.Sheets("Generator")
OriginalWB.Sheets("CRC").Copy Before:=NewCRCWB.Sheets("Module Part Number Tracker")
Application.DisplayAlerts = False
NewCRCWB.Worksheets("Generator").Visible = False
NewCRCWB.Worksheets("Module Part Number Tracker").Visible = False
NewCRCWB.Worksheets("Sheet1").Delete
Application.DisplayAlerts = True
End Sub
I'd take a copy of the original file and delete/hide sheets from that.
All code is copied over as part of the save.
Sub Test()
Dim wrkBk As Workbook
Dim sCopyFileName As String
Dim wrkSht As Worksheet
sCopyFileName = "C:\MyFolderPaths\Book2.xlsm"
'Create copy of original file and open it.
ThisWorkbook.SaveCopyAs (sCopyFileName)
Set wrkBk = Workbooks.Open(sCopyFileName)
'wrkbk.Worksheets does not include Chart sheets.
'wrkbk.Sheets would take into account all the types of sheet available.
For Each wrkSht In wrkBk.Worksheets
Select Case wrkSht.Name
Case "Generator", "Module Part Number Tracker"
wrkSht.Visible = xlSheetVeryHidden
Case "CRC"
'Do nothing, this sheet is left visible.
Case Else
Application.DisplayAlerts = False
wrkSht.Delete
Application.DisplayAlerts = True
End Select
Next wrkSht
wrkBk.Close SaveChanges:=True
End Sub
I managed to find an answer to my question.. This code works fine however you need to add "Microsoft Visual Basic for Applications Extensibility 5.x" as a reference via Tools -> References. Here is the code:
Dim src As CodeModule, dest As CodeModule
Set src = ThisWorkbook.VBProject.VBComponents("Sheet1").CodeModule
Set dest = Workbooks("Book3").VBProject.VBComponents("ThisWorkbook") _
.CodeModule
dest.DeleteLines 1, dest.CountOfLines
dest.AddFromString src.Lines(1, src.CountOfLines)
Credit: Copy VBA code from a Sheet in one workbook to another?

How to disable add sheet button in Excel with VBA?

I have a workbook I would like to disable the Add New Sheet button that is next to the tabs. I have searched and found the following that disable the insert options on the workbook book which is great.
Application.CommandBars("Ply").FindControl(, 945).Enabled = False
Application.CommandBars("Insert").Controls(4).Enabled = False
But I have yet to find the command for the Add New Sheet button. Is there a place that lists all these options or a tool I can use to identify the control or button.
The workbook is shared so automatically deleting the sheet on creation will not work.
Protect Structure does not work either and throws the following error:
In the ThisWorkbook code sheet, paste the following.
Option Explicit
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Application.DisplayAlerts = False
Sh.Delete
End Sub
Any new (or copied) worksheet that is created is instantly deleted.
This isn't a proper solution to your actual problem, but it will give the illusion of doing what you want...
In the ThisWorkbook module, add this to instantly hide any new sheets with 'DeleteThisSheet' in cell A1
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Sh.Cells(1, 1) = "DeleteThisSheet"
Sh.Visible = xlSheetVeryHidden
End Sub
Obviously, this will clutter up the workbook with hidden sheets, so you can clear them out from time to time using this code to switch off sharing and delete the hidden sheets.
Sub removeSheets()
Dim ws As Worksheet
' Turn off sharing
Application.DisplayAlerts = False
If ActiveWorkbook.MultiUserEditing Then
ActiveWorkbook.ExclusiveAccess
End If
' Delete veryhidden sheets with delete code
For Each ws In ThisWorkbook.Sheets
If ws.Visible = xlSheetVeryHidden And ws.Cells(1, 1) = "DeleteThisSheet" Then
ws.Visible = xlSheetVisible
ws.Delete
End If
Next ws
' Turn sharing back on
If Not ActiveWorkbook.MultiUserEditing Then
ActiveWorkbook.SaveAs ActiveWorkbook.Name, accessmode:=xlShared
End If
Application.DisplayAlerts = True
End Sub
As I say, it's not ideal, but may at least serve your purpose, although probably won't stand up to many people repeatedly attempting to add new sheets. You could possibly add a msgbox to the newssheet code to say something along the lines of 'This action has been disabled' to stop them retrying. I'll keep an eye on this thread to see if anyone comes up with a proper solution, it's always good to learn something new.
Not sure if this solves the issue:
Application.CommandBars("Insert").Controls(4).Visible = False
This uses Visible property.

how can i change the colour of mutiple optionbuttons with as little code as possible

I have a spreadsheet with 70 rows x 6 columns containing 420 option buttons in groups of 6 ie group1 = optionbutton1, 71.141,211,281 and 351. Group2 = Optionbutton2,72,142,282 and 352.
This is the code I have for changing the background colour based on the value of the button:
Private Sub OptionButton1_Change()
With OptionButton1
If .Value Then
.BackColor = vbRed ' or RGB(255, 0, 0)
Else
.BackColor = vbGreen ' or RGB(0,0,0)
End If
End With
End Sub
I need to do this for all 420 option buttons, but this could take a while to replicate and stands more chance of missing entries.
Is there a way of shortening this code or changing the code to apply to any option button on the worksheet to change to red on true or green when false?
It looks like you're using an ActiveX Option Button and, unfortunately, I don't believe there is a way to get around having to have code associated with the Change or Click Events of each Option Button if you want it to automatically change the Controls BackColor when the user changes an option.
An alternative would be to use the Form Controls Option Button as with these you can set them all to run the same code whenever their selection is changed. Taking this approach you could have a single Method which will loop through every Option Button on the Sheet and change it's background colour dependent on its value.
The following is an example of how you could do this. In the Visual Basic editor add a new Module to your project. This function would be called whenever your Option Button is changed, and it will work through every Option Button on the Sheet and change its colour.
Sub optionButtonChange()
Dim wb As Workbook
Dim ws As Worksheet
Dim formShape As shape
Set wb = ActiveWorkbook
Set ws = wb.ActiveSheet
For Each formShape In ws.Shapes
If formShape.Type = MsoShapeType.msoFormControl Then
If TypeName(formShape.OLEFormat.Object) = "OptionButton" Then
If formShape.OLEFormat.Object.Value = 1 Then
formShape.OLEFormat.Object.Interior.Color = vbRed
Else
formShape.OLEFormat.Object.Interior.Color = vbGreen
End If
End If
End If
Next
Set ws = Nothing
Set wb = Nothing
End Sub
Now for this to work you need to assign this to the Option Buttons 'macro' - you can do this manually by right clicking the Option Button and selecting it, or you can do it programmatically by applying it to every Option Button on the Sheet, as in the following example:
Sub changeOnAction()
Dim wb As Workbook
Dim ws As Worksheet
Dim formShape As shape
Set wb = ActiveWorkbook
Set ws = wb.ActiveSheet
For Each formShape In ws.Shapes
If formShape.Type = MsoShapeType.msoFormControl Then
If TypeName(formShape.OLEFormat.Object) = "OptionButton" Then
' Macro name format is "'<workbooks filename>'!functionToCall"
formShape.OnAction = "'" & wb.Name & "'!optionButtonChange"
End If
End If
Next
Set formShape = Nothing
Set ws = Nothing
Set wb = Nothing
End Sub
To use this, make sure the Sheet with your Option Buttons on is open and from the Visual Basic editor simply run the code. Once that is done clicking any Option Button on your Sheet will trigger the initial code example and they should all re-colour automatically.

Error-1004 in Excel VBA- Unable to set the visible property of the worksheet class

With the help of Excel forum, I have created a user login form where I have 5 users. Each user can have access to the sheets assigned to him/her only. This is working fine. But now I have protected the "workbook structure" so as to avoid users' adding/deleting sheets. Then I login again, and instead of displaying the login form, the error message pops up in Excel VBA:
Error-1004 Unable to set the visible property of the worksheet class
When I debug the error is highlighted in the following codes where the visible property of the worksheet is set as "True", "False" or "xlSheetVeryHidden".
Private Sub Workbook_Open()
Dim wsSht As Worksheet
Worksheets("Splash").Visible = True
Worksheets("Users").Visible = False
For Each wsSht In Worksheets
If Not wsSht.Name = "Splash" Then wsSht.Visible = xlSheetVeryHidden
Next wsSht
With Worksheets("Splash")
.Visible = True
.Activate
End With
frmLogin.Show
bBkIsClose = False
End Sub
Is there a way to correct this so as I can access the login form as I did prior to password protecting the "workbook structure"?
Here is another concern about this.
You can NOT hide ALL of the worksheets in a workbook. As such if you know you are going to have at least 1 sheet that will ALWAYS be visible, exclude it from the hiding process.
Did you have another Excel Workbook opened at the same time when testing it? There's no explicit reference to the book you're looking for, so in case you run this code having a workbook where the "Splash" sheet is not available, the macro will try to set all sheets to hidden, which may raise this error.
To simulate it, open a new Excel session and run this macro:
Sub test()
Dim oSheet As Excel.Worksheet
For Each oSheet In Worksheets
oSheet.Visible = xlSheetVeryHidden
Next oSheet
End Sub
If I'm not barking to the wrong tree, you'll get the same error.
To solve it, simply add the workbook name into your loop, and it would be like this (obviously, you must ensure that there's a "Splash" sheet, or the error will arise):
For Each wsSht In Workbooks("Mybook.xlsm").Worksheets
If Not wsSht.Name = "Splash" Then wsSht.Visible = xlSheetVeryHidden
Next wsSht
Rgds
You'll have to unprotect and reprotect in code. The downside is that your password will be in the code.
Private Sub Workbook_Open()
Dim wsSht As Worksheet
Me.Unprotect "password"
Me.Worksheets("Splash").Visible = True
Me.Worksheets("Users").Visible = False
For Each wsSht In Me.Worksheets
If Not wsSht.Name = "Splash" Then wsSht.Visible = xlSheetVeryHidden
Next wsSht
With Me.Worksheets("Splash")
.Visible = True
.Activate
End With
frmLogin.Show
bBkIsClose = False
Me.Protect "password", True, False
End Sub
I'm not sure if this is relevant, but I found this question when I was searching for how to hide the last (and only) worksheet. The reason for wanting to do this is because the file is a startup file that contains company-wide macros that should not be edited by the user. I discovered that while the Worksheet needs to be kept open, the Window displaying it does not.
Here's an example:
Sub spork()
Dim x As Workbook
x.Windows.Item(1).Visible = False
End Sub
Now, Excel opens the file with no worksheet visible.
Sometimes there is a "glitch" (a.k.a. "feature" or "bug"), simply returning this error due to no visible reason. Not the worksheet protection, neither the fact that this is the last worksheet visible. To fix the "feature" this worked for me:
Public Sub UnhideAll()
Dim wks As Worksheet
For Each wks In ThisWorkbook.Worksheets
wks.Visible = xlSheetVisible
Next
End Sub