How do I hide a sheet with a button in Excel? - vba

I would like to create a button to hide the sheet. Ideally, it would hide the sheet where the button is located.
To be simple, sheet 1 has a form to fill out. The typical name, address, phone number, etc. Sheet 2 and 3 also have the same fields that is going to be referenced to the 'Data' tab as well. On a sheet named 'Data', I will add fields that will populate simply with the = option like (=Data!...)
However, I do not want the Data page in view once the information is added. We all know the simple right click and hide sheet. But sometimes that's too much for some people that will use this sheet and a pretty button would work better.
I was successful using:
Module 1
Sub SheetCommand()
If Worksheets("Sheet1").Range("C2").Value <> vbNullString Then
Worksheets("Sheet2").Visible = False
Else
Worksheets("Sheet2").Visible = True
End If
End Sub
Sheet1 Code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address <> "$C$2" Then Exit Sub
Run "SheetCommand"
End Sub
However, I am not very VB savvy and have hit a dead end. Could someone help show me how to apply this to a button? I don't want it to reference the $C$2 field as noted on the example, but just when someone presses the button, the sheet goes away. I'm not worried about getting it back as someone can be ready to get it the old fashioned way. This would help the data entry process for this manual form so much easier.
Edit: basically, I need help creating a vba code where I can hide the page. I'd like to create a button where once clicked, it hides that page. I showed an example of a code where I got it to work but it only works if that cell is populated. How do I make it work on button click?
I found this code that does what I need but I would like to tell it a specific Sheet Name instead of having to type it in B6 and B7.
Sub ShowHideWorksheets()
Dim Cell As Range
For Each Cell In Range("B6:B7")
ActiveWorkbook.Worksheets(Cell.Value).Visible = Not
ActiveWorkbook.Worksheets(Cell.Value).Visible
Next Cell
End Sub

It's actually not very clear to me what's your exact goal
for instance, assuming "Sheet 2" and "Sheet2" would point to the same sheet, in your question you seem to reference it as being both a "Form" sheet ("...sheet 1 has a form to fill out....Sheet 2 and 3 also have the same fields...") and "Data" sheet (Worksheets("Sheet2").Visible = False)
so here follow some possible solutions:
1) you want to hide "Data" sheet before closing the workbook it's contained in
then place the following code in "ThisWorkbook" code pane of the workbook containing "Data" sheet
Private Sub Workbook_BeforeClose(Cancel As Boolean)
ThisWorkbook.Worksheets("Data").Visible = False
End Sub
2) you want to hide "Data" sheet once some cells have been filled up in ANY sheet other than "Data"
then place the following code in "ThisWorkbook" code pane of the workbook containing "Data" sheet
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Sh.Name <> "Data" Then
With Sh
'here follows code to check if "the information is added"
'for instance:
If WorksheetFunction.CountA(.Range("A2:C2")) = .Range("A2:C2").Count Then ThisWorkbook.Worksheets("Data").Visible = False 'check if all cells in range "A2" to "C2" has been filled with some data
End With
End If
End Sub
3) you want to hide "Data" sheet once some cells have been filled up in ALL sheets other than "Data"
then place the following code in "ThisWorkbook" code pane of the workbook containing "Data" sheet
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim sht As Worksheet
Dim hideBool As Boolean: hideBool = True 'set initial value as true
If Sh.Name <> "Data" Then
For Each sht In ThisWorkbook.Worksheets
With Sh
'here follows code to check if "the information is added"
'for instance:
hideBool = hideBool And WorksheetFunction.CountA(.Range("A2:C2")) = .Range("A2:C2").Count ''check if all cells in range "A2" to "C2" of current sheet has been filled with some data
End With
If Not hideBool Then Exit For
Next sht
ThisWorkbook.Worksheets("Data").Visible = Not hideBool ' hide if ALL sheets met "information is added" condition
End If
End Sub
4) otherwise give more info about the desired behavior

Related

Dynamically protect sheet from accidental deletion in Excel

