Command button not re-enabling after condition not met automatically - excel

I have created a Command button and written a small code using if condition to match my criteria. Its working fine if their is any value in the cell/range, its doing according to code "asking to enter the data" and if their is any value "saying data is already enter" and disabling the button(what exactly i wanted).
But, when i am re-entering the data/value into those cell, it's not re-enabling the button back automatically. I have to manually have to go to properties to enable it, which i don't want to do everytime.
Below is my code"
Private Sub RESET_Click()
If Range("A10").Value = "" Then
Reset.Enabled = False
MsgBox "Data has already updated for this period"
Else
Reset.Enabled = True
MsgBox "Please, enter the data"
End If
End Sub
It's not re-enabling the button even after i have listed True in else condition.
Please, also let me know if their is way. So, i can reset/re-enable this button on 1st of every month automatically using VBA.
I would appreciate your response.
Thanks

It seems that your code is triggered by the button press. This way, once the first condition of the if statement is met, the button is disabled and won't run its code anymore.
Maybe what you want is to re-eanable the button when cell changing. So put this code on the worksheet after setting your sub to public:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("A10")) Is Nothing Then call RESET_click
End Sub
EDIT:
Maybe you also have to set the button object inside your main sub:
Set Reset = yourworksheet.Buttons("yourbuttonname")
I would also recomend not to use Reset as name inside VBA, since it is already a statement, and may cause confusion.

Related

Get command button by using cell address

I want to call/ activate a button at the end of a Sub. I know the cell address of the command button, but I don't know the name/ID of the button.
How do I select/activate the button without looping through each button on active sheet?
https://stackoverflow.com/a/30600479/13049793
I have created my buttons on multiple rows with each assigned to the same macro, from my understanding, I cannot call the macro the button is assigned to because the macro uses the button's relative position, below is a simple example to illustrate the use of the buttons relative position:
Sub ExampleButtonClick()
Dim Cellvalue As String
Cellvalue = ActiveSheet.Buttons(Application.Caller).TopLeftCell.Offset(0, -1).Value
Msgbox (Cellvalue)
End Sub
i assume you want to run one macro that at the end initiates a different macro, i also assume the reason the button is rather not as a sub that is just called is because it has its independent function that can be used without the other sub
assuming that you used a command button as an activeX control, why not just use a private sub that the button performs and place that in an individual module and at the end of your current sub;
call module1 'assuming the private sub exists in module 1
or rather include the code even if duplicated in the first sub, searching for a button seems the circular route unless there is another intention you wish to pursue.
maybe elaborate on the task at hand or post the current code you are working on?

Macro "Doesn't Work" From Call on Separate Sheet

