If nothing selected macro uses whole worksheet instead of showing error message - excel

The macro offers the options to format selected text, which it does perfectly if some some cells are selected first.
However, the error handling is not working and I don't know why: if nothing is selected when I execute the macro, it formats the whole worksheet instead of showing an error message that requests a selection to be made. Any ideas why this isn't working?
Code from my UserForm ("UserForm1"):
Private Sub OKButton_Click()
Dim WorkRange As Range
Dim cell As Range
On Error Resume Next
Set WorkRange = Selection.SpecialCells _
(xlCellTypeConstants, xlCellTypeConstants)
If OptionUpper Then
For Each cell In WorkRange
cell.Value = UCase(cell.Value)
Next cell
End If
' code for the other options...
Unload UserForm1
End Sub
Code for calling the macro("Module1"):
Sub ChangeCase()
If TypeName(Selection) = "Range" Then
UserForm1.Show
Else
MsgBox "Select an area first.", vbCritical
End If
End Sub
I'm using MS Excel 2010. (Hope I didn't forget any relevant information.)

You could alter the userform code to something like:
Private Sub OKButton_Click()
Dim WorkRange As Range
Dim cell As Range
' If Selection.Cells.Count > 1 then (I corrected this to the line below, then it worked!
If Selection.Cells.Count = 1 then
If Msgbox("Only one cell selected - do you want to format the whole sheet?", vbyesno) = vbNo then Exit Sub
End If
On Error Resume Next
Set WorkRange = Selection.SpecialCells _
(xlCellTypeConstants, xlCellTypeConstants)
If OptionUpper Then
For Each cell In WorkRange
cell.Value = UCase(cell.Value)
Next cell
End If
' code for the other options...
Unload Me
End Sub

A Much Better Solution to If nothing is selected.
Public Sub IfNoSelection()
Application.ScreenUpdating = False
'Activate your Sheet
Sheets("Name Of Sheet Here").Select
'Select your range without selecting the header (column D)
Range(Cells(2, 4), Cells(Rows.Count, 4)).Select
'This Line Checks if what is selected is selected.
If WorksheetFunction.CountA(Selection) = 0 Then
Else
'enter code here
End If
Application.ScreenUpdating = True
End Sub

Related

How to find the next blank column in VBA and populate it using VBA form

I am trying to set up a VBA form that will find the next empty column in a table and populate the empty cells using values entered into a form.
The current code basically finds the next empty cell in column B and resets the form after submitting it.
I will post images of the table and form I am using below.
Code:
Private Sub addButton1_Click()
If surfactantCountBox.Value = "" Or wetterCountBox.Value = "" Or causticCountBox.Value = "" Then
If MsgBox("Form is not complete. Do you want to continue?", vbQuestion + vbYesNo) <> vbYes Then
UserForm1.surfactantCountBox.SetFocus
Exit Sub
End If
End If
Call findEmpty
Call resetForm
End Sub
Sub resetForm()
surfactantCountBox.Value = ""
wetterCountBox.Value = ""
causticCountBox.Value = ""
UserForm1.surfactantCountBox.SetFocus
End Sub
Sub findEmpty()
Dim ws As Worksheet
Set ws = ActiveSheet
For Each cell In ws.Columns(2).Cells
If IsEmpty(cell) = True Then cell.Select: Exit For
Next cell
End Sub
ws.Columns(2) refers to column B - your code is looking at each cell in column B, so will return the last row if anything.
Having said that, you don't have to look at each row/column. Manually you can find the last column by going to the last cell - e.g. cell XFD2 and pressing Ctrl + Left which will take you to the last column in row 2.
To do this in code:
Sub findEmpty()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim NextEmptyCell As Range
With ws
'This is the same as going to XFD2 and pressing Ctrl+Left and then going one cell right.
Set NextEmptyCell = .Cells(2, .Columns.Count).End(xlToLeft).Offset(, 1)
End With
Debug.Print NextEmptyCell.Address
End Sub
This is one way to find the next empty column in row 2.
Set rngEmpty = ActiveSheet.Cells(2, Columns.Count).End(xlToRight).Offset(, 1)
We could incorporate that into the rest of the code to add the data from the userform.
Private Sub addButton1_Click()
Dim rngEmpty As Range
If surfactantCountBox.Value = "" Or wetterCountBox.Value = "" Or causticCountBox.Value = "" Then
If MsgBox("Form is not complete. Do you want to continue?", vbQuestion + vbYesNo) <> vbYes Then
Me.surfactantCountBox.SetFocus
Exit Sub
End If
End If
Set rngEmpty = ActiveSheet.Cells(2, Columns.Count).End(xlToRight).Offset(, 1)
With rngEmpty
.Value = Me.surfactantCountBox.Value
.Offset(1).Value = Me.causticCountBox.Value
.Offset(2).Value = Me.wetterCountBox.Value
End With
Call resetForm
End Sub

