UserForm ComboBox Worksheet Reset - excel

this is the first time I've ever worked with VBA UserForms, I've coded with VBA before and have had some experience producing programs that work in the background but not so much with a user interface. I'd really appreciate some help trouble shooting my dilemma. I took a series of screenshots to represent in order of events what is happening.
This is the number of worksheets before running the UserForm
This is the UserForm with the current worksheets
This is the Updated number of worksheets after closing both the Macro and Userform
This is the Userform with the same number of worksheets
As you can see the number of worksheets did not update after running it a second time and the hidden worksheet is displayed as an option.
Private m_Cancelled As Boolean
Public Property Get Cancelled() As Variant
Cancelled = m_Cancelled
End Property
Private Sub ComboBox1_Change()
End Sub
Private Sub CommandButton1_Click()
Hide
End Sub
Private Sub CommandButton2_Click()
' Hide the Userform and set cancelled to true
Hide
m_Cancelled = True
End Sub
Private Sub UserForm_Click()
End Sub
Private Sub UserForm_Initialize()
ReDim InitialArray(ActiveWorkbook.Worksheets.Count) As Variant
Dim i As Integer
For i = 1 To ActiveWorkbook.Worksheets.Count
InitialArray(i) = ActiveWorkbook.Sheets(i).Name
Next i
ComboBox1.List = InitialArray
End Sub
Private Sub UserForm_Activate()
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer _
, CloseMode As Integer)
' Prevent the form being unloaded
If CloseMode = vbFormControlMenu Then Cancel = True
' Hide the Userform and set cancelled to true
Hide
m_Cancelled = True
End Sub
This is the code I'm currently using. It's a bit rough and tumble because I'm still learning how to use it and it's various properties.
I would like the combobox to update when ran a second time if a worksheet is added or removed.
I'd also like the conbobox to keep the hidden worksheets hidden from the options.
Again any help would be greatly appreciated!
Thank you! :)

Write the Names of Visible Worksheets to a Combo Box
You need an array of visible worksheet names but you don't know how many worksheets are visible. In this case, a better choice is to use a dictionary since its keys (or its items) result in an array.
Private Sub UserForm_Initialize()
With CreateObject("Scripting.Dictionary")
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If ws.Visible = xlSheetVisible Then .Add ws.Name, Empty
Next ws
ComboBox1.List = .Keys
End With
End Sub
If for some reason you want to stick with the array, you could use the following.
Private Sub UserForm_Initialize()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wCount As Long: wCount = wb.Worksheets.Count
Dim wsNames() As String: ReDim wsNames(1 To wCount)
Dim ws As Worksheet, w As Long
For Each ws In wb.Worksheets
If ws.Visible = xlSheetVisible Then
w = w + 1
wsNames(w) = ws.Name
End If
Next ws
If w < wCount Then ReDim Preserve wsNames(1 To w)
ComboBox1.List = wsNames
End Sub

Related

How to initialize a listbox to a desired starting point in the list?

I created a macro for Excel which opens a list of all visible sheets in a workbook and goes to the desired sheet as you scroll through the list. The idea is to avoid using the mouse as much as possible.
I am forced to scroll down starting from the first item in the list.
I would like to instead "start" from the initial sheet (wherever it may be) so I can scroll up/down depending on what sheet I would like to open.
In other words,
I would like the listbox to populate with all visible sheets
I would like the starting point for the user to be the active sheet so they can scroll up/down from their starting point
Code for the listbox:
Private Sub CommandButton1_Click()
Unload ListBox
End Sub
Private Sub UserForm_Initialize()
Dim WS As Worksheet
For Each WS In Worksheets
ListBox1.AddItem WS.Name
Next WS
End Sub
Private Sub ListBox1_Click()
Sheets(ListBox1.Value).Activate
End Sub
Code which opens the listbox:
Public Sub ShowUserForm()
Load ListBox
ListBox.Show
Debug.Print "===="
Debug.Print
End Sub
another one...
Private Sub UserForm_Initialize()
Dim ws As Worksheet, idx As Long
With Me.ListBox1
For Each ws In ActiveWorkbook.Worksheets
If ws.Visible = xlSheetVisible Then
.AddItem ws.Name
If ws Is ActiveSheet Then
idx = .ListCount - 1 ' item indexes start at zero
End If
End If
Next
.ListIndex = idx '
End With
End Sub
Private Sub ListBox1_Change()
Worksheets(ListBox1.Value).Activate
End Sub
You mentioned "all . . . sheets", if you want to include Chart sheets loop Each objSheet in Sheets and in the change event replace Worksheets with Sheets
what's about that:
Private Sub UserForm_Initialize()
Dim wksTab As Worksheet
For Each wksTab In ThisWorkbook.Worksheets
If wksTab.Visible = xlSheetVisible Then
If wksTab.Name <> ActiveSheet.Name Then
Me.ListBox1.AddItem wksTab.Name
End If
End If
Next wksTab
Me.ListBox1.AddItem ActiveSheet.Name
Me.ListBox1.ListIndex = Me.ListBox1.ListCount - 1
End Sub
Best regards
Bernd