This macro works as intended, from a button on the Batch Input sheet:
Sub BatchTriggerOFF()
Sheets("Batch Input").Unprotect
Sheets("Batch Input").Range("G3:J3").Value = "Off"
Sheets("SQL LOGIC").Calculate
Sheets("Batch Input").Range("A12").Select
Sheets("Batch Input").Shapes.Range(Array("Group 12")).ZOrder msoSendToBack
Sheets("Batch Input").Protect
End Sub
However, when BatchTriggerOFF is called from a different sheet in the same workbook, the macro neither changes the Range("G3:J3").Value nor Shapes.Range(Array("Group 12")).ZOrder msoSendToBack. There is no error message.
If Sheets("SQL LOGIC").Range("B1") = "On" Then Call BatchTriggerOFF
I've tried unprotecting the Batch Input sheet beforehand, messing with Sheets("Batch Input").Activate, Sheets("Batch Input").Select, and even tried pasting the BatchTriggerOFF line by line VBA directly into the second macro, to no avail.
What is causing BatchTriggerOFF to seemingly not run when called from the second macro/sheet?
[...] something is inherently wrong with the second code I've provided, likely not actively running when the value in Range("B1") is changed?
Exactly. A procedure that's in a standard module needs something, somewhere to invoke it. Could be a shape or button on the worksheet, could be other VBA code, but something needs to invoke it somehow.
No procedure is going to just know to run when Range("B1") is changed on Sheets("SQL LOGIC"): you need to have code that's "triggered" when a cell is changed on that sheet.
The way to do this, is to handle the worksheet module's Change event. Find your "SQL LOGIC" sheet in the VBE's Project Explorer (Ctrl+R), double-click it. In the code-behind module for that specific worksheet, select Worksheet from the left-side dropdown at the top of the code pane; the right-side dropdown should say SelectionChange, and the VBE should have added a private procedure that looks like this:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
Select Change from the right-side dropdown; the VBE creates a private procedure that looks like this:
Private Sub Worksheet_Change(ByVal Target As Range)
End Sub
Now delete the SelectionChange handler, you don't need it unless you need to track cells that the user has selected. Since we want to track cells that have changed, we'll use the Change worksheet event. This procedure will be invoked whenever the user or your code changes anything on that sheet.
Since we only care to run code when a specific cell is changed, we need a condition here, involving the Target parameter. Using the Application.Intersect function, we can get a Range object reference that's Nothing if the two specified ranges don't intersect; we can use this information to bail out if it's not B1 that changed:
If Application.Intersect(Me.Range("B1"), Target) Is Nothing Then Exit Sub
Any code written after that condition inside the Worksheet.Change event handler procedure, will only run after the value of cell B1 was modified - either by the user typing in a value, or by any other code writing to that cell (you need to toggle Application.EnableEvents off if you have to prevent firing that event when it's code doing the changes and you don't want the handler to run).
Now, it looks like cell B1 isn't going to change, rather, it looks like it contains a formula whose result might change after making changes to the "Batch Input" sheet.
If that's the case, then the Change event will not be fired when B1 recalculates and now evaluates to a new value, because the cell didn't change, only its result.
If that's your scenario, then you want to handle the Calculate worksheet event, and have that be your trigger:
Private Sub Worksheet_Calculate()
If Me.Range("B1").Value = "On" Then BatchTriggerOFF
End Sub
If you need your sub to be called from any (sheet) module, move it in a module! The function/sub in the sheet module cannot be called without specifying the module name where it belongs, like you will be able to do in a module.

How to create a code of clicking the button in VBA?

I have created a messagebox and coded so that the excel goes to the specific range where the button exists. But I do not know how to code so that the macro automatically clicks the button.
Sub Start()
Range("A4").Select
< >
End Sub
Sub MessageBox()
MsgBox "Hi" & vbCrLf & "Professor", _
vbInformation, "Greetings"
End Sub
I need something < > in this space but the process to automatically get linked.
Anyone have an idea?
In your example it looks like you have the name of the macro, and if that's the case it should be easy to just call it. See below
Sub Start()
Range("A4").Select
Call MessageBox
End Sub
Sub MessageBox()
MsgBox "Hi" & vbCrLf & "Professor", vbInformation, "Greetings"
End Sub
However, I'm guessing that doesn't help you because what you're asking doesn't truly make sense. I'm going to guess that maybe by MsgBox, you actually mean Form or Command Button. These look similar but they are distinctly different.
A MsgBoxis more of an alert to the user with the option to capture a small amount of information back (i.e. yes/no/ok/cancel etc). Clicking on a MsgBoxwill never directly launch another macro. An ANSWER to a MsgBox(i.e yes/no) MIGHT determine if another Macro is run based on an if-statement, or if the next line of code is simply just to execute another macro.
If you have a macro running distinctly based on a click, the button is likely a Form or an active X command Button. You need to figure out what macro this object is executing and then you just need to include this in your code. Google "how to see what macro a form button runs in VBA" or if it's an active X button, right click on it and hit "View Code". Both of these approaches should drive you to a macro name such as CommandButton1_Click.
Unfortunately, you might have to get more fancy as if it's a sheet Commandbutton1_Click you may have to make it public. Hopefully you can insert a call that code in your current macro.
Hope that helps.

Wait via Do Events works in standard module but not userform

