excel 2010 vba send keys to simulate clicking the formula bar - excel

Google hasn't given me quite what I want, I thought maybe SO might have the answer.
Instead of using a input box or user prompt that asks the user for info that will be stored in cell, I'm looking for some code to simulate clicking in the formula bar. I am currently using sendkeys method with "F2" to allow the user to enter info into the selected cell. It would be much easier to look into the formula bar, instead of a single cell in a sea of data.
Sub CopyTemplate()
'ActiveWorkbook.Save
Worksheets("HR-Cal").Activate
Dim rng As Range
Dim trng As Range
Dim tco As String
'Use the InputBox select row to insert copied cells
Set rng = Application.InputBox("select row to paste into", "Insert template location", Default:=ActiveCell.Address, Type:=8)
If rep = vbCancel Then
End If
startrow = rng.Row
' MsgBox "row =" & startrow
Range("AG2") = startrow
Application.ScreenUpdating = False
'copy template block
Range("C6").End(xlDown).Select
Range("AG1") = ActiveCell.Row
tco = "A5:AN" & Range("AG1")
Range(tco).Select
Selection.Copy
Range("A" & Range("AG2")).Activate
Selection.Insert Shift:=xlDown
Range("c100000").End(xlUp).Select
Selection.End(xlUp).Select
'select first value
Range("AG1:AG2").ClearContents
Application.ScreenUpdating = True
SendKeys "{F2}"
SendKeys "{BS}"
End Sub
when the codes runs this is what the user sees (col 2 col 2621)

I don't believe there is a single keypress to "activate" the formula bar. There is probably a way to do with multiple keypress events like <alt><tab><tab>...~nine years later and a couple of other keys~...<tab><tab>
The quicker and more direct way would be to turn off the "EditDirectlyInCell" setting:
Application.EditDirectlyInCell = False
This will bring the cursor to the formula bar when you sendkey F2
You could just turn this thing off on Workbook_Open() in the workbook's code:
Private Sub Workbook_Open()
Application.EditDirectlyInCell = False
End Sub
Perhaps on Workbook_BeforeClose() you could toggle that setting back on so you don't change their defaults:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Application.EditDirectlyInCell = True
End Sub

maybe this will help, i set the Application.EditDirectlyInCell to false, before entering cell editing, then call DoEvents before returning EditDirectlyInCell to true
Sub EditRange(ByVal Target As Range) 'so any change in target would not affect
'the caller's variable
Set Target = Target.Areas(1).Resize(1, 1) 'to make sure the target is single cell
Target.Worksheet.Activate 'to make sure the worksheet is active
Target.Activate 'activate the designated cell
Application.EditDirectlyInCell = False 'turn cell editing to false, any attempt _
to edit cell will be done in formula bar
SendKeys "{F2}" 'send F2 to start editing the cell
DoEvents 'make sure every command is fully executed
Application.EditDirectlyInCell = True 'return in cell editing to default value
End Sub

Related

How to apply code to all the following rows

I have this code but it only work for my first row.
It is suppose to look if the checkbox on B, C or D is checked, and if so, a date + username will automaticaly fill in F and G.
here is a picture of my table:
This is what my code looks like:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Range("B2") Or Range("C2") Or Range("D2") = True Then
Range("G2").Value = Environ("Username")
Range("F2").Value = Date
Else
Range("F2:G2").ClearContents
End If
End Sub
Enter this code in a regular module, select all your checkboxes and right-click >> assign macro then choose ReviewRows.
This will run the check whenever a checkbox is clicked - a bit of overhead since all rows will be checked, but should not be a big deal.
Sub ReviewRows()
Dim n As Long
For n = 1 To 100 'for example
With Sheet1.Rows(n)
If Application.CountIf(.Cells(2).Resize(1, 3), "TRUE") > 0 Then
If Len(.Cells(6).Value) = 0 Then 'only enter if currently empty?
.Cells(6) = Date
.Cells(7) = Environ("Username")
End If
Else
.Cells(6).Resize(1, 2).ClearContents
End If
End With
Next n
End Sub
If you want to be more precise then Application.Caller will give you the name of the checkbox which was clicked, and you can use that to find the appropriate row to check via the linkedCell.
Sub ReviewRows()
Dim n As Long, shp As CheckBox, c As Range, ws As Worksheet
Set ws = ActiveSheet
On Error Resume Next 'ignore error in case calling object is not a checkbox
Set shp = ActiveSheet.CheckBoxes(Application.Caller) 'get the clicked checkbox
On Error GoTo 0 'stop ignoring errors
If Not shp Is Nothing Then 'got a checkbox ?
If shp.LinkedCell <> "" Then 'does it have a linked cell ?
With ws.Range(shp.LinkedCell).EntireRow
If Application.CountIf(.Cells(2).Resize(1, 3), "TRUE") > 0 Then
If Len(.Cells(6).Value) = 0 Then 'only enter if currently empty?
.Cells(6) = Date
.Cells(7) = Environ("Username")
End If
Else
.Cells(6).Resize(1, 2).ClearContents
End If
End With
End If 'has linked cell
End If 'was a checkbox
End Sub
However this appraoch is sensitive to the exact positioning of your checkbox
You have a long way to go!
Unfortunately, If Range("B2") Or Range("C2") Or Range("D2") = True Then is beyond repair. In fact, your entire concept is.
Start with the concept: Technically speaking, checkboxes aren't on the worksheet. They are on a layer that is superimposed over the worksheet. They don't cause a worksheet event, nor are they responding to worksheet events. The good thing is that they have their own.
If Range("B2") Or Range("C2") Or Range("D2") = True Then conflates Range with Range.Value. One is an object (the cell), the other one of the object's properties. So, to insert sense into your syntax it would have to read, like, If Range("B2").Value = True Or Range("C2").Value = True Or Range("D2").Value = True Then. However this won't work because the trigger is wrong. The Worksheet_Change event won't fire when when a checkbox changes a cell's value, and the SelectionChange event is far too common to let it run indiscriminately in the hope of sometimes being right (like the broken clock that shows the correct time twice a day).
The answer, therefore is to capture the checkbox's click event.
Private Sub CheckBox1_Click()
If CheckBox1.Value = vbTrue Then
MsgBox "Clicked"
End If
End Sub
Whatever you want to do when the checkbox is checked must be done where it now shows a MsgBox. You can also take action when it is being unchecked.

