Auto-tabbing between fields in Excel Workbook - excel

The following VBA script for an Excel sheet allows an individual to type text into a cell and then automatically jump to the next cell in the array once they hit enter.
However, this requires someone to type into every cell for the script to advance to the next cell in the array below and does not recognize tab, only enter.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim tabArray As Variant
Dim i As Long
tabArray = Array("B5", "C6", "D7", "E8")
Application.ScreenUpdating = False
For i = LBound(tabArray) To UBound(tabArray)
If tabArray(i) = Target.Address(0, 0) Then
If i = UBound(tabArray) Then
Me.Range(tabArray(LBound(tabArray))).Select
Else
Me.Range(tabArray(i + 1)).Select
End If
End If
Next i
Application.ScreenUpdating = True
End Sub
I'd like to let the person hit tab or enter if they want to skip the given field and advance without typing anything in the cell.

You can also just protect the sheet and have the input cells unlocked.
Right Click on the Cell, choose "Format cells".
Then, go to Protection Tab, and uncheck "Locked".
Once the input cells are unlocked, go to the "Review" Ribbon, and click on Protect Sheet. Uncheck "Select locked cells" and it should only allow you to click on the cells that are unlocked, and can press Tab repeatedly to go to the next available cell.

Protecting the sheet and unlocking the data-entry cells as suggested by #Basher is probably a better solution IMO, but this sort-of works. Couple of notes:
To "break into" the tab sequence you need to select one of the data-entry cells
To "break out" of the tab sequence (so you can select some other cell maybe) you can make a multi-cell selection.
Code:
Dim lastCellAddress As String
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim tabArray As Variant
Dim i As Long, addr, mCurr, indx, mPrev
If Target.Cells.CountLarge = 1 Then
tabArray = Array("B5", "C6", "D7", "E8")
addr = Target.Address(False, False)
mCurr = Application.Match(addr, tabArray, 0)
If IsError(mCurr) Then 'current selection isn't a data entry cell
If lastCellAddress <> "" Then
'was user previously in a data entry cell?
mPrev = Application.Match(lastCellAddress, tabArray, 0)
If Not IsError(mPrev) Then
'mPrev is 1-based but tabArray is 0-based...
indx = IIf((mPrev - 1) < UBound(tabArray), mPrev, 0)
On Error GoTo haveError
Application.EnableEvents = False
Me.Range(tabArray(indx)).Select '<< select the next entry cell
Application.EnableEvents = True
End If
End If
End If
lastCellAddress = Selection.Address(False, False)
Else
lastCellAddress = "" 'breaks out of the sequence
End If
Exit Sub
haveError:
Debug.Print Err.Description
Application.EnableEvents = True
End Sub

You don't need VBA to achieve this task - it's a built-in Excel functionality.
Simply select your data entry range and after inputting the desired value into the first cell hit TAB, it will take you to the next highlighted cell - either to the right of the current one or to the next row if you were at the end of the row.

Related

Call a hiding macro with a checkbox