Variable not available on UseerForm_Initialize event

I am trying to pass row number to UserForm, so it could display data in user friendly way for end user, but having trouble catching this variable on Initialize moment.
Code in the Worksheet module, it should open UserForm and pass row number as variable:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim DataRange As ListObject
Dim xRow As Long
xRow = Target.Row
Set DataRange = Sheets("Forecast").ListObjects("ForecastTable")
If Application.Intersect(Target, DataRange.DataBodyRange) Is Nothing Or Target.Cells.Count > 1 Then
Exit Sub
Else
MsgBox xRow
With FullInfo
.MyProp = xRow
.Show
End With
End If
End Sub
This is the code in UserForm:
Property Let MyProp(xRow As Long)
publicRow = xRow
End Property
Private Sub UserForm_Initialize()
Dim publicRow As Long
MsgBox publicRow
End Sub
From MsgBox I used for testing I determined that code in the sheet module returns correct row number, but then UserForm is initialized it shows 0 as no data is received. Interestingly enough, I put a button in the user form for testing with following code:
Private Sub Save_Click()
MsgBox publicRow
End Sub
After pressing it - it shows correct row number, so it means it passed but only after Initialize event. How should I pass variable to UserForm so it would be available at Initialize event?
I have a solution for you. :)
...so this is your code corrected ...
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim DataRange As ListObject
Dim xRow As Integer
Dim FullInfo As Object
xRow = Target.Row
Set DataRange = Sheets("Forecast").ListObjects("Tabela1")
If Application.Intersect(Target, DataRange.DataBodyRange) Is Nothing Or
Target.Cells.Count > 1 Then
Exit Sub
Else
Set FullInfo = New UserForm1
With FullInfo
.Label1.Caption = xRow
.Show
End With
End If
End Sub
... if you want to go further, I have another way to pass a public variable to userForm
You code in sheet
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim DataRange2 As ListObject
Dim xRow As Integer
xRow = Target.Row
Set DataRange2 = Sheets("Arkusz1").ListObjects("Tabela2")
If Application.Intersect(Target, DataRange2.DataBodyRange) Is Nothing Or
Target.Cells.Count > 1 Then
Exit Sub
Else
Call UserFormStart(xRow)
End If
End Sub
Put code to new module (in the worksheet do not work)
'Public rowSelection As Integer 'declare public variable
Public Sub UserFormStart(ByVal rowRef As Integer)
rowSelection = rowRef
UserForm1.Show
End Sub
In your userForm
Private Sub CommandButton1_Click()
MsgBox rowSelection & " it's work"
End Sub
Public Sub UserForm_Initialize()
MsgBox rowSelection
End Sub
It works for me :)
You can check one topic
Excel - VBA : pass variable from Sub to Userform

Log every time a sheet is protected or unprotected in excel VBA

I'm looking for a way to write into another sheet in excel, every time someone either protects or unprotects the sheet in my Workbook. I want it to log whether it was protected or unprotected and the time beside it. Thanks!
Right now I have the following code for protecting or unprotecting the sheet with a more user friendly button:
If ActiveWorkbook.Sheets("Calendar").ProtectContents = True Then
ActiveSheet.Unprotect
MsgBox "Sheet unprotected"
Exit Sub
End If
ActiveSheet.Protect ("password")
MsgBox "Calendar has been protected"
Excel VBA does not have an event that can detect if a sheet is being protected/unprotected.
Don't shoot the messenger.
A google would have landed you here: https://www.ozgrid.com/forum/index.php?thread/43816-unprotect-worksheet-event/, the author even gives you a sample:
https://www.ozgrid.com/forum/core/index.php?attachment/1082834-52719-xls/
This is not 100% fool proof as the eventhandler can not tell when a user Cancels the protect/unprotect dialog.
This workbook
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
StartEventListiner False
End Sub
Private Sub Workbook_Open()
StartEventListiner True
End Sub
Module
Option Explicit
Public g_clsEvnt As CProtectEvt
Public Sub StartEventListiner(Action As Boolean)
If Action Then
Set g_clsEvnt = New CProtectEvt
Else
Set g_clsEvnt = Nothing
End If
End Sub
Class
Option Explicit
Public WithEvents cbbProtect As CommandBarButton
Private Sub m_ProtectControls(State As Boolean)
Dim objX As OLEObject
On Error Resume Next
For Each objX In ActiveSheet.OLEObjects
objX.Object.Enabled = State
Next
End Sub
Private Sub cbbProtect_Click(ByVal Ctrl As Office.CommandBarButton, CancelDefault As Boolean)
m_ProtectControls (InStr(1, Ctrl.Caption, "Un&protect", vbTextCompare) > 0)
End Sub
Private Sub Class_Initialize()
On Error Resume Next
' hook into Tools > Protection > Protect Sheet event
Set cbbProtect = Application.CommandBars.FindControl(msoControlButton, ID:=893)
End Sub
Toggle and Log Worksheet Protection
The code only logs the protection when using the button (which has toggleWorksheetProtection_Click assigned to it) or when running toggleWorksheetProtection_Click from VBE.
Copy the complete code into a standard module (e.g. Module11).
Adjust the values of the five constants.
ThisWorkbook refers to the workbook containing this code.
Additionally adjust the date format in writeLogRow.
The Code
Option Explicit
Sub toggleWorksheetProtection_Click()
' Constants
Const srcName As String = "Calendar"
Const tgtName As String = "Log"
Const tgtCol As Variant = 1
Const msgProtect As String = "Sheet protected."
Const msgUnProtect As String = "Sheet unprotected."
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook
' Other Variables
Dim src As Worksheet: Set src = wb.Worksheets(srcName)
Dim tgt As Worksheet: Set tgt = wb.Worksheets(tgtName)
Dim msg As String
' Protection
If src.ProtectContents Then
src.Unprotect: msg = msgUnProtect
Else
src.Protect: msg = msgProtect
End If
' Log
Dim cel As Range
Set cel = getEmptyCell(tgt, tgtCol)
writeLogRow cel, msg
End Sub
Function getEmptyCell(Sheet As Worksheet, ByVal writeColumn As Variant)
Dim cel As Range
Set cel = Sheet.Columns(writeColumn).Find("*", , xlValues, , , xlPrevious)
If Not cel Is Nothing Then
Set cel = cel.Offset(1)
Else
Set cel = Sheet.Cells(1, writeColumn)
End If
Set getEmptyCell = cel
End Function
Sub writeLogRow(logRange As Range, ByVal logMessage As String)
Dim logDate As Date: logDate = Now
logRange.Value = logDate
logRange.NumberFormat = "mm/dd/yyyy hh:mm:ss (ddd)"
logRange.Offset(, 1).Value = logMessage
End Sub

