below is the code I'm working on to make a UserForm. I'm new to using UserForm and am tryin to populate ComboBox 2 with ComboBox 1 selection. ComboBox 1 holds the name of the worksheets and I'd like ComboBox 2 to update with the column heading names of the selected worksheet. Any help would be greatly appreciated.
Private m_Cancelled As Boolean
Public Property Get Cancelled() As Variant
Cancelled = m_Cancelled
End Property
Private Sub ComboBox1_Change()
'Initialize ComboBox2
Application.EnableEvents = False
ComboBox2.Clear
Application.EnableEvents = True
Debug.Print "Here"; ComboBox1.Value
' Select Case ComboBox1.Value
' Case ComboBox1.Value
With Worksheets(ComboBox1.Value)
Debug.Print "Active Worksheet";
Dim InitialArray() As Variant
Dim i As Integer
Dim ColCount As Integer
' Debug.Print ColCount; RowStart
Do While IsEmpty(Cells(1, ColCount + 1).Value) = False
ColCount = ColCount + 1
' Debug.Print Cells(RowStart, ColCount)
Loop
Debug.Print ColCount; "Cols"
End With
' End Select
' Select Case ComboBox1.Value
For i = 1 To ColCount
Cells(1, i).Add
Next i
' End Select
End Sub
Private Sub ComboBox2_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()
ComboBox1.Clear
'Initialize ComboBox1
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
' ReDim InitialArray(ActiveWorkbook.Worksheets.Count) As Variant
' Dim i As Integer
'
' ComboBox1.Clear
' 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
Function GetComboBox1() As String
GetComboBox1 = ComboBox1.Value
End Function
Related
I have put together the code below to hide named worksheets using a Checkbox. The workbook also contains sheets with the generic names like Sheet1, Sheet2, etc and I would like to be able to hide all sheets whose name contains the word "Sheet" from the same Checkbox.
Is this possible?
Thanks
Private Sub CheckBox1_Click()
Application.ScreenUpdating = False
If CheckBox1 = False Then
If ThisWorkbook.Sheets("Summary").Range("B10") <> "" Then Sheets(ActiveSheet.Range("B10").Value).Visible = False
Else:
If ThisWorkbook.Sheets("Summary").Range("B10") <> "" Then Sheets(ActiveSheet.Range("B10").Value).Visible = True
End If
Application.ScreenUpdating = False
End Sub
If you really want hiding sheets, please use the next code. It hides all sheets where their name starts with ""Sheet":
Private Sub CheckBox1_Click()
Dim sh As Worksheet
For Each sh In Worksheets
If left(sh.name, 5) = "Sheet" Then
sh.Visible = xlSheetVeryHidden
End If
Next
End Sub
Hide Worksheet With Pattern
Reminder
At least one of all sheets in a workbook has to be visible.
There is a third 'visibility' parameter xlSheetHidden which is not considered in this solution.
You can hide multiple worksheets in one go by using an array of worksheet names (fast), but you have to loop through the array to unhide each of them (slow).
The Code
Option Explicit
Private Sub CheckBox1_Click()
Const WorksheetPattern As String = "ShEeT*"
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsArr As Variant
Application.ScreenUpdating = False
If CheckBox1 Then ' Hide
wsArr = WorksheetNamesToArray(wb, WorksheetPattern)
wb.Worksheets(wsArr).Visible = xlSheetHidden ' also 0 or False
Else ' UnHide
wsArr = WorksheetNamesToArray(wb, WorksheetPattern, xlSheetHidden)
Dim n As Long
For n = 1 To UBound(wsArr)
wb.Worksheets(wsArr(n)).Visible = xlSheetVisible ' also -1 or True
Next n
End If
Application.ScreenUpdating = True
End Sub
Function WorksheetNamesToArray( _
ByVal wb As Workbook, _
ByVal WorksheetPattern As String, _
Optional ByVal isVisible As XlSheetVisibility = xlSheetVisible) _
As Variant
If Not wb Is Nothing Then
Dim wsCount As Long: wsCount = wb.Worksheets.Count
Dim wsArr() As String: ReDim wsArr(1 To wsCount)
Dim ws As Worksheet
Dim n As Long
For Each ws In wb.Worksheets
If UCase(ws.Name) Like UCase(WorksheetPattern) Then
If ws.Visible = isVisible Then
n = n + 1
wsArr(n) = ws.Name
End If
End If
Next ws
ReDim Preserve wsArr(1 To n)
WorksheetNamesToArray = wsArr
End If
End Function
Hi everyone! I'm trying to write a method in VBA to keep 2 worksheets and delete others at the same time.
I already did the one that will keep one worksheet and delete others like this:
Sub delete_all_pages_except_main()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Application.DisplayAlerts = False
If ws.Name <> "Home Page" Then
ws.Delete
End If
Next ws
End Sub
And I try to write it like this
If (ws.Name <> "Home Page" Or ws.Name <> "Data")
But VBA would accept it.
Can you guys help? Thank you.
This should do
Sub delete_all_pages_except_main()
Dim ws As Worksheet
Dim arr As Variant
Dim boo As Boolean
Application.DisplayAlerts = False
arr = Array("Home Page", "Data")
For Each ws In ThisWorkbook.Worksheets
boo = NoDel(ws.Name, arr)
If boo <> True Then ws.Delete
Next ws
Application.DisplayAlerts = True
End Sub
Function NoDel(ws As String, warr As Variant) As Boolean
NoDel = False
For i = LBound(warr, 1) To UBound(warr, 1)
If warr(i) = ws Then NoDel = True
Next i
End Function
Delete Sheets With Exceptions
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: In a specified workbook, writes all the sheet names '
' not specified in an Exceptions array to a Result array, and '
' using the Result array deletes all the sheets in one go. '
' Remarks: This solution applies to worksheets and chartsheets. '
' Since there is no Sheet object, the For Next loop (instead '
' of the For Each Next loop) and the Object type have '
' to be used. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub deleteSheets(Book As Workbook, Exceptions As Variant)
' Program
Dim SheetsCount As Long: SheetsCount = Book.Sheets.Count
Dim Result As Variant: ReDim Result(SheetsCount)
Dim sh As Object, i As Long, j As Long
j = -1
For i = 1 To SheetsCount: GoSub checkName: Next i
If j = -1 Then GoTo NothingToDelete
If j = SheetsCount - 1 Then GoTo NoExceptions
GoSub deleteSheetsInOneGo
MsgBox "Deleted '" & j + 1 & "' sheets.", vbInformation, "Success"
Exit Sub
' Subroutines
checkName:
Set sh = Book.Sheets(i)
If IsError(Application.Match(sh.Name, Exceptions, 0)) Then
j = j + 1
Result(j) = sh.Name
End If
Return
deleteSheetsInOneGo:
ReDim Preserve Result(j)
Application.DisplayAlerts = False
Book.Sheets(Result).Delete
Application.DisplayAlerts = True
Return
' Labels
NothingToDelete:
MsgBox "Sheets already deleted.", vbCritical, "Nothing to Delete"
Exit Sub
NoExceptions:
MsgBox "Cannot delete all sheets.", vbCritical, "No Exceptions"
Exit Sub
End Sub
' Usage Example
Sub runDeleteSheets()
Dim SheetNames As Variant: SheetNames = Array("Home Page", "Data")
deleteSheets ThisWorkbook, SheetNames
End Sub
I am new to VBA and UserForms.
I have a ComboBox where the user will enter a unique Sales Order # (SalesOrder). I want my form to take this input and find it in the workbook and then update the status with the user's inputs in later ComboBoxes (CommentBox & OrderStatus). The issue I am facing is the actual code to find the Sales Order # in the workbook. I've tried what is seen below in several different variations.
If I replace all the ComboBox inputs with the actual inputs as a string, the code runs fine in a module.
Ideally, the code will loop through the sheet array finding all the lines with the Sales Order # and apply the inputs to the row.
Sub AddDataToList()
Dim shtarray As Variant, shtname As Variant
Dim Data As Worksheet, ws As Worksheet
Dim wbk As Workbook
Dim Strg As String
shtarray = Array("EMAUX", "Irene", "Cassandra", "Patricia", "EMREL", "Maria", "Jason", "Peedie", "MICRO", "PARTS", "NAVY", "DELTA")
Set wbk = ThisWorkbook
For Each shtname In shtarray
Set ws = Nothing
On Error Resume Next
Set ws = wbk.Worksheets(shtname)
On Error GoTo 0
If Not (ws Is Nothing) Then
ActiveSheet.Cells.Find(StatusUpdateForm.SalesOrder.Text).Offset(0, 17).Select
ActiveCell.Value = CommentBox.Text
ActiveCell.Offset(0, 2).Value = OrderStatus.Text
End If
Next
MsgBox SalesOrder.Value & "was updated."
End Sub
Thank you for the assistance!
More Information ***
Below is the code for the Update command button. This is a standard two button system, one updates the records and the other cancels the form.
Private Sub UpdateButton_Click()
If Not EverythingFilledIn Then Exit Sub
Me.Hide
AddDataToList
Unload Me
End Sub
And code for the EverthingFilledIn
Private Function EverythingFilledIn() As Boolean
Dim ctl As MSForms.Control
Dim AnythingMissing As Boolean
EverthingFilledIn = True
AnythingMissing = False
For Each ctl In Me.Controls
If TypeOf ctl Is MSForms.TextBox Or TypeOf ctl Is MSForms.ComboBox Then
If ctl.Value = "" Then
ctl.BackColor = rgbPink
Controls(ctl.Name & "Label").ForeColor = rgbRed
If Not AnythingMissing Then ctl.SetFocus
AnythingMissing = True
EverythingFilledIn = False
End If
End If
Next ctl
End Function
Try this (my first comment notwithstanding):
Sub AddDataToList()
Dim shtarray As Variant, shtname As Variant
Dim Data As Worksheet, ws As Worksheet
Dim wbk As Workbook
Dim Strg As String
Dim r As Range
shtarray = Array("EMAUX", "Irene", "Cassandra", "Patricia", "EMREL", "Maria", "Jason", "Peedie", "MICRO", "PARTS", "NAVY", "DELTA")
Set wbk = ThisWorkbook
For Each shtname In shtarray
Set ws = wbk.Worksheets(shtname)
Set r = ws.Cells.Find(StatusUpdateForm.SalesOrder.Text) 'better to specify all parameters
If Not r Is Nothing Then
r.Offset(0, 17).Value = CommentBox.Text
r.Offset(0, 2).Value = OrderStatus.Text
End If
Next
MsgBox SalesOrder.Value & "was updated."
End Sub
There is no need to select things.
Allowing a user to update the content of listobjects in protected sheets can be cumbersome.
Gladly I found Excel Developers answer but I also needed to allow the user to add or delete rows.
Below is my code to solve it.
(*) Any improvements are welcome
Add a class module to your VB project
Note: This will work if you have only one table (listobject) per page
Class name: cProtectedLO
Option Explicit
' Credits: https://stackoverflow.com/questions/32221328/how-to-protect-a-worksheet-and-unprotect-a-list-object-in-vba
Private Type TTable
Table As ListObject
password As String
End Type
Private this As TTable
Private WithEvents appExcel As Excel.Application
Public Property Set Table(ByVal object As ListObject)
Set this.Table = object
End Property
Public Property Let password(ByVal password As String)
this.password = password
End Property
Private Sub Class_Initialize()
Set appExcel = Excel.Application
End Sub
Private Sub appExcel_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim evalRange As Excel.Range
Dim currentValue As Variant
Set evalRange = this.Table.Range
If Sh Is evalRange.Parent Then
If Target.Row > 1 Then
If Not Intersect(Target.Offset(-1), evalRange) Is Nothing Then
If Intersect(Target, evalRange) Is Nothing Then
' Check if selection is an entire row
If Not Target.Cells.Count = Target.EntireRow.Cells.Count Then
currentValue = Target.Value
Sh.Unprotect password:=IIf(Len(this.password), this.password, Null)
With Application
.EnableEvents = False
.Undo
Target.Value = currentValue
'Sh.Cells.Locked = True
this.Table.DataBodyRange.Locked = False
this.Table.Range(this.Table.Range.Rows.Count, 1).Offset(1, 0).Resize(1, this.Table.ListColumns.Count).Locked = False
.EnableEvents = True
End With
Target.Offset(1).Select
Sh.Protect password:=IIf(Len(this.password), this.password, Null), UserInterfaceOnly:=True, AllowFormattingRows:=True, AllowUsingPivotTables:=True, AllowDeletingRows:=True, AllowInsertingRows:=True
End If
End If
' If user is writing somthing in a row
ElseIf Not Intersect(Target.EntireRow, evalRange) Is Nothing Then
' User has selected a row and begins typing (as the row is unprotected). Undo whatever user is doing
If Sh.ProtectContents = True Then
With Application
.EnableEvents = False
.Undo
.EnableEvents = True
End With
End If
End If
End If
End If
End Sub
Private Sub Class_Terminate()
Set this.Table = Nothing
Set appExcel = Nothing
End Sub
Private Sub appExcel_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
Dim evalRange As Range
Dim IsProtected As Boolean
Set evalRange = this.Table.Range
If Sh Is evalRange.Parent Then
' Check if user is copying / cutting cells and is selecting the entire row
If Target.Row > 1 Then
If Not Intersect(Target.Offset(-1), evalRange) Is Nothing And Application.CutCopyMode = 0 And Target.Cells.Count = Target.EntireRow.Cells.Count Then
' Unlock row if it's at the same listobject range (plus the row below the bottom)
If Not Intersect(Target, evalRange.Resize(evalRange.Cells.Rows.Count + 1, evalRange.Cells.Columns.Count)) Is Nothing Then
IsProtected = False
Else
IsProtected = True
End If
Target.EntireRow.Locked = IsProtected
End If
End If
End If
End Sub
Add a standard module
Module name: mSecurity
Option Explicit
Public colProtectedTable As Collection
Public Sub ProtectWorkbook(Optional ByVal password As Variant)
Dim lProtectedTable As cProtectedLO
Dim evalSheet As Worksheet
Dim evalListObject As ListObject
' Initialize the collection to store current workbook listobjects
Set colProtectedTable = New Collection
' Loop through all worksheets in current workbook
For Each evalSheet In ThisWorkbook.Worksheets
' If the evaluated worksheet has excel structured tables (listobjects)
If evalSheet.ListObjects.Count > 0 Then
' If it does, loop through all of listobjects
For Each evalListObject In evalSheet.ListObjects
' Initialize the class that handles the protected list objects
Set lProtectedTable = New cProtectedLO
With lProtectedTable
' Add the listobject to the class
Set .Table = evalListObject
' In case it's specified, add the password to the class property
If Not IsMissing(password) Then
.password = password
End If
End With
' In case sheet is protected, unprotect it
evalSheet.Unprotect password:=password
' if the listobject is not empty, unblock its cells
If Not evalListObject.DataBodyRange Is Nothing Then
evalListObject.DataBodyRange.Locked = False
End If
' Unlock cells bellow table (so user can add data and the table auto-expands
evalListObject.Range(evalListObject.Range.Rows.Count, 1).Offset(1, 0).Resize(1, evalListObject.ListColumns.Count).Locked = False
' Add the class to the collection so it remains usable
colProtectedTable.Add Item:=lProtectedTable
Next evalListObject
End If
' Protect current sheet
evalSheet.Protect password:=password, UserInterfaceOnly:=True, AllowFormattingRows:=True, AllowUsingPivotTables:=True, AllowDeletingRows:=True, AllowInsertingRows:=True
' Allow expanding grouped rows and columns
evalSheet.EnableOutlining = True
Next evalSheet
End Sub
Run the protection with:
ProtectWorkbook
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