I wanted to make a checkbox, calling a macro that hides and unhides columns on Excel worksheet with specific value in cell, but it is not working
I tried the following VBA script
Sub Hide_Forecasts()
Dim c As Range
For Each c In Range("E12:CF12").Cells
If c.Value = "Forecast" Then
c.EntireColumn.Hidden = True
End If
Next c
End Sub
Sub Unhide_Forecasts()
Dim c As Range
For Each c In Range("E12:CF12").Cells
If c.Value = "Forecast" Then
c.EntireColumn.Hidden = False
End If
Next c
End Sub
Sub CheckBox_For()
If CheckBox1.Value = True Then
Call Hide_Forecasts
Else
Call Unhide_Forecasts
End If
End Sub
Please help me out
You haven't said what type of checkbox you're using - Form Control or ActiveX Control.
For an ActiveX Control right-click the control and select View Code.
Use this code that sits behind the worksheet (CheckBox1 will be named after your checkbox).
Private Sub CheckBox1_Click()
Dim Cell As Range
For Each Cell In Me.Range("E12:CF12")
If Cell.Value = "Forecast" Then
'Checkbox returns TRUE/FALSE - Hidden takes TRUE/FALSE so just connect the two up.
Cell.EntireColumn.Hidden = Me.CheckBox1.Value
End If
Next Cell
End Sub
For a Form Control right-click the control and select Assign Macro.
Place this code in a normal module.
Sheet1 is the codename for the sheet (that's the name not in brackets in the Project Explorer).
'Form Control can have three values:
' 1 = Checked
' -4146 = Unchecked
' 2 = Mixed - ignoring that this value may occur.
Public Sub Checkbox_For()
Dim ChkValue As Boolean
'Is value different from -4146? Returns TRUE = Checked or Mixed / FALSE = Unchecked
ChkValue = Sheet1.Shapes("Check Box 1").OLEFormat.Object.Value <> -4146
Dim Cell As Range
For Each Cell In Sheet1.Range("E12:CF12")
If Cell.Value = "Forecast" Then
Cell.EntireColumn.Hidden = ChkValue
End If
Next Cell
End Sub

How to fill a worksheet based on cell values from another worksheet

I have two worksheets ("Worksheet A" and "Worksheet B").
Worksheet A has a list of tests. Each row represent a test performed.
Column F has the value "Passed" or "Not Passed".
If "Not Passed", the entire row needs to be added automatically to "Worksheet B" which represent an action list.
Any suggestion on how to do this dynamically, i.e. without having to run a macro manually?
Use worksheet events. Alt + F11 to open VBA interface:
Double click "Sheet1" on the left hand side of the interface and paste this in:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.Count > 0 Then
update_sheet
End If
End Sub
Below where it says "Sheet1", right click on "Modules". Hover on insert and click "Add Module". Paste the following code into the module:
Sub update_sheet()
s1_rows = ThisWorkbook.Worksheets(1).Cells(ThisWorkbook.Worksheets(1).Rows.Count, "F").End(xlUp).Row
Set s1_rng = ThisWorkbook.Worksheets(1).Range("F1:F" & s1_rows)
s2_rows = 1
For Each cell In s1_rng
If cell.Value = "Not Passed" Then
cell.EntireRow.Copy
ThisWorkbook.Worksheets(2).Range("A" & s2_rows).PasteSpecial xlPasteValues
s2_rows = s2_rows + 1
End If
Next cell
Application.EnableEvents = True
End Sub
This can be improved, but should start you off.

If statement that only performs action when selection is within a specific column

I am trying to finish this macro that will open another workbook, copy, and paste the selected cells into the other workbook. I want to do this only when the selection is in column A and only when the selection contains data.
The if the selection contains data part is easy, however how can I make a statement that says if selection is not within column A, then MsgBox("Please select data")?
Here is the if statement so far, it still needs the part mentioned directly above.
'Warns if no QN#s are selected
If Selection = "" Then
MsgBox ("Please Select Your QN#s Before Running This Macro")
Exit Sub
End If
This seems to work for recognizing if the cells are within a certain column.
If Not Intersect(Selection, Range("A:A")) Is Nothing Then
'Proceed
Else
MsgBox ("Please Select Your QN#s Before Running This Macro")
Exit Sub
End If
Why not use a Worksheet_SelectionChange?
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Column <> 1 Then
MsgBox "Please Select Your QN#s Before Running This Macro", vbOKOnly, "Data Selection"
Else
RunMacro
End If
End Sub
Use this pattern of codes. This is just dealing with the selection and not detecting changes.
Dim a As Integer
Dim b As Integer
Dim c As String
a = Selection.Row
b = Selection.Rows.Count - 1
c = "A" & a & ":" & "A" & a + b
If ((Selection.Column = 1) And (WorksheetFunction.CountA(Range(c)) > 0)) Then
MsgBox "ready to go"
End If
In the above code the hidden rows with data will be considered.
Merged cells are considered as one cell with value and others are blanks( example: When you have merged A2:A5, then you have 3 blank cells)

How can I control which cells can receive user input and the order in which the cursor moves to each cell?

I would like for the user to only be allowed to input values into the cells listed below in the following order:
D3,C3,B9,B3,E2,D4,G4,I4,D5,G5,I5,D6,G6,I6,D7,G7,I7,D8,G8 and I8.
If you want to check the order without VBA, you can use Data Validation with formulas (this will take some time but you will have no code to write).
Select the second cell you want to check (C3 in your case)
In the Ribbon, go to Data > Data Validation
In the Allow:, choose Custom
In the field, put this formula: =IF(ISEMPTY(D3),FALSE,TRUE)
In the tab Error Alert, change the dialog to explain to the user what he should do, something like:
You have to fill cell D3 before filling cell C3.
For some extra information about Data Validation, you can have a look here.
[EDIT] The best way is probably to create vba that will automatically create these validations from an array
Open excel and select the cells mentioned by you. You can do this by keeping Ctrl key pressed while selecting the cells. Now right click and select format cells and go to the protection tab. In the protection tab, uncheck the Locked check box. Now protect the sheet and make sure that you check the option 'Select Unlocked Cells' (second checkbox in the list)
Here is the code to control the order using vba
Right-click on the sheet1 tab and "View Code".
Paste the following code into that sheet module.
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
On Error GoTo enditall
Application.EnableEvents = False
i = Array("D3", "C3", "B9", "B3", "E2", "D4", "G4", "I4", "D5", "G5", "I5", "D6", "G6", "I6", "D7", "G7", "I7", "D8", "G8", "I8")
k = Replace(Target.Cells.Address, "$", "")
If k = i(j) Then
Sheet1.Unprotect
Sheet1.Range(i(j)).Locked = True
Sheet1.Range(i(j + 1)).Locked = False
Sheet1.Range(i(j + 1)).Select
j = j + 1
Sheet1.Protect
End If
enditall:
Sheet1.Protect
Application.EnableEvents = True
End Sub
Now right click on sheet1 in the same window and select insert. From the insert menu click on Module. Now select the create module and paste the following code.
Public j
Sub Settings()
j = 0
Sheet1.Unprotect
Sheet1.Cells.Locked = True
Sheet1.Range("D3").Locked = False
Sheet1.Range("D3").Select
Sheet1.Protect
End Sub
Now run the macro settings every time you want to enter data to your sheet.
Here is the commented version of the code
'The code below should come in a module and should be run every time a change is required in the sheet
Public j 'declaring j as a public variable so that it can be accessed from any procedure in the excel project
Sub Settings()
j = 0 'sets j as zero
Sheet1.Unprotect 'unprotect the sheet
Sheet1.Cells.Locked = True 'locks all the cells in the sheet
Sheet1.Range("D3").Locked = False 'unlocks the first cell D3 and makes it editable
Sheet1.Range("D3").Select 'selects the cell D3
Sheet1.Protect 'reprotects the sheet
End Sub
'Following code should be entered in the code of sheet where the values need to be entered
Private Sub Worksheet_Change(ByVal Target As Excel.Range) 'the code runs when a cell in the excel sheet is changed
On Error GoTo enditall 'this handles error
Application.EnableEvents = False 'excel events are disabled
i = Array("D3", "C3", "B9", "B3", "E2", "D4", "G4", "I4", "D5", "G5", "I5", "D6", "G6", "I6", "D7", "G7", "I7", "D8", "G8", "I8") 'array with cells in order
k = Replace(Target.Cells.Address, "$", "") 'finds the cell address where the change was made
If k = i(j) Then 'checks whether the change was made in a cell in the array, we set the value of j to zero by running the macro settings shown below
Sheet1.Unprotect 'unprotects the sheet to make the changes
Sheet1.Range(i(j)).Locked = True 'makes the correspondig cell in the array locked after editing
Sheet1.Range(i(j + 1)).Locked = False 'unlocks the next cell in the array
Sheet1.Range(i(j + 1)).Select 'selects the next cell in the array
j = j + 1 'increments the value of j by 1
Sheet1.Protect 'reprotects the sheet
End If
enditall: 'the code below will run on an error, this code will run when value of j becomes more than the number of elements in array k
Sheet1.Protect 'protect the sheet
Application.EnableEvents = True 'enables excel events
End Sub
See the sample file at https://docs.google.com/open?id=0B3mN8H2AV4UCN2E5ZWMxNjEtMGZiZS00NzYzLWI2NDUtOTdmZjg3YzcyNGUw

How to highlight calculated fields in an Excel spreadsheet?

Is there a simple way to do this, via macro or otherwise? By calculated field I mean a field that is computed from other fields, versus raw entered values. By highlight I mean colored differently. I need this to better understand a large spreadsheet from a client.
To do it manually, press the F5 key to bring up the GoTo dialog. Click the Special Cells button. On the next screen, select Formulas (it's an option on the right).
Excel will select all of the cells that match. Now it's just a matter of applying formatting.
I'm going to assume you're only talking about cell formulas rather than VBA calculations here, since you could set the cell colour in your VBA procedure if you're doing it that way.
The way to do this is to check the cell for a formula after you're done with it, and change it's colour at that point. The relevant event here is Change, and the cell's HasFormula property will tell you whether the cell is a literal value, or calculated from a formula:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.HasFormula Then
Target.Interior.Color = vbRed
Else
' remove background colour entirely (i.e. No Fill)
Target.Interior.ColorIndex = xlColorIndexNone
End If
End Sub
TLDR;
Use Conditional Formatting with a Formula to highlight all cells that contain a formula.
Details
In MS Office 365 Version: 5.0.4667.1002, the following works
Select a range of cells.
Case1: Use Ctrl + A to select all cells.
Case2: Select a specific range.
Go to the Home tab, Styles section, and choose Conditional Formatting > New Rule.
The "New Formatting Rule" dialog will open.
Choose "Use a formula to determine which cells to format"
In the textbox, add the following rule: =IsFormula(A1)
Case1: If you selected all cells, use A1 because it is the first cell.
Case2: If you selected a specific range, replace A1 with the first cell in your range.
Click Format...
The "Format Cells" dialog will open.
Choose the format you would like to apply. E.g. a yellow background.
Click OK.
All cells that have formulas will now have, for instance, a yellow background.
Screenshot
Excel has a built in feature of "Trace Dependents" (which shows arrows to show you the calculated cells)
Select the range containing your data.
Excel 2007 -> Formulas -> Trace Dependents
The code below should cycle through each sheet, highlighting every cells that starts with an '=' and colors it the desired color (currently colour 36 which is Light Yellow).
Sub HighLightFormulas()
Dim objSheet As Worksheet
Dim strOriginalSheet As String
Dim intMaxBlankCells As Integer
Dim intBlankColumns As Integer
Dim intBlankRows As Integer
Dim intCurrentColumn As Integer
Dim intCurrentRow As Long
intMaxBlankCells = 40
strOriginalSheet = ActiveSheet.Name
For Each objSheet In Worksheets
intBlankRows = 0
intCurrentRow = 1
intCurrentColumn = 1
Do While intCurrentRow <= 65536 And intBlankRows <= intMaxBlankCells
intBlankColumns = 0
intCurrentColumn = 1
Do While intCurrentColumn <= 256 And intBlankColumns <= intMaxBlankCells
If Left(objSheet.Cells(intCurrentRow, intCurrentColumn).Formula, 1) = '=' Then
objSheet.Cells(intCurrentRow, intCurrentColumn).Interior.ColorIndex = 36
End If
intCurrentColumn = intCurrentColumn + 1
Loop
If intCurrentColumn = intBlankColumns Then
intBlankRows = intBlankRows + 1
Else
intBlankRows = 0
End If
intCurrentRow = intCurrentRow + 1
Loop
Next objSheet
Worksheets(strOriginalSheet).Activate
Call MsgBox("The Highlighting process has completed", vbOKOnly, "Process Complete")
End Sub
It will also stop after 40 consecutive blank cells (to avoid processing all of a mostly blank sheet).
Hope this helps.
Simple solution:
Ctrl - ` (the key just above Tab)
You can use the Interior.ColorIndex property to change the active cell's background color:
ActiveCell.Interior.ColorIndex = 36
You may also apply it to a range:
Range("A1:A5").Interior.Color = RGB(200,160,35)
This applies to Excel 2003, I haven't used the latest version but I doubt this has changed.
You can usually record a macro and then look at the generated code to see how something is done.
I liked Craig's code here, because it keeps the layout of the existing worksheet and yet shows what is calculated and what is not 'at a glance', but I have reworked it a bit so it does a better job of working out the active area of sheets, and I added an 'UnhighlightFormulas' subroutine so one can easily undo the formatting (e.g. before printing). It has been tested in Excel 2007. Note that you will lose any other cell background colouring upon running this.
Option Explicit
Public Sub HighlightFormulas()
ColorFormulas (36) '36 is yellow
End Sub
Public Sub UnhighlightFormulas()
ColorFormulas (-4142) '-4142 is default
End Sub
Private Sub ColorFormulas(intColor As Integer)
Dim wshSheet As Worksheet
Dim rngRange As Range
Dim rngCell As Range
For Each wshSheet In Worksheets
Set rngRange = RangeInUse(wshSheet)
If Not rngRange Is Nothing Then
For Each rngCell In rngRange
If Left(rngCell.Formula, 1) = "=" Then
If rngCell.Interior.ColorIndex <> intColor Then rngCell.Interior.ColorIndex = intColor
Else
If rngCell.Interior.ColorIndex <> -4142 Then rngCell.Interior.ColorIndex = -4142 '-4142 is default
End If
Next
End If
Next
End Sub
Private Function RangeInUse(ws As Worksheet) As Range
Dim LastRow&, LastCol%
' adapted from http://www.beyondtechnology.com/geeks012.shtml
' Error-handling in case there is no data in worksheet
On Error Resume Next
With ws
LastRow& = .Cells.Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByRows).Row
LastCol% = .Cells.Find(What:="*", SearchDirection:=xlPrevious, SearchOrder:=xlByColumns).Column
End With
Set RangeInUse = ws.Range("A1", Cells(LastRow&, LastCol%))
End Function

Resources