I have a worksheet that I am trying to enter new product details in.
One column requires a 5 digit number. What I would like my code to do is once this number is entered if it is not exactly a 5 digit number, send a warning message box asking to check the job number.
The warning message should apply if the entry is <>5 digits and also if it contains letters. However whatever the entry I still want the cell to accept the entry.
In your case I would use Excel Data Validation
Simply change range to be between 9999 and 100000, so it will be a 5 digit number. Or you can use a standard Excel formula to validate the entry.
At the data validation dialog you can also define an alert or error mensage.
For more information: Excel reference on data validation
This is coded for column B.
Place the following in the worksheet code area:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range, r As Range, s As String, L As Long
Dim addy As String
Set rng = Intersect(Range("B:B"), Target)
If rng Is Nothing Then Exit Sub
For Each r In rng
s = r.Text
L = Len(s)
addy = r.Address(0, 0)
If L <> 5 Then
MsgBox "Please check " & addy
Else
For i = 1 To 5
If Not IsNumeric(Mid(s, i, 1)) Then
MsgBox "Please check " & addy
End If
Next i
End If
Next r
End Sub
Because it is worksheet code, it is very easy to install and automatic to use:
right-click the tab name near the bottom of the Excel window
select View Code - this brings up a VBE window
paste the stuff in and close the VBE window
If you have any concerns, first try it on a trial worksheet.
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE windows as above
clear the code out
close the VBE window
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
To learn more about Event Macros (worksheet code), see:
http://www.mvps.org/dmcritchie/excel/event.htm
Macros must be enabled for this to work!
Related
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))
I want to create a secure timestamp on my Excel sheet. The VBA I am using will automatically add the current users user name, the time, and the date when a user puts information into column A. So if the users puts something into cell A1 then B1 automatically gets filled with their username and C1 gets filled with the time and date. The only problem is that this method isn’t secure because the user could alter the information after it is automatically populated. I would like to add code to this VBA so it will lock all three cells after the information is populated.
I was planning on using the Protect Sheet feature and only allowing users to “Select unlocked cells” So if the VBA could auto lock the cells then the users would not be able to alter the information.
Moreover I have used Me.Unprotect before changing cells and Me.Protect after that still it is not working
Any help would be much appreciated!
Assume that we start with all the cells on the worksheet unlocked and the sheet password-protected with the password:
6LgSdHjc2uOssv0e1LDI
The following Event Macro will:
unprotect the workbook
detect entries in column A
place the username in column B and the date/timestamp in column C
lock the entries in columns A,B,C
re-protect the worksheet.
This goes in the Worksheet code area:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range, MyPass As String, sh As Worksheet
Dim unit As Range
Set A = Range("A:A")
MyPass = "6LgSdHjc2uOssv0e1LDI"
Set sh = ActiveSheet
If Intersect(Target, A) Is Nothing Then Exit Sub
Set unit = Union(Target, Target.Offset(0, 1), Target.Offset(0, 2))
Application.EnableEvents = False
sh.Unprotect (MyPass)
unit.Locked = False
Target.Offset(0, 1) = Environ("Username")
Target.Offset(0, 2) = Now()
unit.Locked = True
sh.Protect (MyPass)
Application.EnableEvents = True
End Sub
Because it is worksheet code, it is very easy to install and automatic to use:
right-click the tab name near the bottom of the Excel window
select View Code - this brings up a VBE window
paste the stuff in and close the VBE window
If you have any concerns, first try it on a trial worksheet.
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE windows as above
clear the code out
close the VBE window
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
To learn more about Event Macros (worksheet code), see:
http://www.mvps.org/dmcritchie/excel/event.htm
Macros must be enabled for this to work!
I'm creating a very basic excel workbook for my own personal record, and what I'm wanting to do is having a record timestamp(in column B) whenever I add/edit the value of column A. As I've never dealt with VBA before, but with other programming languages, can someone point me into a right direction to start with?
I'm thinking of opening the macros to write a sub, then using a for loop to screen the whole columns and set the timestamp using TODAY() by seeing which cells in colA have been changed. But I reckon this will be a very inefficient method (as whole worksheet screening is required), I wonder what's the proper way of doing this? Thank you.
Include the following event macro in the worksheet code area:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range, L As Long, r As Range, rInt As Range
Set A = Range("A:A")
Set rInt = Intersect(A, Target)
If rInt Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each r In rInt
r.Offset(0, 1) = Now()
Next r
Application.EnableEvents = True
End Sub
Because it is worksheet code, it is very easy to install and automatic to use:
right-click the tab name near the bottom of the Excel window
select View Code - this brings up a VBE window
paste the stuff in and close the VBE window
If you have any concerns, first try it on a trial worksheet.
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE windows as above
clear the code out
close the VBE window
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
To learn more about Event Macros (worksheet code), see:
http://www.mvps.org/dmcritchie/excel/event.htm
Macros must be enabled for this to work!
I have an Excel sheet with columns A to F to be filled out by different users. Once one row is completed another user (control user) enteres "done" in column G. As soon as the user entered "done" in coulmn G, I want a VBA script to lock the entire row (column A to G) so that no one can change any of that row entries any longer. Is that possible using VBA scripting?
We must start with all cells un-protected and the sheet Locked
Enter the following Event macro in the worksheet code area:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim N As Long
N = Target.Row
If Intersect(Target, Range("G:G")) Is Nothing Then Exit Sub
If Target.Text <> "Done" Then Exit Sub
ActiveSheet.Unprotect
Range("A" & N & ":G" & N).Locked = True
ActiveSheet.Protect
End Sub
Because it is worksheet code, it is very easy to install and automatic to use:
right-click the tab name near the bottom of the Excel window
select View Code - this brings up a VBE window
paste the stuff in and close the VBE window
If you have any concerns, first try it on a trial worksheet.
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE windows as above
clear the code out
close the VBE window
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
To learn more about Event Macros (worksheet code), see:
http://www.mvps.org/dmcritchie/excel/event.htm
Macros must be enabled for this to work!
The Problem
Assume that the active cell contains a formula based on the INDEX function:
=INDEX(myrange, x,y)
I would like to build a macro that locates the value found value by INDEX and moves the focus there, that is a macro changing the active cell to:
Range("myrange").Cells(x,y)
Doing the job without macros (slow but it works)
Apart from trivially moving the selection to myrange and manually counting x rows y and columns, one can:
Copy and paste the formula in another cell as follows:
=CELL("address", INDEX(myrange, x,y))
(that shows the address of the cell matched by INDEX).
Copy the result of the formula above.
Hit F5, Ctrl-V, Enter (paste the copied address in the GoTo dialog).
You are now located on the very cell found by the INDEX function.
Now the challenge is to automate these steps (or similar ones) with a macro.
Tentative macros (not working)
Tentative 1
WorksheetFunction.CELL("address", ActiveCell.Formula)
It doesn't work since CELL for some reason is not part of the members of WorksheetFunction.
Tentative 2
This method involves parsing the INDEX-formula.
Sub GoToIndex()
Dim form As String, rng As String, row As String, col As String
form = ActiveCell.Formula
form = Split(form, "(")(1)
rng = Split(form, ",")(0)
row = Split(form, ",")(1)
col = Split(Split(form, ",")(2), ")")(0)
Range(rng).Cells(row, CInt(col)).Select
End Sub
This method actually works, but only for a simple case, where the main INDEX-formula has no nested subformulas.
Note
Obviously in a real case myrange, x and ycan be both simple values, such as =INDEX(A1:D10, 1,1), or values returned from complex expressions. Typically x, y are the results of a MATCH function.
EDIT
It was discovered that some solutions do not work when myrange is located on a sheet different from that hosting =INDEX(myrange ...).
They are common practice in financial reporting, where some sheets have the main statements whose entries are recalled from others via an INDEX+MATCH formula.
Unfortunately it is just when the found value is located on a "far" report out of sight that you need more the jump-to-the-cell function.
The task could be done in one line much simpler than any other method:
Sub GoToIndex()
Application.Evaluate(ActiveCell.Formula).Select
End Sub
Application.Evaluate(ActiveCell.Formula) returns a range object from which the CELL function gets properties when called from sheets.
EDIT
For navigating from another sheet you should first activate the target sheet:
Option Explicit
Sub GoToIndex()
Dim r As Range
Set r = Application.Evaluate(ActiveCell.Formula)
r.Worksheet.Activate
r.Select
End Sub
Add error handling for a general case:
Option Explicit
Sub GoToIndex()
Dim r As Range
On Error Resume Next ' errors off
Set r = Application.Evaluate(ActiveCell.Formula) ' will work only if the result is a range
On Error GoTo 0 ' errors on
If Not (r Is Nothing) Then
r.Worksheet.Activate
r.Select
End If
End Sub
There are several approaches to select the cell that a formula refers to...
Assume the active cell contains: =INDEX(myrange,x,y).
From the Worksheet, you could try any of these:
Copy the formula from the formula bar and paste into the name box (to the left of the formula bar)
Define the formula as a name, say A. Then type A into the Goto box or (name box)
Insert hyperlink > Existing File or Web page > Address: #INDEX(myrange,x,y)
Adapt the formula to make it a hyperlink: =HYPERLINK("#INDEX(myrange,x,y)")
Or from the VBA editor, either of these should do the trick:
Application.Goto Activecell.FormulaR1C1
Range(Activecell.Formula).Select
Additional Note:
If the cell contains a formula that refers to relative references such as =INDEX(A:A,ROW(),1) the last of these would need some tweaking. (Also see: Excel Evaluate formula error). To allow for this you could try:
Range(Evaluate("cell(""address""," & Mid(ActiveCell.Formula, 2) & ")")).Select
This problem doesn't seem to occur with R1C1 references used in Application.Goto or:
ThisWorkbook.FollowHyperlink "#" & mid(ActiveCell.FormulaR1C1,2)
You could use the MATCH() worksheet function or the VBA FIND() method.
EDIT#1
As you correctly pointed out, INDEX will return a value that may appear many times within the range, but INDEX will always return a value from some fixed spot, say
=INDEX(A1:K100,3,7)
will always give the value in cell G3 so the address is "builtin" to the formula
If, however, we have something like:
=INDEX(A1:K100,Z100,Z101)
Then we would require a macro to parse the formula and evaluate the arguments.
Both #lori_m and #V.B. gave brilliant solutions in their own way almost in parallel.
Very difficult for me to choose the closing answer, but V.B. even created Dropbox test file, so...
Here I just steal the best from parts from them.
'Move to cell found by Index()
Sub GoToIndex()
On Error GoTo ErrorHandler
Application.Goto ActiveCell.FormulaR1C1 ' will work only if the result is a range
Exit Sub
ErrorHandler:
MsgBox ("Active cell does not evaluate to a range")
End Sub
I associated this "jump" macro with CTRL-j and it works like a charm.
If you use balance sheet like worksheets (where INDEX-formulas, selecting entries from other sheets, are very common), I really suggest you to try it.