I have an Exit button on a userform. If the user clicks it I want it to return Excel's settings to it's original values and then close the workbook. The code in the Exit button is as follows:
Unload Me
If g_Released Then
ThisWorkbook.Close savechanges:=False
End If
The code in the Workbook_BeforeClose event is:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim bSaved As Boolean
bSaved = ThisWorkbook.Saved
ActiveWindow.DisplayWorkbookTabs = True
'more code here
The last line does not cause the workbook tabs to be displayed. Further in the code I also try to set things like Application.DisplayFormulaBar = True and so forth, but none of them have any impact. It appears as if these properties has somehow been forced into a read-only state, but I don't know why.
Edit: Here is the complete code.
Private Sub Workbook_Open()
InitialiseVariables
Application.ScreenUpdating = False
HideExcelUI Application, False, True, False, "Some Company", "Budgeting Module Release 0.1", ThisWorkbook.Path & "\Logo.ico"
HideWorksheetsUI False, False, False
wsBackground.Select
With Application
.WindowState = xlNormal
.Height = frmMain.Height
.Width = frmMain.Width
End With
Application.ScreenUpdating = True
DisplayFormInCenter frmMain
End Sub
Public Sub InitialiseVariables()
g_tDBfolder = ThisWorkbook.Path & "\"
Set g_cn = New ADODB.Connection
With g_cn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Properties("Data Source") = g_tDBfolder & g_tDBname
.Open
End With
g_ScenarioIsSaved = True
g_ScenarioID = CLng([Scenario_ID])
Set g_rBudgetYear = [BudgetYear]
Set g_rStartMonth = [StartMonth]
Set g_rDealerName = [DealerName]
Set g_rScenario = [Scenario]
End Sub
Public Sub HideExcelUI(ByRef xlApp As Excel.Application, _
ByVal ShowFormulaBar As Boolean, ByVal ShowScrollBars As Boolean, ByVal ShowStatusBar As Boolean, _
Optional ByVal strApplicationCaption As String, Optional ByVal strWindowCaption As String, Optional ByVal strIcoFile As String)
With xlApp
.ExecuteExcel4Macro "SHOW.TOOLBAR(""RIBBON"",FALSE)"
.DisplayFormulaBar = ShowFormulaBar
.DisplayScrollBars = ShowScrollBars
.DisplayStatusBar = ShowStatusBar
If strApplicationCaption <> "" Then
.Caption = strApplicationCaption
End If
If strWindowCaption <> "" Then
.Windows(1).Caption = strWindowCaption
End If
If strIcoFile <> "" Then
SetIcon strIcoFile, 0
End If
End With
End Sub
Public Sub HideWorksheetsUI(ByVal ShowGridlines As Boolean, ByVal ShowHeadings As Boolean, ByVal ShowWorkbookTabs As Boolean)
Dim ws As Worksheet, wsCurrent As Worksheet
Application.ScreenUpdating = False
Set wsCurrent = ActiveSheet
For Each ws In ThisWorkbook.Worksheets
ws.Activate
With ActiveWindow
.DisplayGridlines = False
.DisplayHeadings = False
.DisplayWorkbookTabs = False
.Caption = ""
End With
Next
wsCurrent.Activate
Application.ScreenUpdating = True
End Sub
Public Sub DisplayFormInCenter(ByVal objForm As Object, Optional ByVal bModeless As Boolean)
With objForm
.startupposition = 0
.Left = Application.Left + (0.5 * Application.Width) - (0.5 * .Width)
.Top = Application.Top + (0.5 * Application.Height) - (0.5 * .Height)
If bModeless Then
.Show vbModeless
Else
.Show
End If
End With
End Sub
Private Sub ExitButton_Click()
Unload Me
If g_Released Then
ThisWorkbook.Close savechanges:=False
End If
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim bSaved As Boolean, Success As Boolean
Dim UserResponse As Long
bSaved = ThisWorkbook.Saved
ActiveWindow.DisplayWorkbookTabs = True
If g_Released Then
If Not g_ScenarioIsSaved Then
UserResponse = MsgBox(Prompt:="There are unsaved changes in the current budget. Save changes?", Buttons:=vbYesNoCancel)
If UserResponse = vbYes Then
Success = SaveInputs(ActiveSheet)
If Not Success Then
MsgBox "Unexpected error. All inputs were not saved. Please contact vendor."
End If
ElseIf UserResponse = vbNo Then
'Go ahead and close
Else
Cancel = True
End If
End If
End If
ResetIconToExcel
ThisWorkbook.Saved = bSaved
End Sub
Related
I'm beginner in VBA, I would like to know if my code is efficient. I'm wondering that is to long, maybe there is some function to save the spreadsheet?
I'm proceeding like this :
I click on the button (the code runs the Userform "Edition Fichier"), the name of this Userforme in my code is uSauvegarde.
I make my choices :
The code is :
Private Sub bParcourir_Click()
With Application.FileDialog(4)
.AllowMultiSelect = False
.Show
uSauvegarde.TextBox1 = .SelectedItems(1)
End With
End Sub
Private Sub bValider_Click()
Dim wb_Saisie As Workbook, wb_Sauv As Workbook
Dim New_Wkb As String, TableDesFeuilles() As String
Dim i As Integer, NumF As Integer
Dim S As Worksheet
Dim obj As Shape
Dim mdCalc As XlCalculation
mdCalc = Application.Calculation
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
New_Wkb = uSauvegarde.TextBox1 & "\" & uSauvegarde.TextBox2 & ".xlsx"
Set wb_Saisie = ThisWorkbook
wb_Saisie.Activate
i = 0
For Each S In wb_Saisie.Sheets
If S.Visible = True Then
ReDim Preserve TableDesFeuilles(i)
TableDesFeuilles(i) = S.Name
i = i + 1
End If
Next
Application.ScreenUpdating = False
NumF = 0
BlocageModif = True
For Each S In wb_Saisie.Sheets
If S.Visible = True Then
S.Copy
ActiveSheet.Cells.Copy
ActiveSheet.Cells.PasteSpecial xlPasteValues
If NumF = 0 Then
Set wb_Sauv = ActiveWorkbook
NumF = 1
Else
ActiveSheet.Move After:=wb_Sauv.Worksheets(NumF)
NumF = NumF + 1
End If
Range("A1").Select
For i = ActiveSheet.UsedRange.Columns.Count To 1 Step -1
If ActiveSheet.Columns(i).Hidden = True Then ActiveSheet.Columns(i).Delete
Next
For j = ActiveSheet.UsedRange.Rows.Count To 1 Step -1
If ActiveSheet.Rows(j).Hidden = True Then ActiveSheet.Rows(j).Delete
Next
For Each obj In ActiveSheet.Shapes
If obj.OnAction <> "" Then obj.OnAction = ""
Next
End If
Next S
For Each NomLocal In wb_Sauv.Names
If InStr(NomLocal.Name, "Print_") = 0 Then NomLocal.Delete
Next
wb_Sauv.SaveAs Filename:= _
New_Wkb, FileFormat:= _
xlOpenXMLWorkbook, Password:="", WriteResPassword:="", ReadOnlyRecommended:=False,
CreateBackup:=False
wb_Sauv.Close
Application.Calculation = mdCalc
Application.ScreenUpdating = True
MsgBox ("Fichier enregistré")
uSauvegarde.Hide
End Sub
Private Sub OptionButton1_Click()
With ThisWorkbook.Sheets("Feuil1")
uSauvegarde.TextBox2 = "Mon_fichier"
End With
End Sub
Private Sub OptionButton2_Click()
uSauvegarde.TextBox2 = ""
End Sub
Thank you for your help !
Your code looks good to me, but I found some things that didn't make any sense like a With that created more code or turning off Screen updating where it was already turned off. The code was difficult to read because of bad indentation and lack of descriptive variable names. This is really important when coding because is HIGHLY possible you will need to read it again to fix possible bugs or make it more efficient. I made some changes for you to review.
Option Explicit '---- always good to have
Private Sub bParcourir_Click()
With Application.FileDialog(4)
.AllowMultiSelect = False
.Show
uSauvegarde.TextBox1 = .SelectedItems(1)
End With
End Sub
Private Sub bValider_Click()
Dim wb_Saisie As Workbook, wb_Sauv As Workbook
Dim New_Wkb As String, TableDesFeuilles() As String
Dim i As Integer, NumF As Integer
Dim S As Worksheet
Dim obj As Shape
Dim mdCalc As XlCalculation
mdCalc = Application.Calculation
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
New_Wkb = uSauvegarde.TextBox1 & "\" & uSauvegarde.TextBox2 & ".xlsx"
Set wb_Saisie = ThisWorkbook
wb_Saisie.Activate
i = 0
For Each S In wb_Saisie.Sheets
If S.Visible = True Then
ReDim Preserve TableDesFeuilles(i)
TableDesFeuilles(i) = S.Name
i = i + 1
End If
Next
'Application.ScreenUpdating = False ---- why disable "screen updating" again?
NumF = 0
BlocageModif = True
With ActiveSheet '----- a "With" here is a good idea
For Each S In wb_Saisie.Sheets
'If S.Visible = True Then
If S.Visible Then '------- the if statement above can be written like this
S.Copy
.Cells.Copy
.Cells.PasteSpecial xlPasteValues
If NumF = 0 Then
Set wb_Sauv = ActiveWorkbook
NumF = 1
Else
.Move After:=wb_Sauv.Worksheets(NumF)
NumF = NumF + 1
End If
Range("A1").Select
For i = .UsedRange.Columns.Count To 1 Step -1
If .Columns(i).Hidden Then
t.Columns(i).Delete
End If
Next
For j = .UsedRange.Rows.Count To 1 Step -1
If .Rows(j).Hidden Then
.Rows(j).Delete
End If
Next
For Each obj In .Shapes
If obj.OnAction <> "" Then
obj.OnAction = ""
End If
Next
End If
Next S
End With
For Each NomLocal In wb_Sauv.Names
If InStr(NomLocal.Name, "Print_") = 0 Then NomLocal.Delete
Next
'------ this section of the code has problems.. check it out
wb_Sauv.SaveAs Filename:= _
New_Wkb, FileFormat:= _
xlOpenXMLWorkbook, Password:="", WriteResPassword:="", ReadOnlyRecommended:=False,
CreateBackup:=False
wb_Sauv.Close
Application.Calculation = mdCalc
Application.ScreenUpdating = True
'MsgBox ("Fichier enregistré") '----- parenthesis are nor necessary
MsgBox "Fichier enregistré"
uSauvegarde.Hide
End Sub
Private Sub OptionButton1_Click()
'With ThisWorkbook.Sheets("Feuil1") ---- this "With" creates more code...
'uSauvegarde.TextBox2 = "Mon_fichier"
'End With
ThisWorkbook.Sheets("Feuil1").uSauvegarde.TextBox2 = "Mon_fichier"
End Sub
Private Sub OptionButton2_Click()
uSauvegarde.TextBox2 = ""
End Sub
enter image description hereI have a spreadsheet that has 3 checkbox options for each row, I have created a VBA to disable the other 2 checkboxes once a checkbox is created (so that only 1 checkbox can be checked), however my solution only works for one row and I need some help in rewriting this so that it will apply to all rows please. (I'm new to VBA).
The code I have used is this:
Private Sub CheckBox1_Click()
If CheckBox1.Value = True Then
CheckBox2.Value = False
CheckBox2.Enabled = False
CheckBox3.Value = False
CheckBox3.Enabled = False
Else
CheckBox2.Value = False
CheckBox2.Enabled = True
CheckBox3.Value = False
CheckBox3.Enabled = True
End If
End Sub
Private Sub CheckBox2_Click()
If CheckBox2.Value = True Then
CheckBox1.Value = False
CheckBox1.Enabled = False
CheckBox3.Value = False
CheckBox3.Enabled = False
Else
CheckBox1.Value = False
CheckBox1.Enabled = True
CheckBox3.Value = False
CheckBox3.Enabled = True
End If
End Sub
Private Sub CheckBox3_Click()
If CheckBox3.Value = True Then
CheckBox1.Value = False
CheckBox1.Enabled = False
CheckBox2.Value = False
CheckBox2.Enabled = False
Else
CheckBox1.Value = False
CheckBox1.Enabled = True
CheckBox2.Value = False
CheckBox2.Enabled = True
End If
End Sub
You should probably just use Radios it would be a lot simpler.
If you are intent on doing this you will need to delete all your boxes and then put this code in. It will create and name your boxes and assign them code on click.
Alright, This needs to go in your Sheet module:
Sub Worksheet_Activate()
'Change Module2 to whatever the module name you are using is.
Module2.ActivateCheckBoxes ActiveSheet
End Sub
This next stuff will go into the module you're referencing from the Worksheet Module.
Sub ActivateCheckBoxes(sht As Worksheet)
If sht.CheckBoxes.Count = 0 Then
CreateCheckBoxes sht
End If
Dim cb As CheckBox
For Each cb In sht.CheckBoxes
'You may be able to pass sht as an object, It was giving me grief though
cb.OnAction = "'Module2.CheckBoxClick """ & cb.name & """, """ & sht.name & """'"
Next cb
End Sub
Sub CreateCheckBoxes(sht As Worksheet)
Dim cell As Range
Dim chkbox As CheckBox
With sht
Dim i As Long
Dim prevrow As Long
prevrow = 0
For Each cell In .Range("B2:D5") 'Change this to whatever range you want.
If prevrow < cell.row Then
prevrow = cell.row
i = 0
End If
Set chkbox = .CheckBoxes.Add(cell.Left, cell.Top, 30, 6)
With chkbox
.name = "CheckBox" & i & "_" & cell.row
.Caption = ""
End With
i = i + 1
Next cell
End With
End Sub
Sub CheckBoxClick(chkname As String, sht As String)
Dim cb As CheckBox
With Worksheets(sht)
For Each cb In .CheckBoxes
If Split(cb.name, "_")(1) Like Split(chkname, "_")(1) And Not cb.name Like chkname Then
cb.Value = -4146
End If
Next cb
End With
End Sub
You do not say anything about your sheet check boxes type... Please, test the next solution. It will be able to deal with both sheet check boxes type:
Copy this two Subs in a standard module:
Public Sub CheckUnCheckRow(Optional strName As String)
Dim sh As Worksheet, s As CheckBox, chK As OLEObject ' MSForms.CheckBox
Set sh = ActiveSheet
If strName <> "" Then
Set chK = sh.OLEObjects(strName) '.OLEFormat.Object
solveCheckRow chK.Object.Value, sh, Nothing, chK
Else
Set s = sh.CheckBoxes(Application.Caller)
solveCheckRow s.Value, sh, s
End If
End Sub
Sub solveCheckRow(boolVal As Long, sh As Worksheet, chF As CheckBox, Optional chK As OLEObject)
Dim s As CheckBox, oObj As OLEObject, iCount As Long
If Not chF Is Nothing Then
For Each s In sh.CheckBoxes
If chF.TopLeftCell.Address <> s.TopLeftCell.Address Then
If s.TopLeftCell.Row = chF.TopLeftCell.Row Then
s.Value = IIf(boolVal = -4146, 1, -4146): iCount = iCount + 1
If iCount = 2 Then Exit Sub
End If
End If
Next
ElseIf Not chK Is Nothing Then
For Each oObj In sh.OLEObjects
If oObj.TopLeftCell.Address <> chK.TopLeftCell.Address Then
If oObj.TopLeftCell.Row = chK.TopLeftCell.Row Then
boolStopEvents = True
oObj.Object.Value = IIf(boolVal = 0, True, False): iCount = iCount + 1
boolStopEvents = False
If iCount = 2 Then Exit Sub
End If
End If
Next
End If
End Sub
For case of Form check boxes type:
a). Manually assign the first sub to all your Form Type check boxes (right click - Assign Macro, choose CheckUnCheckRow and press OK).
b). Automatically assign the macro:
Dim sh As Worksheet, s As CheckBox
Set sh = ActiveSheet ' use here your sheet keeping the check boxes
For Each s In sh.CheckBoxes
s.OnAction = "'" & ThisWorkbook.Name & "'!CheckUnCheckRow"
Next
End Sub
If your check boxes have already assigned a macro, adapt CheckUnCheckRow, in Form check boxes section, to also call that macro...
For case of ActiveX check boxes:
a). Create a Public variable on top of a standard module (in the declarations area):
Public boolStopEvents
b). Manually adapt all your ActiveX check boxes Click or Change event, like in the next example:
Private Sub CheckBox1_Click()
If Not boolStopEvents Then CheckUnCheckRow "CheckBox1"
End Sub
Private Sub CheckBox2_Click()
If Not boolStopEvents Then CheckUnCheckRow "CheckBox2"
End Sub
Private Sub CheckBox3_Click()
If Not boolStopEvents Then CheckUnCheckRow "CheckBox3"
End Sub
and so on...
c). Or do all that with a click, using the next piece of code:
Sub createEventsAllActiveXCB()
Dim sh As Worksheet, oObj As OLEObject, strCode As String, ButName As String
Set sh = ActiveSheet 'use here your sheet keeping ActveX check boxes
For Each oObj In sh.OLEObjects
If TypeName(oObj.Object) = "CheckBox" Then
ButName = oObj.Name
strCode = "Private Sub " & ButName & "_Click()" & vbCrLf & _
" If Not boolStopEvents Then CheckUnCheckRow """ & ButName & """" & vbCrLf & _
"End Sub"
addClickEventsActiveXChkB sh, strCode
End If
Next
End Sub
Anyhow, the code cam be simplified in order to deal with only a type of such check boxes. If you intend to use it and looks too bushy, I can adapt it only for the type you like. Like it is, the code deals with both check box types, if both exist on the sheet...
Save the workbook and start playing with the check boxes. But, when you talk about check boxes on a row, all tree of them must have the same TopLeftCell.Row...
I have one sheet ("Settings"), which needs to be hidden most of the time. I have created Settings UserForm which contains various settings buttons and toggle button in there hides/show that hidden sheet (then clicked and password is entered).
Macro for hiding/showing sheet:
Private Sub SettingsTB_Click()
Dim strPassTry As String
Dim strPassword As String
Dim lTries As Long
Dim bSuccess As Boolean
If SettingsTB.Value = True Then
strPassword = "asd"
For lTries = 1 To 3
strPassTry = InputBox("Enter password", "Show Settings sheet")
If strPassTry = vbNullString Then Exit Sub
bSuccess = strPassword = strPassTry
If bSuccess = True Then Exit For
MsgBox "Incorrect password"
Next lTries
If bSuccess = True Then
Worksheets("Settings").Visible = True
End If
Else
Worksheets("Settings").Visible = xlSheetHidden
End If
End Sub
That macro works as intended, problem arises then I open UserForm and "Settings" Sheet is left visible. UserForm_Initialize event triggers SettingsTB_Click event (ask for entering password).
Code in UserForm_initialize used for remembering toggle button position (without it, every time, UserForm is opened, toggle button in FALSE possition):
Private Sub UserForm_Initialize()
If Worksheets("Settings").Visible = True Then
SettingsTB.Value = True
Else
SettingsTB.Value = False
End If
End Sub
Is it possible to stop SettingsTB_Click from triggering on UserForm_Initialize or should I use completely different approach?
Use a public variable or the tag-property to stop the click-event from running.
Private Sub SettingsTB_Click()
Dim strPassTry As String
Dim strPassword As String
Dim lTries As Long
Dim bSuccess As Boolean
If SettingsTB.Tag Then Exit Sub
If SettingsTB.Value = True Then
strPassword = "asd"
For lTries = 1 To 3
strPassTry = InputBox("Enter password", "Show Settings sheet")
If strPassTry = vbNullString Then Exit Sub
bSuccess = strPassword = strPassTry
If bSuccess = True Then Exit For
MsgBox "Incorrect password"
Next lTries
If bSuccess = True Then
Worksheets("Settings").Visible = True
End If
Else
Worksheets("Settings").Visible = xlSheetHidden
End If
End Sub
Private Sub UserForm_Initialize()
SettingsTB.Tag = True
If Worksheets("Settings").Visible = True Then
SettingsTB.Value = True
Else
SettingsTB.Value = False
End If
SettingsTB.Tag = False
End Sub
I am using this code to password protect two pages.
For some weird reason I can hide "Sheet1" but not "Sheet2" as its always visiable.
The reason for the line Sheets(MySheet2).Visible = True is so if someone puts in the wrong password it won't just hide it instantly.
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim MySheets As String, Response As String
MySheet = "Sheet1"
MySheet2 ="Sheet2"
If ActiveSheet.Name = MySheet Then
ActiveSheet.Visible = False
Response = InputBox("Enter password to view sheet")
If Response = "MyPass" Then
Sheets(MySheet).Visible = True
Application.EnableEvents = False
Sheets(MySheet).Select
Application.EnableEvents = True
End If
End If
Sheets(MySheet).Visible = True
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If ActiveSheet.Name = MySheet2 Then
ActiveSheet.Visible = False
Response = InputBox("Enter password to view sheet")
If Response = "MyPass" Then
Sheets(MySheet2).Visible = True
Application.EnableEvents = False
Sheets(MySheet2).Select
Application.EnableEvents = True
End If
End If
Sheets(MySheet2).Visible = True
End Sub
I guess you're after this:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Dim MySheets As String, Response As String
With ActiveSheet
Select Case .Name
Case "Sheet1", "Sheet2"
Application.EnableEvents = False
.Visible = False
Response = InputBox("Enter password to view sheet")
If Response = "MyPass" Then
.Visible = True
.Select
End If
Application.EnableEvents = True
End Select
End With
End Sub
as you should already know, this code is to be placed in ThisWorkbook code pane
I use a macro to automatically compress pictures in Excel 2010, the macro opens a dialog and sendkeys, and final users can see it (for half a second), i want to hide it. Please help !
This is my macro:
Sub compression()
Application.SendKeys "%w~"
Application.CommandBars.ExecuteMso "PicturesCompress"
End Sub
I already tried:
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
But they don't seem to work.
#TomPreston
Here's my whole code, i want users to double click on type of cells to insert pictures in comments but the pictures must be compressed to keep the file fit !
I ALSO have problems with sendkeys and num lock, if someone can help me on this (see below):
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Not Intersect(Target, [v:v]) Is Nothing Then
Application.ScreenUpdating = False
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
.InitialFileName = CurDir
.Filters.Clear
.Filters.Add Description:="Images", Extensions:="*.png;*.jpg;*.jpeg;*.gif", Position:=1
.Title = "Choose image"
If .Show = -1 Then TheFile = .SelectedItems(1) Else TheFile = 0
End With
If TheFile = 0 Then
MsgBox ("No image selected")
Exit Sub
End If
ActiveCell.ClearComments
Selection.AddComment
PreviousCell = ActiveCell.Address
ActiveCell.Comment.Shape.Fill.UserPicture TheFile
NumLockState = GetKeyState(VK_NUMLOCK)
Application.SendKeys "%a~"
Application.CommandBars.ExecuteMso "PicturesCompress"
If NumLockState <> GetKeyState(VK_NUMLOCK) Then
Application.SendKeys ("%{Numlock}"), True
End If
ActiveCell.Comment.Visible = True
CommentAdded = True
Application.ScreenUpdating = True
End If
End Sub
Users can change de size of the picture and after the selection change, the comment is hidden.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If CommentAdded = True Then
Range(PreviousCell).Comment.Visible = False
PreviousCell = ""
CommentAdded = False
End If
End Sub
And these are the variables:
Public CommentAdded As Boolean
Public PreviousCell As String
Public Const VK_NUMLOCK = &H90
Public Declare Function GetKeyState Lib "user32" _
(ByVal nVirtKey As Long) As Long
If you just want to hide the flicker effect, use this:
Sub compression()
Application.ScreenUpdating = False
Application.SendKeys "%w~" Application.CommandBars.ExecuteMso "PicturesCompress"
Application.ScreenUpdating = True
End Sub