Run a Macro in Excel 2010 using Enter Key, Whether Worksheet has Changed or Not, when Pressed in Particular Range - vba

The short version of the question: How can I make a macro run in Excel 2010 when the user hits the numeric [Enter] key within a given range of cells, and whether or not they've changed the spreadsheet since the last running of the macro?
LONGER VERSION: I have a macro in Excel 2010, and I currently have a button on the sheet that the user presses to run it. The user enters 4 cells of data (in A2:D2) and runs the macro to populate several tables on several sheets with the data. The user may enter several hundred sets of data in a single sitting, and currently leaves the mouse hover over the button, enters the data, and clicks the mouse without moving it to hit the button. I'd like to simplify it by having a press of the numeric [Enter] key run the macro so they can leave their hand on the numeric key area.
I've found this question, but the answer was to use Worksheet_Change and the user didn't need the Enter Key. I also found this question, which used on the [Enter] key, but also required the worksheet to change to be of use.
My user may use the same data multiple times, so I'd like them to be able to press the [Enter] key multiple times. Currently the macro finishes by selecting A2, the first cell with data, so the user can enter new data or press it again to run it again. I want it to run from anywhere in the range of A2:D2, selecting A2 when complete (as it does now), and if [Enter] is pressed while any other cell is selected, or a cell on any other sheet is selected, I want it to move down a cell as it currently does, without running any macro.
Useful names/numbers/things:
Data range will always be in Sheet 1, cells A2:D2.
Macro to be run is named "InsertIntoTables()" and takes no parameters.
Currently no other application-wide macros or events are being used.
The macro already handles empty or improperly-filed cells in my range.
If there is anything else necessary to provide an answer, I'm happy to supply it.

This is just to get you started. Say clicking the button with the mouse runs InsertIntoTables(). I am assuming that InsertIntoTables() is in a standard module. (this makes it easy to call from another sub)
First run:
Sub NumericEnter()
Application.OnKey "{ENTER}", "InsertIntoTables"
End Sub
After this has been run:
touching the numeric keypad ENTER key will have the same effect as mouse-clickng the button
the normal ENTER key will not be affected
To restore the numeric keyboard ENTER key, run this:
Sub ClearEnter()
Application.OnKey "{ENTER}", ""
End Sub
What you must complete:
The numeric keypad ENTER key will call your sub no matter which worksheet is active. YOU must add the logic to detect which sheet is active and take appropriate actions. You must select which ever cell you want when your sub completes. You must remember to run the restore sub before quitting.
EDIT#1:
I have two worksheets; Sheet1 and Sheet2.Sheet1 is the sheet in which I want to use the "special" ENTER key.
I placed the following in a standard module:
Sub NumericEnter()
Application.OnKey "{ENTER}", "InsertIntoTables"
End Sub
Sub ClearEnter()
Application.OnKey "{ENTER}", ""
End Sub
Sub InsertIntoTables()
MsgBox "Inserting"
End Sub
I placed the following in the Sheet1 code area:
Private Sub Worksheet_Activate()
Call NumericEnter
End Sub
Private Sub Worksheet_Deactivate()
Call ClearEnter
End Sub
I placed the following in the workbook code area:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Call ClearEnter
End Sub
Private Sub Workbook_Open()
Sheets("Sheet2").Activate
Sheets("Sheet1").Activate
End Sub
The purpose of the Workbook_Open() macro is to insure we start with Sheet1 active and the "special" ENTER key active.
EDIT#2:
Use this instead:
Sub ClearEnter()
Application.OnKey "{ENTER}"
End Sub
Reference:
Tims answer

Related

Unable to run macro from Application.Onkey

I am unable to run macro from Application.Onkey option. The following message is displayed upon pressing TAB key: "Cannot run the macro "C:\...\Desktop\test.xlsm!abc'. The macro may not be available in this workbook or all macros may be disabled."
However, upon pressing Enter key, selection goes 1 row below (as it always does) instead of running the same macro.
I have enabled all macros from Trust Settings and checked "Trust access to the VBA project object model". The file have been saved with xlsm extension.
All of the following macros are in thisWorkbook:
Private Sub Workbook_Open()
Test1
End Sub
Sub Test1()
Application.OnKey "{TAB}", "abc"
Application.OnKey "{ENTER}", "abc"
End Sub
Sub abc()
MsgBox "TAB"
End Sub
Can anyone help me with this one?
To make your code running, move Sub Test1 and abc to a module.
Then if you have 2 Enter keys on your keyboard, press the one on the numeric keypad (the smaller one) and your code should work. To use the big one, use ~ like this:
Sub Test1()
Application.OnKey "{ENTER}", "abc" 'The small one
Application.OnKey "~", "abc" 'The huge one
End Sub
Application.OnKey MSDN
I assume your macro abc() is in "Ten_skoroszyt" ("ThisWorkbook") module, it should be transfered to separate (new) module.

