Excel VBA copy cells on key press - vba

I'm using VBA to dynamically change the worksheet while typing into another cell. To do so, I've been using the API code that is found here:
Excel track keypresses
So the Sub Sheet_Keypress describes the desired action upon pressing a key.
However, I've been running into problems with the following:
Private Sub Sheet_KeyPress(ByVal KeyAscii As Integer, _
ByVal KeyCode As Integer, _
ByVal Target As Range, _
Cancel As Boolean)
Dim Col As String
Col = Chr(KeyAscii)
Worksheets(1).Range("G" & 4 & ":G" & 6).Value = _
Worksheets(1).Range(Col & 1 & ":" & Col & 3).Value
End Sub
When I go back to the sheet and type somewhere not in rows 1-3, the first keypress does fine. However, the second keypress is not recorded, and a further key gives Error 1004. What exactly is causing this error and is it possible to avoid it?

The problem appears to stem from the fact that Excel locks the worksheets from being changed whilst you are in "edit mode" (i.e. editing a value in a cell) until after you exit edit mode by pressing Enter or Escape.
So in your scenario, it looks like that when you first press a key it is registered fine and triggers your Sheet_Keypress, however, immediately after this, Excel goes into "edit mode" and then your subsequent call to Worksheets(1).Range("G" & 4 & ":G" & 6).Value fails as Excel locks the sheet. Nevertheless, Excel still registers the key press, and you can see this if, for example you change the last row of your routine to something like Application.StatusBar = Col.
As to ways around this, you would need to write code in such a way that it kicked Excel out of "edit mode" just after the key press. Unfortunately, there is no built-in way to do this, people have come up with various ways to do this (e.g. here)
There is a simpler solution, however, there are a couple of caveats: the value typed in will not display in the Excel sheet, and you will only be able to type a single value before your formula is updated (so no good for > column AA).
What you can do is to put the line Cancel = True into your sub above, and this will prevent the key press from going into Excel and thus activating the edit mode.

Related

Excel macro add two cells into one of them

I am absolutely new in macro and need a little help.
The two columns are "O" and "P". After a user writes a number into O2 and clicks double (or press a button) the macro has to add O2 and P2 together and show the result in P2. The problem is it should work for O3-P3, O4-P-4 until forever but O1-P1.
Can anybody help?
It would be great if the value was deleted in O2 after the double click (or button).
Look, usually you have to do some code and then you ask for input on what is not working/what you want to achieve. It is not cool to come and ask for free code.
That being said, the work here is kinda slow right now, and this wasn't that hard.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Not Intersect(Target, Range(Cells(2, 16), Cells(Cells(Rows.Count, 16).End(xlUp).Row, 16))) Is Nothing Then
Selection.Value = Selection.Value + Cells(Selection.Row, 15).Value
Cells(Selection.Row, 15).Value = vbNullString
End If
End Sub
You have to put this code on the sheet you want the Double Click to happen. If you don't know how, you do it by pressing ALT+F11. Then, on the left, you click on the sheet (In my case Plan1. It may vary based on the language your excel is. Here is a reference image
So, after you did this, you paste the code on the right and it will work. But how does it work?
The first line, Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) defines when the code will be executed. As you asked, it is on double click. If you want to change the trigger (Like in a button, for example), it's here you need to change.
The second line checks for the valid range of action. It checks if the Rangeis between Cells(2,16)
, which means Cell at Row 2 and Column 16 AKA P2and Cells(Cells(Rows.Count, 16).End(xlUp).Row, 16). This second part is weird because you mentioned "Go forever". So, instead of saying a specific row, like I did with row 2 on the first part, it now checks which is the last row of columns 16. The specific to get the last row is Cells(Rows.Count, 16).End(xlUp).Row, basically meaning this part of the range is Cell at last row and Column 16, AKA P..something
Since now we have our range of action, we need to make what you want, right? Adding them together. Which is line 3. Selection.Value returns the value of the cell you selected with the first click. Remember this will only work if it is within the range defined at line 2.
Since you have the value, you say that Selection.Value = Selection.Value + Cells(Selection.Row, 15).Value, so it sets the value to itself + the cell at the same row (Selection.Row) at column 15 (Column "O").
After that, it sets the value of the Column "O"to empty with vbNullString. If you want, you could replace it with 0, so this would also work.
And that's it. I just kindly ask for some research and some tries before asking for code. It is ok to get stuck. It is ok to not know how to do things. Don't feel afraid to ask for help. Just show some code next time.
The solution listed below applies simplified logic: as User enter the value in any cell in column O, this code will update column P (e.g. P3.Value =O3.Value + P3.Value) and then clear the content of the cell in column O (O3 in this example)
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
If Target.Column = 15 Then
Range("P" & Target.Row).Value = Target.Value + Range("P" & Target.Row).Value
Application.EnableEvents = False
Target.Value = ""
Application.EnableEvents = True
End If
End Sub
In this case you do not need any button or double_click event handler. Hope this may help

User-defined formula not updating after opening Excel 2013 and acknowledging Security Warning