Lock in dropdown selection

I'm creating a quiz.
Questions on one worksheet and the answers on another.
When a question is answered another field with this formula
=IF(C5="","",IF(C5=Answers!A5,"Correct","Incorrect"))
tells the person if the answer is correct or incorrect.
I am using data validation with dropdown lists so they can only choose true/false, (a, b, c, d) etc.
Is there a way to lock in a selected answer, until a master reset button is pressed?
For example,
Question is in A1
The possible answers are in the form of a dropdown menu in B1.
Sometimes the answer is in the form of a true false, sometime it is in the form of a multiple choice. In the example of true false, if the person puts in true, c3 will say correct or if they put false, then incorrect.
As it is now, the person can switch back and forth as much as they want.
I am looking to make it so once an answer is selected, they cannot change it.
You can use Sheet Protection, combined with Range Locking and a Change event.
Put this code in the relevant Worksheet Module. Adjust the Private constants to suit your needs.
Option Explicit
' Reference the cells that your users may enter data into
Private Const DataCells As String = "J1,J3,J5"
Private Const PW As String = "password"
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cl As Range
Dim DataRange As Range
Set DataRange = Me.Range(DataCells)
'Loop thru changed cells
For Each cl In Target.Cells
'If changed cell is in the DataCells range and is not blank, lock it
If Not Application.Intersect(cl, DataRange) Is Nothing Then
If Not IsEmpty(cl) Then
Me.Unprotect PW
Target.Locked = True
Me.Protect PW
End If
End If
Next
End Sub
'Re-enable data entry to all DataCells
Sub MasterReset()
'Unlock the sheet, prompt for password
Me.Unprotect
'Unlock the cells
Me.Range(DataCells).Locked = False
'Optional, clear DataCells
Me.Range(DataCells).ClearContents
'Lock the sheet again
Me.Protect PW
End Sub
This works pretty good:
In the "This Workbook" module, insert the code:
Private Sub Workbook_Open()
Sheet1.Protect userinterfaceonly:=True 'allows macros to run
Sheet1.Range("A1:A20").Locked = False 'replace this range with the range the user deals with.
End Sub
In the sheet module that the user will be interacting with, add this code:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Locked = True Then Exit Sub
If Target.Locked = False Then
If Target.Value = "" Then Exit Sub
If Target.Value <> "" Then Target.Locked = True
End If
End Sub
That should take care of things for you!

How to reference a specific sheet within VBA Code in Excel 2013