I am trying to put a dynamic protection on the sheets in my workbook. I have many different sheets and sometimes I delete a sheet that I still need by accident.
If Cell OP15 contains a value, this means I am okay to delete the sheet to clean up my workbook. How do I create a protection for the sheets that only lets me delete it if Cell OP15 contains a value?
The closest thing I can find on the internet is something along these lines:
ActiveSheet.Unprotect
' your vba code here
ActiveSheet.Protect
The .BeforeDelete does not have a cancel, so you can't stop them deleting the sheet.
from this website, you can copy the sheet, and save it from deletion that way. You could use this routine to decide if you need to save the sheet from deletion or not:
Private Sub Worksheet_BeforeDelete()
Dim MyName As String
'Abort if no value in OP15
if [OP15].value<>'' then exit sub
‘Capture the original worksheet name
MyName = ThisWorkbook.ActiveSheet.Name
‘Rename the worksheet
ThisWorkbook.ActiveSheet.Name = Left(MyName, 30) + “#”
‘Create a copy of the worksheet
ThisWorkbook.ActiveSheet.Copy _
After:=Sheets(ThisWorkbook.ActiveSheet.Index)
‘Name the copy to the original name
ThisWorkbook.ActiveSheet.Name = MyName
End Sub
This code is pasted into the sheet code for my admin template. Cell A1 is hardcoded to say "admin template". When the template is copied Cell A1 changes to the name of the new tab.
Option Explicit
Private Sub Worksheet_Deactivate()
'This sub prevents acidental deletion of tab until it has been hardcoded
If Range("a1").Value = "admin template Ticket Info" Then
ThisWorkbook.Protect , False
Exit Sub
End If
If Range("OP15").Value <> "" Then
MsgBox "Cannot delete tab until the Onboarding details have been hardcoded."
Exit Sub
End If
ThisWorkbook.Protect , True
Application.OnTime Now, "Unprotectbook"
End Sub
This is copied into one of the modules
Sub UnprotectBook()
ThisWorkbook.Unprotect
End Sub

VBA - Filling a cell value after a combobox text is entered/changed

I have the following piece of code on my workbook on my sheet, which is intended to test intersection using ws change and then go to the combo box and retrieve whatever value is entered in the box. However, what is happening is that after the value is entered in the combo box the first time the cell isn't updating with it's value. I have to click it again, and then it will populate. I know I have to likely use another event procedure, but I have no clue about combo box events. Can someone point me in the right direction?
Thx Mike.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim aRng As Range
Dim tRng As Range
Set aRng = Range("C19:C36")
Set tRng = Sheet2.Range("I2")
Application.EnableEvents = False 'to prevent re-iteration of event
On Error GoTo cleanup:
If Not Intersect(aRng, Target) Is Nothing Then
Call Sheet2.ComboBox1_Change
Target.Value = Sheet2.ComboBox1.Value
End If
cleanup: 'enable events once again
Application.EnableEvents = True
End Sub
and on Sheet 2 where the box is.
Public Sub ComboBox1_Change()
With ComboBox1
.Activate
.SelText = Empty
.DropDown
.MatchRequired = True
End With
End Sub
To get to the basics of your question, the Combobox has a LinkedCell property. If you enter the cell address on Sheet1 there, the selected item in the ComboBox will be displayed on Sheet1. (If a value is entered in that Cell on Sheet1, it will also be displayed in the ComboBox.)
ComboBox LinkedCell
You can force Sheet1 to be displayed after a selection is made in the ComboBox with this code (in the module of Sheet2):
Private Sub ComboBox1_Change()
Sheet1.Select
End Sub
Using Worksheet_Change will only have effect AFTER something has been entered into the cell (and RETURN has been hit).

Creating a Sheet List using Listbox