After opening an Excel 2013 Worksheet, I get the following messages:
"Protected View - Be careful ..." and the button "Enable Editing"
"Security Warning - Some active content has been disabled. Click for more details." and the button "Enable Content".
These are expected messages that pop up in accordance to my Trust Center Settings, as I use macros and user-defined functions stored in my add-in.
The problem I'm recently experiencing is, that I'm get different results depending on how I acknowledge the "Security Warning":
a) If I click the "Enable Content" button, then my custom formulas return the #NAME? error in those cells that contain my user-defined formulas (e.g. ufCombineRanges). Re-calculating manually (F9) doesn't solve the problem. On the other hand, if I select the cell, edit it (F2) and press Enter, then the formula computes and continues to update correctly after that.
Result after pressing Security Warning "Enable Content" Button
b) If I click the "X" button, then my custom formulas compute and continue to update correctly.
Result after pressing Security Warning X Button
When using the user-defined formula in a brand new worksheet, this does not happen. The problem seems to be related to the way Excel updates the formulas after pressing that "Enable Content" button.
Any ideas what the cause could be, i.e. how this can be fixed?
Is there a function that can be called, that will update the user-defined formulas, other than the equivalent of F9?
Any help/ideas are greatly appreciated.
FYI: This is the code for the user-defined function:
Function ufCombineRanges(Separator As String, ParamArray Ranges() As Variant) As String
Application.Volatile
Dim i As Long
Dim TheRange As Variant
For i = LBound(Ranges) To UBound(Ranges)
For Each TheRange In Ranges(i)
If TheRange.Text <> "" Then
OutStr = OutStr & TheRange.Text & Separator
End If
Next TheRange
Next i
If Len(OutStr) > 0 Then
ufCombineRanges = Left(OutStr, Len(OutStr) - Len(Separator))
Else
ufCombineRanges = ""
End If
End Function
If the UDFs are in linked workbooks/add-ins, then you should be able to Edit Links.. Change-Source or Check-Status.
If the UDFs are defined in the same workbook, you might need to update all of the formulas. The easy way to do that is to Find/Replace all "=" with "=", which effectively changes all of your formulas without actually changing them, but it's enough to make Excel calculate the cells. Then save, and you shouldn't have the problem again.

VBA to create formula causes 1004 error when parentheses entered and causes an update values box when space is entered

I have a UserForm with TextBoxes that are used in creating new sheets from a template.
The gist of how this all works is that the VBA creates a copy of a "template sheet" that is hidden in the workbook. It names this copy based on the values entered by the user in the form's TextBox.
Additionally, I have a Summary sheet that is, as the name implies, a summary of different information entered in the sheet(s) the user has created.
To relieve the need for users to manually copy info into the Summary sheet, I'm using a formula tied to a function which will update the Summary sheet for them.
Now, when the user finishes entering their information into the UserForm, they click a Generate Workbook button which runs the code below which build formulas into the Summary sheet based on the info entered in the UserForm TextBox.
I have two issues when the VBA attempts to add a formula to the cells in the Summary Sheet.
Issue 1:
When a space is entered into the TextBox, it opens a "Update Values" dialog box when the user clicks the Generate Workbook button.
Example - Project 1234
Issue 2:
When parentheses are entered into the TextBox, a 1004 error occurs when the user clicks the Generate Workbook button.
Example - Project1234(Mobile)
If no parentheses and no spaces are entered, it all works fine.
There are 25 possible entries in the UserForm.
Each entry has three TextBoxes: ProjectNameTXT, SheetNameTXT, and ProjectNumTXT - each numbered 1-25 (i.e., ProjectNameTXT1, SheetNameTXT1, ProjectNumTXT1).
The two issues only pertain to the SheetNameTXT TextBoxes.
The csvRange is the function I mentioned earlier.
Here's the relevant code.
Code in UserForm1:
Private Sub GenerateWorkbook_Click()
Dim ws As Worksheet
Dim k As Long
Dim strSName
For k = 1 To 25
strSName = Me.Controls("SheetNameTXT" & k).Text
'Creates a data sheet for each project.
'Uses the MASTER SHEET as a template.
Set ws = ThisWorkbook.Worksheets("MASTER SHEET")
ws.Copy ThisWorkbook.Sheets(Sheets.count)
ActiveSheet.Name = strSName
ActiveSheet.Visible = xlSheetHidden
ThisWorkbook.Worksheets("Summary").Select
'THIS IS THE CODE CAUSING THE ISSUES
Range("B" & k + 3).Value = "=IF(ISERROR(csvRange(" & strSName & "!A2:A2500)),"""",csvRange(" & strSName & "!A2:A2500))"
Next k
Unload UserForm1
End Sub
Code for the Function csvRange:
Function csvRange(myRange As Range)
Dim csvRangeOutput
For Each entry In myRange
If Not IsEmpty(entry.Value) Then
'Create comma separated value
csvRangeOutput = csvRangeOutput & entry.Value & ", "
End If
Next
'Removes the last comma and space.
csvRange = Left(csvRangeOutput, Len(csvRangeOutput) - 2)
End Function
The csvRange function is a modified version of this function that muncherelli created:
https://superuser.com/a/241233
I'm not the world's greatest VBA coder, so apologies if my syntax or methodology sucks. Feel free to improve and provide suggestions if you are so inclined.
I searched StackOverflow and didn't find anything that would solve the problem. Tried some of the solutions suggested for similar problems but no luck getting them to fix these issues.
As always, your help and constructive criticism are much appreciated.
Put single quotes around your sheet name in your formula.
"=IF(ISERROR(csvRange('" & strSName & "'!A2:A2500)),"""",csvRange('" & strSName & "'!A2:A2500))