Background/issue: I created a userform so that when a value lower than $250 is entered in a specific cell, the userform prompts the user for a password. The password is then supplied by a supervisor to allow the value. The issue is that the value entered by the user will be a guess. These users mess with values until the value they enter gets them the number they're looking for (separate formula that's dependent upon the low $250 amount). So after the user attempts their first number, they're likely going to need to enter it up to 10ish times. Currently the userform would require the supervisor to enter the password each time the value is changed. I'm hoping to edit my code so that either A) the password can be "retained" if you will for a certain length of time or B) allow the opportunity to enter an amount lower than $250 a set amount of times without the userform launching each time. I tried the number attempt originally and was unsuccessful. Honestly a time option would be best so hopefully someone can help. I've tried multiple ways of waiting (application.wait), sleep using lib kernel32, and a few different do events. From what I've gathered, the do events might be my best option as what I need it to do is allow the user to change values and not have the PC prevent the user from working (change said value though I suppose the user could still perform other actions.)
I've tried putting different the different wait/sleep/loop subs in a standard module and call them but I've also tried putting them directly in the forms module but neither way works. If the sub is in a standard module, Excel doesn't let the user do anything (it acts as application.wait) but if I perform it in the form module, it allows the user to select cells but not edit them until the loop/userform sub is complete. No errors are given in any of this, it just doesn't let users make multiple attempts at the value under $250. One last tidbit...I can run the Wait sub on a standard module and work in the workbook while it continues firing; just can't get it to work with the userform.
Public Sub CommandButton1_Click()
Dim newTime As Date
If tbPassword.Value = "password" Then
me.hide 'Form would stay up so I thought hiding it would fix issue but didn't
call wait 'loop to allow an amount of time before PS has to be reentered
Else
MsgBox "Password is incorrect."
Sheets("Rate Calculator v8").Range("K19") = ""
Application.Goto Sheets("Rate Calculator v8").Range("K19")
End If
Unload me
End Sub
Sub Wait()
Start = Timer
Do While Timer < Start + 60
DoEvents
Loop
End Sub
I got a solution that works but not as you like it to work and I will tell you why it shouldn't work like you want it to work.
First the solution:
Put this code in "ThisWorkbook"-Module:
Option Explicit
Public Endt
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Call Modul1.TimeBeforeReentry
End Sub
Side note here: You may want to use another event then Workbook_SheetChange but it does the job for me here. The disadvantage is that it also triggers with everything else that changes the a sheet.
Then put this code in a module1:
Sub TimeBeforeReentry()
If ThisWorkbook.Endt > Timer Then
Else
UserForm1.Show
If UserForm1.Passwordfield.Value = "password" Then
UserForm1.Passwordfield.Value = ""
ThisWorkbook.Endt = Timer + 60
Else
MsgBox "Password is incorrect."
Worksheets(1).Range("K19") = ""
Application.Goto Worksheets(1).Range("K19")
End If
End If
End Sub
And finally in the userform:
Private Sub CommandButton1_Click()
Me.Hide
End Sub
And now the explanation and why you shouldn't put everything into the userform.
The public variable Endt is in thisworkbook and will be saved there (unless there is an error!). As soon as the event is triggered, in our case workbook_SheetChange, the module will be called. Here is the whole logic and this is good. Because you do not want to make "smartUI" the problem with logic in userforms is that it is nearly impossible to maintain and to adjust to changes. I learned this the hard way believe me.. I am not an expert on this topic but read these links
Smart UI
Model View Presenter as alternative to Smart UI
The Sub TimeBeforeReentry then checks the time and shows the userform accordingly. If the password is entered the Endt is set and if the next event is triggered within Endt then the password does not have to be reentered. Otherwise the password will be needed to reentered.
The userform is just a data interchange device it has nothing to do with logic it just holds data and delivers it. That's what UI is for!

How do I run some VBA code when a cell is changed?

I want to add some VBA code when the value in a cell changes.
I've already tried Worksheet_Change() as described at Contextures however, this won't work: it only fires when the user changes the value. I want to fire it whenever the value changes, i.e. whenever the spreadsheet recalculates.
Any ideas?
Private Sub Worksheet_Calculate()
MsgBox "Something recalculated", vbOKOnly, "Testing Actions"
End Sub

Resources