In a User form using a Listbox1 I would like to make a list of the Opened Workbooks and in the Listbox2 in the same form the sheets of the selected workbook in the listbox1 But also in the lisbox2 I would like to create with each sheet name a checkbox with five command buttons in the form to import, Export, Erase, Hide or Unhide the selected sheets from Wb1 to Wb2 and vice versa.
So far I receive assistance from you guys to make a do a form with a list of opened workbooks and a list of the respective worksheets here also I'm trying to get to work a code to import the sheets from one workbook to another here,. Do you know a Way to make this happen.
thank You
By the way this is the code use from a sheet to erase the sheets that might be put in the list
Sub DeleteSheets()
Dim wks As Worksheet
Dim MyRange As Range
Dim cell As Range
Set wks = Worksheets("Controls")
With wks
Set MyRange = Range("D5:D34", .Cells(.Rows.Count, "H").End(xlUp))
End With
On Error Resume Next
Application.DisplayAlerts = False
For Each cell In MyRange
Sheets(cell.Value).Delete
Next cell
Application.DisplayAlerts = True
On Error GoTo 0
Sheets("Controls").Range("D5:D34").ClearContents
End Sub
And this ones for hide and unhide the sheets:
Sub Hide_Sheets()
'In use
'Hide the sheets in Controls Sheet
Dim cell As Range
On Error Resume Next
For Each cell In Sheets("Controls").Range("E5:E34")
' Hide sheets
Sheets(cell.Value).Visible = False
Next cell
End Sub
Sub Unhide_Sheets()
'In use
'Unhide the sheets in Controls Sheet
Dim cell As Range
On Error Resume Next
For Each cell In Sheets("Controls").Range("G5:G34")
' Hide sheets
Sheets(cell.Value).Visible = True
Next cell
End Sub
I suggest the following structure of your userform:
Since you do what two lists one with workbooks and one with the worksheets of the currently selected workbook. Then you want to have five command buttons for the actions you want to perfom.
In order to update the workbooks and worksheets you will want to place code in the userform inside the Userform_activate and Listbox1_Change events. So You get the code to list all the workbook names into the listbox1 and put it into Userform_Activate. Evertime the userform is activated the list of workbooks will be updated.
If you now select a entry of listbox1 you want the code to update your sheet names. So you get the code to update the sheet names of a workbook with name "wbname" and put it into listbox1_Change. You then do the following code:
Private Sub ListBox1_Change()
Dim wbname as string
wbname=ListBox1.Value
call GetSheetNamesIntoListBox2(wbname)
End Sub
Where of course GetSheetNamesIntoListBox2 is the sub were you get all the sheetnames into ListBox2.
Lastly you need to setup the Buttons. Each Button has a Click Event which you will want to use. So if the Button is clicked the following code will run:
Private Sub CommandButton1_Click()
Dim wbname as string, wsname as string
wbname=Listbox1.Value
wsname=Listbox2.Value
' You may want to check if wbname and wsname are valid before running the Task
PerformAction(wbname,wsname)
End Sub
Where PerformAction is the routine you use to import, export, clear, hide or unhide the sheet.
I know it is no workedout solution but you will be able to adjust this general solution to your specific case. If you run into problems using my approach just ask in the comments.

Change active sheetname based on a cell value of that sheet automatically

I found this code on google which can help me to change current tab name based on a cell value of this sheet. However, I have to run this macro code manually each time. How can I modify this code to make it change automatically after entering value in a cell or at least tab's name changes as typing. Here is the code:
Sub myTabName()
ActiveSheet.Name = ActiveSheet.Range("C3")
End Sub
place this in the sheet code pane
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address(False, False) = "C3" Then ActiveSheet.name = ActiveSheet.Range("C3")
End Sub

VBA causing typed information to go to an incorrect worksheet