only userform should be visible and not the excel

Please advise as to how can we show only userform and not excel behind it.
I used application.visible = false but it is hiding all the other excel.
I used activatewindow.visible = false but userform is not retrieving the data from excel.
I used activatewindow.displayworkbooktabs=false but it is not hiding the workbook.
Try this code.
Private Sub Workbook_Open()
Application.Visible = False
UserForm1.Show vbModeless
End Sub
Don't forget to make Application visible before close
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Application.Visible = True
End Sub
Write this to userform:
Private Sub CommandButton1_Click()
Dim wCount As Long
Dim i As Long
wCount = Windows.Count
For i = 1 To wCount
Windows(i).Visible = True
Next i
Unload Me
End Sub
Private Sub UserForm_Initialize()
Dim wCount As Long
Dim i As Long
wCount = Windows.Count
For i = wCount To 1 Step -1
Windows(i).Visible = False
Next i
End Sub

Uncheck all checkboxes across entire workbook via CommandButton

I would like to have a code that unchecks all checkboxes named "CheckBox1" for all sheets across the workbook. My current code unfortunately doesn't work, and I'm not sure why - it only works for the active sheet.
Private Sub CommandButton1_Click()
Dim Sheet As Worksheet
For Each Sheet In ThisWorkbook.Worksheets
Select Case CheckBox1.Value
Case True: CheckBox1.Value = False
End Select
Next
End Sub
This code iterates through all sheets (except sheets named Sheet100 and OtherSheet) and unchecks all your ActiveX checkboxes named CheckBox1
Sub uncheck_boxes()
Dim ws As Worksheet
Dim xbox As OLEObject
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Sheet100" And ws.Name <> "OtherSheet" Then
For Each xbox In ws.OLEObjects
ws.OLEObjects("CheckBox1").Object.Value = False
Next
End If
Next
End Sub
To uncheck all ActiveX checkboxes in all sheets disregarding the names used
Sub uncheck_all_ActiveX_checkboxes()
Dim ws As Worksheet
Dim xbox As OLEObject
For Each ws In ThisWorkbook.Worksheets
For Each xbox In ws.OLEObjects
ws.OLEObjects(xbox.Name).Object.Value = False
Next
Next
End Sub
To uncheck all Form Control checkboxes on a spreadsheet use
Sub uncheck_forms_checkboxes()
Dim ws As Worksheet
Dim xshape As Shape
For Each ws In ThisWorkbook.Worksheets
For Each xshape In ws.Shapes
If xshape.Type = msoFormControl Then
xshape.ControlFormat.Value = False
End If
Next
Next
End Sub
[edited following comments]
Try this:
Sub test()
Dim ws As Excel.Worksheet
Dim s As Object
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Definitions" And ws.Name <> "fx" Then
Set s = Nothing
On Error Resume Next
Set s = ws.OLEObjects("CheckBox1")
On Error GoTo 0
If Not s Is Nothing Then
s.Object.Value = False
End If
End If
Next ws
End Sub
This is a global function (it doesn't belong to a particular sheet), but you can put it inside CommandButton1_Click() if you want.
You might not need the error blocking if your sheets (other than Definitions and fx) always contain CheckBox1. Alternatively remove that if statement.

Resources