Trying to combine two parts of VBA coding into one

First let me say that I am freshly new to VBA coding. My spreadsheet has 8 tabs(1 hidden and 1's a chart). Of the other 6 tabs, I would like the code to be able to run on them as well, I just don't know how. I have two sets of code and I am trying to combine them. They are event related codes. I can get them both to run separately but only on a specified sheet. I'm testing them on the "New" tab. The first code sorts the rows after the date is entered into column "H". The other code will cut and paste the entire row into the corresponding tab based on a selection from the drop down list in column "O". I created a call function for both however, only the first code will do anything. Here is what I have so far:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngChng As Range
Set rngChng = Intersect(Target, Range("H:H"))
If rngChng Is Nothing Then Exit Sub
If Target.Cells.Count > 1 Then Exit Sub
Application.ScreenUpdating = False
Call AutoSort(rngChng)
Set rngChng = Intersect(Target, Range("O:O"))
If rngChng Is Nothing Then Exit Sub
If Target.Cells.Count > 1 Then Exit Sub
Call CopyNPaste(rngChng)
Application.ScreenUpdating = True
End Sub
Sub AutoSort(rngChng As Range)
Range("A2:O1000").Sort Key1:=Range("H1"), Order1:=xlAscending, Header:=xlNo
End Sub
Sub CopyNPaste(rngChng As Range)
Dim ws As Worksheet
For Each ws In Sheets
If ws.Name <> "New" Then
If ws.Name = Target Then
Target.EntireRow.Copy Sheets(ws.Name).Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
Target.EntireRow.Delete Shift:=x1Up
End If
End If
Next ws
End Sub
To run the same code from many sheets move the code to a module. Use insert->module on the menu bar, if there are no others it will be named Module1.
In each relevant sheet add the code
Private Sub Worksheet_Change(ByVal Target As Range)
Call Module1.sortOrCopy(Target)
End Sub
Put the sortOrCopy sub in the module. I would suggest using the Target.column
value rather than Intersections to control the program flow.
Put the target.cells.count check once at the start. Pass parameters to your 2 subs.
Sub sortOrCopy(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
Dim ws As Worksheet
Set ws = Target.Parent
If Target.Column = 8 Then ' col H
Call AutoSort(ws)
ElseIf Target.Column = 15 Then ' col O
Call CopyNPaste(Target)
End If
End Sub
For the AutoSort sub the only parameter required is the sheet which will be Target.parent.
You can set the sort range rather than hard coding it using .end(xlUp.row as you have in the other sub.
Sub AutoSort(ws As Worksheet)
Dim iLastRow As Long
' last row of sort range
iLastRow = ws.Range("H" & Rows.Count).End(xlUp).Row
Application.ScreenUpdating = False
Range("A2:O" & iLastRow).Sort Key1:=Range("H1"), Order1:=xlAscending, Header:=xlNo
Application.ScreenUpdating = True
End Sub
For the sub CopyNPaste, pass the Target so that the source,row and destination can be determined.
Try to structure the code in simple steps by not doing too much in one line. If the code doesn't work as expected it is easier then to add debug.print or msgBox statements at the various steps. Comment out the If .. End if you don't want user confirmation of the change.
Sub CopyNPaste(Target)
Dim wsCopyTo As Worksheet, iInsertRow As Long, text As String
Set wsCopyTo = Sheets(Target.Value)
' find last row on CopyTo sheet, insert below
iInsertRow = 1 + wsCopyTo.Range("A" & Rows.Count).End(xlUp).Row
text = "Copy line to sheet " & wsCopyTo.Name & " row " & iInsertRow
If MsgBox(text, vbYesNo) = vbYes Then
With Target.EntireRow
.Copy wsCopyTo.Range("A" & iInsertRow)
.Delete Shift:=xlShiftUp
End With
End If
End Sub

Application.Goto Target Cell Not in View

I have created a simple Excel Macro which is triggered when a user clicks on a cell in a worksheet (worksheet1). Basically the macro takes the value of the cell which was clicked on and selects a target cell in a separate worksheet (worksheet2) that has the same value.
The problem is that about 20% of the time after being directed to worksheet2, the target cell is highlighted but is just out of view, i have to scroll down a couple of rows to see it. I want to be able to ensure that the target cell is always in view after the user is directed to it, but I am not sure how this can be achieved.
This is in Excel 2016.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If ActiveCell.Column = 1 Then
If Target.Cells.Count = 1 Then
Application.ScreenUpdating = False
Dim c As Range
Dim ans As String
Dim Lastrow As Long
ans = ActiveCell.Value
Lastrow = Sheets("worksheet2").Cells(Rows.Count, "A").End(xlUp).Row
For Each c In Sheets("worksheet2").Range("A2:A" & Lastrow)
If c.Value = ans Then Application.Goto Reference:=Sheets("worksheet2").Range(c.Address): Exit Sub
Next
End If
End If
Exit Sub
End Sub
You can use find to find the selected item in sheet2 then just select the sheet and the found cell
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim s As Range
If Target.Column = 1 Then
Set s = Worksheets("Sheet2").Range("B:B").Find(what:=Target, lookat:=xlWhole)
If Not s Is Nothing Then
Worksheets("Sheet2").Activate
s.Select
Else: MsgBox Target.Value & " is not found in sheet 2"
End If
End If
End Sub

Be able to select next cell down every time button is clicked Excel VBA

Below is the code that I have so far I am able to click the button and every time the button is clicked the cell selection is moved down the row by 1.
What I need is to start the selection on F3 and select down until about F35 but when I range it doesn't select the cells one by one.
Here is my code:
Dim rng As Range
Dim row As Range
Dim cell As Range
Set rng = Range("F2")
rng.Select
For Each row In rng.Rows
For Each cell In row.Cells
ActiveCell.Offset(1, 0).Select
Next cell
Range("G66") = ActiveCell
Next row
if you have a Form button called Button1 then attach it a sub called Button1_Click() (or whatever, but be consistent with the name of the attached Sub) and place the following code in any module:
Option Explicit
Dim notFirst As Boolean
Dim rng As Range
Sub Button1_Click()
If notFirst Then
If rng.row = 35 Then
MsgBox "Sorry: you've already reached last valid cell in column F"
Exit Sub
Else
Set rng = rng.Offset(1)
End If
Else
Set rng = Range("F3")
notFirst = True
End If
Range("G66").Value = rng.Value
End Sub
if you have a ActiveX button called Button1 then write the same code as above in its sheet code pane

Macro that searches with the name a cell from a selection of items from a list and finds it in another sheet

I am new in VBA and I want to write a program that when I manually select 1 or more items from a list the code searches with the name of the item and picks it from another sheet, copies the whole row and pastes it in a 3rd sheet. Is that possible? Preferably with a click of a button the selection is made. Thanks a lot!
Here is an example.
Sub FindAndMove()
Dim Finder As Range
Dim TheItem As Variant
With Sheets("Sheet1")
If Selection.CountLarge = 1 And Not Intersect(Selection, .Range("A2:A11")) Is Nothing Then
TheItem = Selection.Value
Else
MsgBox ("Please select an item from the list")
Exit Sub
End If
End With
With Sheets("Sheet2")
Set Finder = .Range("A:A").Find(TheItem, LookAt:=xlWhole)
If Finder Is Nothing Then
MsgBox ("Item not found!")
Exit Sub
End If
With Sheets("Sheet3")
Finder.EntireRow.Copy .Range("A" & .UsedRange.Rows.CountLarge + 1)
.Select 'Optional - show sheet 3
End With
End With
End Sub
Walking through the code:
When they click the button, if they only select 1 cell that's in our list.
Get the value of the item they selected
On Sheet2 - go find that value in column A
If you find it, copy the entire row to the end of Sheet3
You can modify the code by changing the sheet names in Sheet("Sheet1") to whatever you want.
You can also change the list range by changing .Range("A2:A11")
You can change the range to search by changing .Range("A:A")
Sheet 1:
Sheet 2:
Sheet 3: (after we select item 3 and click Find and Move)
Error Handling:
Edit:
Code to find multiple occurrences using FindNext
Sub FindAndMove()
Dim Finder As Range
Dim FirstAddress As Variant
Dim TheItem As Variant
With Sheets("Sheet1")
If Selection.CountLarge = 1 And Not Intersect(Selection, .Range("A2:A11")) Is Nothing Then
TheItem = Selection.Value
Else
MsgBox ("Please select an item from the list")
Exit Sub
End If
End With
With Sheets("Sheet2")
Set Finder = .Range("A:A").Find(TheItem, LookAt:=xlWhole)
If Finder Is Nothing Then
MsgBox ("Item not found!")
Exit Sub
End If
FirstAddress = Finder.Address
Do
With Sheets("Sheet3")
Finder.EntireRow.Copy .Range("A" & .UsedRange.Rows.CountLarge + 1)
End With
Set Finder = .Range("A:A").FindNext(Finder)
Loop While Not Finder Is Nothing And Finder.Address <> FirstAddress
End With
Sheets("Sheet3").Select 'Optional - Select Sheet3 After.
End Sub

Resources