This works perfectly, but I only want it to reference a single sheet instead of every sheet in the workbook
Private Sub Worksheet_Change()
Dim LastRow As Long, c As Range
Application.EnableEvents = False
LastRow = Cells(Cells.Rows.Count, "AA120").End(xlUp).Row
On Error Resume Next
For Each c In Range("AA5:AA120" & LastRow)
If c.Value = "0" Then
c.EntireRow.Hidden = True
ElseIf c.Value > "0" Then
c.Activate
c.EntireRow.Hidden = False
End If
Next
On Error GoTo 0
Application.EnableEvents = True
End Sub
As i can see you only need to insert this code in one sheet which ever you want. Rightclick on sheet name(tab) and select "view code", then paste this code. BUT! If this runs on every sheet, then you also need to delete code from "This Workbook" --> (Alt+F11) and select "This workbook", then erase this code from there.
You have to use
Private Sub Worksheet_Change(ByVal Target As Range)
instead.
According to the great Chip Pearson, "The events and their procedure declarations are fixed. You must not alter the name or parameter list of an event procedure." (I do not have a system with Office to test it).
You would insert your Sub in a sheet module, and it will work only on that sheet.

Selection returns “Compile Error: Expected Function or variable”

Help!
Below is my code for a start/stop button in Excel and now I'm getting a Compile error that is highlighting btnStart on the first line.
Sub btnStart()
ActiveSheet.Unprotect
Cells(Rows.Count, 5).End(xlUp).Offset(1) = Date
Cells(Rows.Count, 6).End(xlUp).Offset(1) = Now
Cells(Rows.Count, 7).End(xlUp).NumberFormat = "hh:mm"
Cells(Rows.Count, 8).End(xlUp).Offset(1) = Environ("username")
Me.btnStart().Enabled = False
Me.btnStop.Enabled = True
End Sub
Sub btnStop()
ActiveSheet.Unprotect
Cells(Rows.Count, 7).End(xlUp).Offset(1) = Now
Cells(Rows.Count, 7).End(xlUp).NumberFormat = "hh:mm"
Me.btnStart.Enabled = True
Me.btnStop.Enabled = False
End Sub
Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
If I understand correctly the buttons are on an excel sheet (not in a user form) so your issue because you are calling the buttons incorrectly. you can't simply call the named buttons you must look into the sheet.buttons property like this
ActiveSheet.Buttons("btnStart").
Also if you have named sheets I would use the sheetname rather than ActiveSheet
Sheets("sheetname").Buttons("btnStart").
One more note, that enabling/disabling a button works BUT it doesn't make the button appear enabled/disabled. To do this you also have to change the font color.
ActiveSheet.Buttons("btnStart").Font.ColorIndex = 15 '15 is grey, 1 is black
---- edit: code changed ---
REASON: After doing some more research it seems there are problems with my original solution. The most important is that the "enabled" property has no effect in excel 2010. Another route would be using activeX controls, BUT, a recent windows update (dec 2014) prevents activeX controls from running without deleting some system files (which would have to be done for each user, on every computer this code may run on -_- good job MS SOURCE)
This new solution should avoid all those problems. It uses two global variables start_btn_disabled and stop_btn_disabled I assume each button in your form (btnStart and btnStop) have a macro assigned to them? Simply check the global variable at the very beginning of the the sub if the button is disabled then quit the sub, so even though the click is still processed (it will always be processed in excel 2010 as stated before) the code doesn't run. So it behaves as though it was disabled. In my code I made a sub called btnStopClicked that would run when you click 'btnStop' In order to assign the macro to a button, right click the button, select "assign macro" and select the appropriate macro. I also created a similar sub for when you click the start button
'these are global variables and should be declared at the top of the module
'outside of any sub/function
'
'Note we use DISabled rather than enabled, because by default
'booleans = False. This means as soon as the form opens both these buttons
'will be enabled without any extra work.
'If you want to change this (make start button enabled and stop disabled,
'when the workbook opens simply change all the "stop_btn_disabled" to
'"stop_btn_enabled" and uncomment the following line) make sure you change the
'variable names so they make sense
'Dim stop_btn_enabled As Boolean 'initializes to false
Dim start_btn_disabled As Boolean 'intializes to false
Dim stop_btn_disabled As Boolean 'intializes to false
'Most of this code remains the same as before
Sub btnStart()
ActiveSheet.Unprotect
Cells(Rows.Count, 5).End(xlUp).Offset(1) = Date
Cells(Rows.Count, 6).End(xlUp).Offset(1) = Now
Cells(Rows.Count, 7).End(xlUp).NumberFormat = "hh:mm"
Cells(Rows.Count, 8).End(xlUp).Offset(1) = Environ("username")
'now we set the state of the global variable
start_btn_disabled = True
'makes the button appear greyed out
ActiveSheet.Buttons("btnStart").Font.ColorIndex = 15
'now we set the state of the global variable
stop_btn_disabled = False
'makes the button black like normal
ActiveSheet.Buttons("btnStop").Font.ColorIndex = 1
End Sub
Sub btnStop()
ActiveSheet.Unprotect
Cells(Rows.Count, 7).End(xlUp).Offset(1) = Now
Cells(Rows.Count, 7).End(xlUp).NumberFormat = "hh:mm"
'now we set the state of the global variable
stop_btn_disabled = True
'makes the button appear greyed out
ActiveSheet.Buttons("btnStop").Font.ColorIndex = 15
'now we set the state of the global variable
start_btn_disabled = False
'makes the button black like normal
ActiveSheet.Buttons("btnStart").Font.ColorIndex = 1
End Sub
'and now the real key is checking the globals before running the code
'when you click "btnStop" button this is the code that runs, you may have
'named the sub something different, I just named it this way so it's clear
'what the sub does
Sub StopBtnClicked()
'must be the first bit of code in the btn click sub
If (stop_btn_disabled) Then
Exit Sub
End If
'the rest of the code when you click stop button goes here
'the only way to get to this point is if the but is enabled
End Sub
Sub StartBtnClicked()
'must be the first bit of code in the btn click sub
If (start_btn_disabled) Then
Exit Sub
End If
'the rest of the code when you click start
End Sub
if this solves your problem, please mark it as the answer
Maybe try the following, I corrected one line
Sub btnStart()
ActiveSheet.Unprotect
Cells(Rows.Count, 5).End(xlUp).Offset(1) = Date
Cells(Rows.Count, 6).End(xlUp).Offset(1) = Now
Cells(Rows.Count, 7).End(xlUp).NumberFormat = "hh:mm"
Cells(Rows.Count, 8).End(xlUp).Offset(1) = Environ("username")
'Corrected line below
Me.btnStart.Enabled = False
Me.btnStop.Enabled = True
End Sub
Sub btnStop()
ActiveSheet.Unprotect
Cells(Rows.Count, 7).End(xlUp).Offset(1) = Now
Cells(Rows.Count, 7).End(xlUp).NumberFormat = "hh:mm"
Me.btnStart.Enabled = True
Me.btnStop.Enabled = False
End Sub
Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
You need to use ActiveX buttons if you want to use the Enabled property:
Private Sub btnStart_Click()
Me.btnStart.Enabled = False
Me.btnStop.Enabled = True
End Sub
Private Sub btnStop_Click()
Me.btnStart.Enabled = True
Me.btnStop.Enabled = False
End Sub

