I want to keep a variable from Form to Workbook Events, it works from Form to Module, but doesn't work from Form to Workbook Event, the Variable "Salvar" stay as "Empty" rather than "True"...
'WorkBook Event
Public Salvar As Boolean
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
UserForm_Salvar.Show 'Calls "Private Sub Botao_Salvar_Click()"
If SaveAsUI = True Then
If Salvar = True Then
Cancel = False
Salvar = False
Else
Cancel = True
End If
End If
End Sub
'UserForm
Private Sub Botao_Salvar_Click()
Dim PassWord As Variant
PassWord = Senha_TextBox
If PassWord = 123 Then
Unload UserForm_Salvar
Salvar = True
End If
End Sub 'Go back to "Workbook_BeforeSave"
You don't really need a global variable if you declare the form as an object, which is the better practice anyway, and then handle it correctly. Use any of the form's properties or the form's controls' properties to convey the message. I recommend to use the Tag property. Here is the code in the worksheet's module. Observe that I named the form FrmSalvar.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
' 091
Dim Form As FrmSalvar
If SaveAsUI = True Then
Set Form = New FrmSalvar ' create a new instance of the form
With Form
.Show ' the Form takes control
' code resumes here with Form hidden but still in memory
Cancel = (Val(.Tag) <> True) ' True = -1
End With
Unload Form ' only now the form is destroyed
Set Form = Nothing
End If
End Sub
and the code in the Form's code sheet.
Private Sub Botao_Salver_Click()
' 091
Dim PassWord As String ' Textboxes handle text = strings
PassWord = Senha_TextBox.Value ' this is a string, even if numeric
If PassWord = "123" Then
Me.Tag = -1 ' write something to the Tag property
Else
MsgBox "The password is incorrect", vbInformation, "Access denied"
End If
Me.Hide ' hide the form
End Sub
The line Cancel = (Val(.Tag) <> True) in the BeforeSave procedure will crash if the user closed the form using the X button. This is because that button effectively unloads the form before your code can do it. In your system, that action should be paramount to "no password". Therefore this code will remedy the situation.
On Error Resume Next
Cancel = (Val(.Tag) <> True)
If Err.Number Then Cancel = True
That's a more dignified exit than gathering your skirts and fleeing the scene in panic. However, there is also a method by which you can simply not allow the form to be closed that way. I use the two event procedures below in most of my forms.
Private Sub CmdCancel_Click()
' 091
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
' 091
Cancel = (CloseMode <> vbFormCode)
If Cancel Then CmdCancel_Click
End Sub
Read up about the QueryClose event here. In its above incarnation it just cancels what the user pressed and suggests alternative code which could be simply Me.Hide. I have Me.Hide in the procedure that responds to the Cancel button on my form and I rather invoke that procedure than allowing a second cancel exit from the form in my code. In this way there are just two exits from my form, with OK or with Cancel. Pressing the X is handled in the same way as when Cancel was pressed. Either way, the Me.Tag is preserved until the bitter end.
Change the value of Salvar before Unloading the UserForm.
If PassWord = 123 Then
Salvar = True
Unload UserForm_Salvar
End If
Related
I have a command button to save an Excel workbook in a particular format.
I want that the users are unable to save the workbook unless they click that command button.
To prevent the use of traditional saving options I used the code below:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
MsgBox "You can't save this workbook!"
Cancel = True
End Sub
How do I prevent traditional saving options but allow saving if the command button is clicked?
You can have a boolean flag to indicate whether or not saving is allowed and only set it to true when you call the macro that contains your logic for saving the workbook.
Add the following code under ThisWorkbook:
Public AllowSave As Boolean
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Not AllowSave Then
MsgBox "You can't save this workbook!"
Cancel = True
End If
End Sub
Public Sub CustomSave()
ThisWorkbook.AllowSave = True
' TODO: Add the custom save logic
ThisWorkbook.SaveAs '....
MsgBox "The workbook has been saved successfully.", , "Workbook saved"
ThisWorkbook.AllowSave = False
End Sub
Note that you'll need to assign the CustomSave macro to the button that will be initiating the custom save.
Demo:
I want to click in a certain cell and for the Userform with the Monthview to appear , then once I have selected a date and it is inserted into the cell, i want the userform to close automatically
This code is in Work Sheet
Private Sub worksheet_selectionchange(ByVal target As Range)
If Not Application.Intersect(Range("l14"), target) Is Nothing Then
UserForm1.Show
End If
End Sub
This code is in the UserForm - MonthView1
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
ActiveCell.Value = DateClicked
End Sub
Any assistance would be Grateful
UserForm1.Show is toxic; you're essentially storing state in global scope, and that will inevitably cause issues down the line. Make a new instance of the form instead:
If Not Application.Intersect(Range("l14"), target) Is Nothing Then
With New UserForm1
.Show
End With
End If
Now, a form/dialog exists to collect user input, not to consume that input and change cell values. What happens to that input should be up to the code that's using that form, not up to the form itself. Expose the selected Date value with a property.
The user can do 2 things: either they select a date and you have a SelectedDate, or they clicked that [X] button and dismissed the form: You need to be able to tell what the user did. Handle QueryClose for that, and expose an IsCancelled property.
Selecting a date, or cancelling out, should hide the form, not destroy it.
Option Explicit
Private selectedValue As Date
Private cancelled As Boolean
Public Property Get IsCancelled() As Boolean
IsCancelled = cancelled
End Property
Public Property Get SelectedDate() As Date
SelectedDate = selectedValue
End Property
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
selectedValue = DateClicked
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
cancelled = True
Me.Hide
End If
End Sub
And now you have a date picker form that you can reuse whenever you need it, because it doesn't know or care about what happens to the value that was selected:
If Not Application.Intersect(Range("l14"), target) Is Nothing Then
With New UserForm1 ' todo: rename form to "DatePickerDialog" or something
.Show
If Not .IsCancelled Then
target.Value = .SelectedDate
End If
End With
End If
You could add unload me in that sub:
Private Sub MonthView1_DateClick(ByVal DateClicked As Date)
ActiveCell.Value = DateClicked
Unload me
End Sub
I have a button the executes a user form to display with a required password before executing the buttons command, however when the user form is displaying it freezes the rest of the sheet. On the user Form a I created a cancel button so that the user can exit out of the UserForm should he not know the password and use the other buttons I have on the sheet. When the user clicks the cancel button, it still executes the command even though he/she did not put a password in. The user Form works properly when you enter the correct password/incorrect password, its only when you click cancel that it does not work. Could any on please offer any help? see my code below for the button and the code for my cancel button
Sub Feeder_Schedule()
UserForm1.Show
If Sheets("Bulk_Data").Visible = xlVeryHidden Then
Sheets("Bulk_Data").Visible = True
End If
Sheets("Bulk_Data").Select
Sheets("Home").Visible = xlVeryHidden
End Sub
code for the Cancel button
Private Sub CommandButton1_Click()
Unload Me
End Sub
If you want to make it right change/add to your code of the userform
Option Explicit
' USERFORM CODE
Private m_Cancelled As Boolean
' Returns the cancelled value to the calling procedure
Public Property Get Cancelled() As Variant
Cancelled = m_Cancelled
End Property
Private Sub buttonCancel_Click()
' Hide the Userform and set cancelled to true
Hide
m_Cancelled = True
End Sub
' Handle user clicking on the X button
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
Your code could then look like that
Sub Feeder_Schedule()
Dim frm As UserForm1
Set frm = New UserForm1
frm.Show
If Not frm.Cancelled Then
If Sheets("Bulk_Data").Visible = xlVeryHidden Then
Sheets("Bulk_Data").Visible = True
End If
Sheets("Bulk_Data").Select
Sheets("Home").Visible = xlVeryHidden
End If
End Sub
I have two forms, a login form to authenticate users to enter the system and a main form to work with if the authentication is successful. I work with an access database to search for the valid users and also to populate lists in the main form.
And here is the code for that:
Private Sub CancelCommandButton_Click()
CloseDatabase
Unload Me
End Sub
Private Sub ConfirmCommandButton_Click()
...
End Sub
Private Sub UserForm_Initialize()
ConnectDatabase
End Sub
Private Sub OpenMainForm()
Unload Me
MainForm.Show
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
Cancel = True
End If
End Sub
And here is the code for managing main form load-up and close:
Public Sub UpdateControls()
PopulateUserList
End Sub
Private Sub UserForm_Activate()
sTag = Split(Me.Tag, "|")
If sTag(0) <> "1" Then
Me.MainFormMultiPage.Pages(0).Enabled = False
Me.MainFormMultiPage.Value = 1
Else
Me.MainFormMultiPage.Pages(0).Enabled = True
Me.MainFormMultiPage.Value = 0
UpdateControls
End If
UserLabel1.Caption = sTag(1)
UserLabel2.Caption = sTag(1)
UserLabel3.Caption = sTag(1)
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
' Tip: If you want to prevent closing UserForm by Close (×) button in the right-top corner of the UserForm, just uncomment the following line:
' Cancel = True
Dim answer As Integer
answer = MsgBox("ÂíÇ ãØãÆäíÏ ˜å ãí ÎæÇåíÏ ÇÒ ÓÇãÇäå ÎÇÑÌ ÔæíÏ¿", vbYesNo + vbQuestion, "ÎÑæÌ ÇÒ ÓÇãÇäå")
If answer = vbYes Then
CloseDatabase
Else
Cancel = True
End If
End If
End Sub
Private Sub UserForm_Terminate()
loginForm.Show
End Sub
When I close the main form by clicking 'X' button, the login form reappears and the main form is closed; But when I login again (preferably using the same credentials) the main form is displayed but totally unresponsive (No list population, 'X' button doesn't work or any other controls in the form).
What should I do? Does the code in the UserForm_CloseQuery() unload the main form and all of its macros and I can't get the required events back to function or am I missing something?
It's not a time I started coding VBA and I can't make the head or tail of it easily when new problems arise. Any help would be appreciated. Thanks
Assuming your forms are modal, change the login form code to:
Private Sub OpenMainForm()
Me.Hide
MainForm.Show
Me.Show
End Sub
and remove the Userform_Terminate code from the main form. That will mean that the login form automatically shows when the main form is closed.
The attached VBA procedures are for a progress bar userform. Everything works as expected, except that the cancel button is intermittently unresponsive.
I say intermittently because, 95% of the time I have to click the cancel button numerous times before the procedure stops. I can see the button click event being animated, but the procedure isn't being interrupted. It looks as though something is stealing focus from the cancel button before the button down event can occur.
The escape and window close buttons respond as expected with one click.
What do I need to do to make the cancel button respond correctly? Thanks!
Update: I noticed that when I click and hold down on the cancel button, instead of the button staying "down" it gets kicked back up. So apparently something is resetting the button state to up, fast enough that the procedure is not catching the down state to fire the click event.
Here is the code in the userform module (named UserForm1):
Private mbooUserCancel As Boolean
Public Property Get UserCancel() As Boolean
UserCancel = mbooUserCancel
End Property
Private Property Let UserCancel(ByVal booUserCancel As Boolean)
mbooUserCancel = booUserCancel
End Property
Public Sub UpdateProgress(CountTotal As Long, CountProgress As Long)
On Error GoTo Error_Handler
ProgressBar1.Value = CountProgress / CountTotal * 100
DoEvents
Error_Handler:
If Err.Number = 18 Then CommandButton1_Click
End Sub
Private Sub CommandButton1_Click()
Hide
UserCancel = True
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Cancel = True
CommandButton1_Click
End Sub
Private Sub UserForm_Activate()
With Application
.Interactive = False
.EnableCancelKey = xlErrorHandler
End With
End Sub
Private Sub UserForm_Terminate()
Application.Interactive = True
End Sub
Here is the code for the module (named Module1) that calls the UserForm1:
Sub TestProgress()
On Error GoTo Error_Handler
Dim objUserForm As New UserForm1
Dim lngCounter As Long
Dim lngSubCounter As Long
With objUserForm
.Show vbModeless
DoEvents
For lngCounter = 1 To 5
If .UserCancel Then GoTo Exit_Sub
For lngSubCounter = 1 To 100000000
Next lngSubCounter
.UpdateProgress 5, lngCounter
Next lngCounter
Application.Wait Now + TimeValue("0:00:02")
.Hide
End With
Exit_Sub:
If objUserForm.UserCancel Then
MsgBox "User Cancelled from UserForm1"
End If
Exit Sub
Error_Handler:
If Err.Number = 18 Then
Unload objUserForm
MsgBox "User Cancelled from Module1"
End If
End Sub
Works for me on the first click every time. Try unloading any add-ins or any other code that could be running inside the container app and see if that helps.
If people are still in need of the answer, well I researched & cracked it!
For the click on cancel button, code should be;
Private Sub CommandButton1_Click()
Unload Me
'this bit ends all macros
End
End Sub
The answer is to use modal userforms for progress bars so that the button click event can fire without getting obscured by processing in the calling procedure.