Need to run a VBA Macro on data refresh in excel

I am attempting to prompt a macro to run on a data refresh. I have the macro that needs to be run build, but I am having an issue with the new values not being used since the macros embedded in the sheet are called using ActiveX ComboBoxs.
I am finding several instances where people refer to AfterRefresh and BeforeRefresh, but I think I am misunderstanding how this would take effect and call a macro.
I currently am running ComboBoxs so I have multiple instances of
Private Sub ComboBox22_Change()
'do stuff
End Sub.
but I need the 'do stuff' to occur upon a data refresh, including refreshes that happen automatically and upon sheet open.
I don't want to tie the refresh to a specific box because the items that are refreshed are not dependent on any one instance of data change.
Any help is greatly appreciated.
Thank you.
Maybe a worksheet change event would help in this situation.
Right Click the sheet tab, select "View Code", Select "Worksheet" then "Change."
Code will automatically kick in when a specific range of cells has been changed.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub ' this stops code error if more than one cell is changed at once
If Not Application.Intersect(Target, Me.Range("A1:C10")) Is Nothing Then ' indicates the Target range
MsgBox "You have changed " & Target.Address & " to " & Target
End If
End Sub
You could also use Worksheet_pivottableupdate event to run the macro. You set it up in a similar way to davesexcel answer above.
The connection in question may not be a pivot table but you can use a small and fast pivot table as a trigger.
Set the pivot table to update at the same time as your connection (e.g. set to self refresh every 5 minutes or on workbook open).

Excel VBA - Code to move or copy worksheets without warnings

I am trying to create a macro that would act the same as right clicking a workbook tab, selecting move or copy, checking the copy option, selecting another open workbook and clicking ok but without the warnings. I found the code to disable warning and I was able to record a macro that does what I want but I don't know how to make it request which open workbook to copy to.
In short how do I make the following code work where WorksheetIWantToCopy is the one the user currently has selected and OpenWorkbookIWantToCopyToo.xlsx is a workbook to be selected by the user out of a list of open workbooks.
Application.DisplayAlerts = False
Sheets("**WorksheetIWantToCopy**").Select
Sheets("**WorksheetIWantToCopy**").Copy Before:=Workbooks( _
"**OpenWorkbookIWantToCopyToo.xlsx**").Sheets(1)
I appreciate any information anyone can provide. My team greatly appreciates your support (we currently have to hit ok on 25 warnings due to conflicts we don't really care about). Thx!
If the worksheet you want to copy will always be the active sheet then you can use ActiveSheet.
As for letting the user select a workbook, it can be as simple as using the InputBox.
Public Function getWorkbookName() As String
Dim i As Integer, sListOfWbks As String, sRsp As String
' build list of workbooks
For i = 1 To Workbooks.Count
sListOfWbks = sWbkList & vbCrLf & i & " - " & Workbooks(i).Name
Next i
sRsp = InputBox("Select workbook." & vbCrLf & sListOfWbks)
If IsNumeric(sRsp) Then
getWorkbookName = Workbooks(CInt(sRsp)).Name
Else
' user pressed cancel or entered invalid text
getWorkbookName = ""
End If
End Function
This basic example will of course list all workbooks, including hidden add-ins and the workbook you are moving away from.
This needs to be said before anything else: always, always, ALWAYS make use of .Copy instead of .Move when automatically shuffling excel workbooks with VBA. Move has inherent risks because it is a modification of the other file, and if your code misbehaves then you could lose all of the data you're working with.
First of all, know which workbook is which, with no ambiguity:
Dim wkbkDestination, wkbkTemporary As Workbook
Set wkbkDestination = Workbooks("OpenWorkbookIWantToCopyTo.xlsx")
Set wkbkTemporary = Workbooks.Open("WorkbookIWantToCopy.xlsx")
Next, Copy your desired tab to your destination workbook, rename the new tab to prevent errors, and close the second workbook, without saving.
wkbkTemporary.Worksheets("WorksheetIWantToCopy").Copy Before:=wkbkDestination.Worksheets(1)
wkbkDestination.Worksheets(1).Name = "WorkbookIWantToCopy"
wkbkTemporary.Close SaveChanges = False
Naturally, depending on the exact controls you intend to use, there are lots of ways this code could be implemented. From your description it is somewhat unclear what exact problem you're trying to solve and whether this is a one-off event you're trying to accomplish for a given list of files, or whether this function is to be used on an ongoing basis.