Selecting cell in Beforesave Event

see codes below.
I have the 'beforesave' code in the Workbook module and it works fine when I'm in the active sheet. However from the table I use on sheet 2 I also have a pivot table on sheet 1. To refresh my pivot I use an inserted button with an attached macro (this is in the module section)
Sub Refresh_Pivot()
'
' Refresh_Pivot Macro
ActiveSheet.PivotTables("PivotTable1").PivotCache.Refresh
ActiveWorkbook.Save
End Sub
On Activate.Workbook.Save its starts to act on my other code (which is in the workbook module), I want this to happen as a pivot table with missing data is not a good tool. However on using this it defaults with an error and highlights the cell.Offset(0, 1).Select - How can I prevent this?
Ideally I want the user to select OK on the msgbox and then the screen page changes to Sheet 2 and highlights the offending cell.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim esave As Range
Dim psave As Range
Dim jsave As Range
Dim RAll As Range
Dim cell As Range
Set esave = Sheet2.Range("Table1[Estimated Claim (USD)]")
Set psave = Sheet2.Range("Table1[Provisional Claim (USD)]")
Set jsave = Sheet2.Range("Table1[Agreed Claim (USD)]")
Set RAll = Union(esave, psave, jsave)
For Each cell In RAll
If cell.Value <> "" And cell.Offset(0, 1).Value = "" Then
Dim missdata
missdata = MsgBox("Missing Data - Enter the Date for WorkBook to Save", vbOKOnly, "Missing Data")
Cancel = True
cell.Offset(0, 1).Select
Exit For
End If
Next cell
End Sub
.Select should be avoided.
INTERESTING READ
I also want to know why are you trying to select that cell? What is the purpose. If you want to interact with it, then you can do that without selecting it. For example
If cell.Value <> "" And cell.Offset(0, 1).Value = "" Then
Dim missdata
missdata = MsgBox("Missing Data - Enter the Date for WorkBook to Save", vbOKOnly, "Missing Data")
Cancel = True
With cell.Offset(0, 1)
'
''~~> Do something
'
End With
Exit For
End If
Having said that if you still want to select that cell then you need to be on that sheet. There are two ways now. One is like I mentioned in the comment above.
Add Sheet2.Activate just before For Each cell In RAll in the Workbook_BeforeSave event or do that in the button's click event.
Sub Refresh_Pivot()
ActiveSheet.PivotTables("PivotTable1").PivotCache.Refresh
Sheet2.Activate
ActiveWorkbook.Save
End Sub
Another point. You might want to pass Cancel = True before the Exit For to disable the save?

Resources