Stop a do loop with a command button

I have a VBA excel userform that is misbehaving. Basically I want my code to pause until a command button on a userform is pressed. Any ideas?
In a module:
Public okayclicked as boolean
Sub MyThing
UserForm1.Show
Do Until okayclicked
DoEvents
Loop
UserForm1.Hide
End Sub
In my userform:
Sub CommandButton1_Click()
okayclicked = True
End Sub
Not sure what else to try to make this work. Any help is appreciated! Thanks!
'module
Sub MyThing1
UserForm1.Show
End Sub
Public Sub MyThing2
'....rest of code
End Sub
'userform
Sub CommandButton1_Click()
MyThing2
Me.Hide
End Sub
Either use a MsgBox to ask for the user input, or set your form to be Modal (MSDN link).
A Modal form will allow you to continue to work in the form, and any code underlying the form will continue to run, but the main code that calls the form will be 'blocked'.
Should the underlying Excel sheets be modified during the period of pause, you can add code when the button press is detected (i.e. when the Form is closed or then the MsgBox OK button is pressed) to update the relevant parts of the Form.
But we have digressed from the original simple question and many other factors (such as how the underlying sheets will be modified when the form is open) come into play.
Consider if a change in the underlying sheet has to change the form immediately or if it can occur when the user resumes the form/code.
Consider if the functions you want can be done natively in the spreadsheet and minimise the use/functionality of the form.
Consider other event driven options where the code is broken into natural sections, functions, subroutines or modules and each section only runs when triggered by the right event (sheet change, user input, subroutine finished, form exit etc.)

Application on key as home button

I'm collecting measurements in an Excel workbook.
All the measurements are displayed in separate sheets.
The average and max of every sheets' measurement is displayed in the home sheet (with the name "1")
I added a line of code to jump from the home sheet to a certain sheet by entering the sheet name in cell J23 and clicking on a button.
Now i'd like to add a physical key/button in order to go back to the home sheet.
for example with ctrl+b
unfortunately my code does not work yet.
I've pasted my code below, hope someone has a solution.
Thanks in advance
Sub Macro1()
i = Sheets("1").Range("J23").Value
Worksheets(i).Select
End Sub
Sub Home()
Application.OnKey "^b", Worksheets("1").Select
End Sub
You need to pass Application.OnKey the name of a procedure, not a VBA command as you are trying to do.
Something along these lines:
Sub Home()
Sheets(1).Select
End Sub
Sub SetUp()
Application.OnKey "^b", "Home"
End Sub
The above subs are in a standard code module. When I run SetUp, I am afterwards able to get back to Sheet1 from any other sheet by entering Ctrl+b.

using one sub for multiple buttons in excel vba