I am creating a spreadsheet that creates a reference number on the first worksheet (called database, to be used similarly to a database) and generates a new worksheet. This then gives a reference number on the new worksheet so that they are linked together. This is done by pressing "New Idea" on a UserForm.
Once this is completed it should then go to the newly created worksheet and highlight cell C7. Once this is complete it should close the UserForm and allow the user to be able to type in cell C7 on the new worksheet with no further steps needed.
This works fine if I use F8 to step through the process however if I close the code window and run through the process as a user would it doesn't work as it should.
C7 is highlighted but once you have typed in it and press enter to go to the cell below, what you've typed disappears completely, and whatever you type on the newly generated worksheet is actually entered on another worksheet.
I have a seperate worksheet that contains a button to open the UserForm and all data that is entered on the newly generated worksheet goes to this sheet incorrectly.
My code is below, and is all within the UserForm's code. I have left the ComboBox code below but this isn't relevant to the generation of the new worksheets. All that does is list the created tabs so the user can select a worksheet from the UserForm and go directly there rather than having to scroll sideways.
I'm using Excel 2013. I'm by no means a VBA veteran so any help would be greatly appreciated!
Thanks!
Private Sub UserForm_Initialize()
Me.ComboBox1.List = Worksheets("Database").Range("A2:A10000").Value
End Sub
Private Sub CreateNewIdea_Click()
CopySheet
End Sub
Sub CopySheet()
Dim LastRow As Long
NewReference
LastRow = Sheets("Database").Range("A" & Rows.Count).End(xlUp).Row - 1
ReturnValue = LastRow
Sheets("Idea Template").Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = LastRow
Range("C3").Value = LastRow
Me.ComboBox1.List = Worksheets("Database").Range("A2:A10000").Value
Range("C7").Select
Unload Home
End Sub
Sub NewReference()
Dim LastRow As Long
LastRow = Sheets("Database").Range("A" & Rows.Count).End(xlUp).Row
Sheets("Database").Cells(LastRow + 1, "A").Value = Sheets("Database").Cells(LastRow, "A").Value + 1
End Sub
Private Sub ComboBox1_Change()
Worksheets(ComboBox1.Text).Select
End Sub
I've taken the liberty to edit and rewrite the code you've written for greater flexibility.
Option Explicit 'Forces the variable to be declared, undeclared variables are not allowed
Dim DatabaseTable As ListObject 'Makes the variable usable for the entire module
Dim Lastrow As Long
Private Sub UserForm_Initialize()
Set DatabaseTable = ThisWorkbook.Worksheets("Database").ListObjects("References")
'I'm assuming you've formatted the data on the worksheet as a table and named the table "References"
Dim i As Long
Dim DatabaseRows As Long
DatabaseRows = DatabaseTable.ListRows.Count
With Me.ComboBox1
.Value = Empty
.Clear
For i = 1 To DatabaseRows
.AddItem DatabaseTable.DataBodyRange(i, 1)
Next i
End With
End Sub
Private Sub CreateNewIdea_Click()
Set DatabaseTable = ThisWorkbook.Worksheets("Database").ListObjects("References")
Call CopySheet
End Sub
Sub CopySheet() 'Are you calling Sub CopySheet() from other subs besides Private Sub CreateNewIdea_Click()?
Call NewReference
Dim ReturnValue As Long 'I'm declaring this variable because I'm using the option explicit and that doesn't allow undeclared variables
ReturnValue = Lastrow 'Unless ReturnValue is a public variable, it's not doing much here.
ThisWorkbook.Worksheets("Idea Template").Copy After:=ThisWorkbook.Worksheets(Worksheets.Count)
ThisWorkbook.Worksheets("Idea Template (2)").name = Lastrow
ThisWorkbook.Worksheets(CStr(Lastrow)).Cells(1, 3).Value = Lastrow 'Cstr(lastrow) is needed because we want the sheet with the name of the last row, not the nth sheet which is what happens with WorkSheets(Lastrow) as lastrow is a number
Call UserForm_Initialize 'Calls the procedure which fills ComboBox1, if the unload home refers to this form, then this line is redundant since the combobox is filled again when the form is initialized.
ThisWorkbook.Worksheets(CStr(Lastrow)).Cells(7, 3).Select
Unload Home 'If the name of this form is home, you can just 'Unload Me'
End Sub
Sub NewReference() 'Are you calling Sub NewReference from other subs besides Sub CopySheet()?
DatabaseTable.ListRows.Add AlwaysInsert:=False 'Adds a new row to the table on the worksheet "Database"
Lastrow = DatabaseTable.ListRows.Count
If Lastrow = 2 And IsEmpty(DatabaseTable.DataBodyRange(1, 1)) Then 'This if determines if a row was added while the first row does not contain a reference
DatabaseTable.DataBodyRange(Lastrow, 1).Value = 1 'First reference, can be anything you want really
DatabaseTable.ListRows(1).Delete 'First row is deleted, otherwise you'd have an empty first row
Lastrow = Lastrow - 1
Else
DatabaseTable.DataBodyRange(Lastrow, 1).Value = DatabaseTable.DataBodyRange(Lastrow - 1, 1) + 1
End If
End Sub
Private Sub ComboBox1_Change()
If Not Me.ComboBox1 = Empty Then
Worksheets(CStr(Me.ComboBox1)).Select
End If
End Sub
Revised answer
After looking at the document provided by #tomjo and trying to reporduce the problem I found that the problem was caused by the buttons on the sheets. The buttons used were the Form Controls rather than ActiveX Controls.
A macro was assigned to the Form Control The macro was defined in a module as you'd expect. The Macro only called to show the relevant form. It appeared as if the selected sheet, either by the menu on the form or after creating a new sheet from the form wasn't properly activated and the information entered in the sheet that showing was actually entered in the form which was last manually selected. Stepping through the code I found that the proper sheet and cell was active after the selection through the form through Debug.Print ThisWorkbook.ActiveSheet.Name, ThisWorkbook.ActiveSheet.ActiveCell.Address. I failed to discover why, while the correct sheet and cell were active, the information was entered in the last manually selected worksheet and cell.
To verify that the issue was not caused by the file somehow I tried to reproduce the problem with an entirely new file. Again the problem occurred that while the screen was showing the correct sheet and cell as selected (selected through a form, called by a sub in a module, called by a Form Control) the information was actually entered in the last manually selected sheet and cell.
----Edit----
Running the Showform macro (which calls the form to show) from the Macros button under the developer tab in the ribbon, instead of clicking the Form control button which has the ShowForm macro assigned to it, doesn't create the issue.
----End of Edit----
I then only removed the Form control, and the sub in the module which calls to show the form and placed an ActiveX Control (CommandButton) on the sheet and on the relevant Sheet module created:
Private Sub CommandButton1_Click()
Form.Show
End Sub
Without editing the code any further, there were no further issues regarding information being entered on the last manually selected sheet and cell instead of the sheet and cell the screen was showing as selected.
Edited file (The link will be active for a limited time)