I have a spreadsheet containing client data, one client per row and each row has a button that launches a userform showing the data for that client, you can then update the data for that client and write it back to the row for that client. Before we start using the spreadsheet each case worker will filter so that only their clients are shown.
I wondered whether there is a way of having one command button procedure for the buttons on each row ie when you press the button in row 6 it runs a procedure for CommandButton6 to call the data in that row, when you press the button in row 8 it runs a procedure for CommandButton8 to call the data in row 8. However the procedure for both is the same so can I have a CommandButtoni sub where I is the row number.
It is a very simple procedure but I don't want to have to copy it 350 times!
Private Sub CommandButton1_Click()
UserForm1.TextBox1.Value = Worksheets("Sheet1").Range("C2").Value
GetData
UserForm1.Show
End Sub
You would need a parameterized Click handler, which you can't have in VBA. You could assign 350 form buttons to the same handler procedure, but they would all assign UserForm1.TextBox1.Value whatever is in Worksheets("Sheet1").Range("C2").Value, and actually reading your question you seem to want to have some "row parameter".
Having 350 form/ActiveX buttons on a worksheet is generally not a very good idea: I'd try to think of a different approach instead.
Is the Selection in the row you need it to be when a button is clicked? You could make the current/active row highlight somehow (handle SelectionChanged worksheet event), and have one button somewhere (in the Ribbon?) that works off the Selection:
UserForm1.TextBox1.Value = Sheet1.Range("C" & Selection.Row).Value
Other than that, Rory's suggestion would work... but form buttons weren't intended to be used like this.
After implementing Rory's suggestion, I think it is the simplest and most elegant code solution. Allows copy and paste of the buttons without any further configuration if done uniformly with the code.
Sub AddVote()
' This is a simple vote tally counter. Each time a button is clicked,
' the vote count in the third column is incremented by one.
' Imagine: first column = candidate name; second column holds form button;
' Thid column = vote count
' Create a Form button and assign this macro. Copy and paste button!
Dim rngTally As Range
' Use rngTally to point to the cell in the third column (3, in the formula)
' in the same row as the top left corner of the button.
Set rngTally = Cells(ActiveSheet.Buttons(Application.Caller).TopLeftCell.Row, 3)
' Increment the value of the cell pointed to by rngTally by 1
rngTally = rngTally + 1
End Sub
If you don't want/need to design a custom user form, you could use the Form... command:
Click the Customize Quick Access Toolbar drop-down menu in the Excel
Title Bar.
Select More Commands.
If the document will be distributed to other users, change the "For all documents (default)" option to the document name.
Select to Choose commands from: Commands Not in the Ribbon.
Select the Form... command.
Click Add to add the button to the right side menu.
Click OK.
With any cell in a table selected, click the Form button. Edit and press Enter. Could also use Criteria to filter on a value. Unfortunately no way to edit the form, but useful for narrow cell contents. No coding required.
https://support.office.com/en-us/article/Add-edit-find-and-delete-rows-by-using-a-data-form-9443c80d-66c6-4c17-b844-64aac5ae841d
A neater way for a sub for each button.
Private Sub Delete0_Click(): DeleteRow (0): End Sub
Private Sub Delete1_Click(): DeleteRow (1): End Sub
Private Sub Delete2_Click(): DeleteRow (2): End Sub
Private Sub Delete3_Click(): DeleteRow (3): End Sub
Private Sub Delete4_Click(): DeleteRow (4): End Sub
Sub DeleteRow(row As Integer)
Debug.Print "DeleteRow(" & row & ")"
End Sub

Why does this code work with F1 and not CTRL-M (for example)

I found this code online, and it works like a charm:
Sub Auto_Open()
Application.OnKey "{F1}", "WorkbooksHandler"
End Sub
Sub WorkbooksHandler()
On Error Resume Next
If ActiveWorkbook.Sheets.Count <= 16 Then
Application.CommandBars("Workbook Tabs"). _
ShowPopup 500, 225
Else
Application.CommandBars("Workbook Tabs"). _
Controls("More Sheets...").Execute
End If
On Error GoTo 0
End Sub
I press F1 and it opens a dialogue with all the sheets. I can select the sheet I want and it goes there.
If I change the code just slightly, and use:
Sub Auto_Open()
Application.OnKey "^{m}", "WorkbooksHandler"
End Sub
Now control-m opens with dialogue showing me the sheets, but when I click on the sheet I want excel doesn't navigate there. Why should the trigger make any difference, and make the execution not work?
Edit: By the way, the code also works fine when I run it manually with F5 as well, just not with the onkey control-m.
The problem appears to be that the Control key, when used with OnKey persists through the whole command even though you've no doubt released the key. This has no effect on most things that you do, but inexplicably effects the More Sheets popup. Take this code
Sub Auto_Open()
Application.OnKey "^m", "WorkbooksHandler"
End Sub
Sub WorkbooksHandler()
SendKeys "{RIGHT}"
End Sub
All that does is press the right arrow key. But it has the effect of pressing Ctrl+Right which takes you to the edge of you worksheet (for a blank worksheet). So the Control part of ^m is sticking around through the execution of WorkbooksHandler.
This happens manually also. Hold down the control key, right click on the sheet navigation buttons, select More Sheets, select a sheet. It doesn't move to that sheet when you have Control held down.
I tried all manner of SendKeys, OnTime, and DoEvents, but couldn't trick Excel into releasing the Control key. I'll bet you could find a Windows API that would do the trick, but it's probably easier to simply pick a key combination that doesn't use Control.
Make sure
Sub WorkbooksHandler()
On Error Resume Next
If ActiveWorkbook.Sheets.Count <= 16 Then
Application.CommandBars("Workbook Tabs"). _
ShowPopup 500, 225
Else
Application.CommandBars("Workbook Tabs"). _
Controls("More Sheets...").Execute
End If
On Error GoTo 0
End Sub
is pasted in Modules,
Then
Compile and Run the Auto_Open() manually then try the shortcut