Worksheet.Select switching screens excel VBA - vba

I currently have 3 sheets: Input, Process, Output and a macro that uses values displayed on the input sheet and various stores on the process sheet. The problem is when the user presses a submit button linked to the macro on the input page the sheet switches to the Process sheet before displaying the Output sheet. I understand that this is because of this line of code:
Worksheets("Process").Select
However whenever I remove it from the macro everything goes madly out of range. Is there any way of selecting a sheet without actually visually moving to it? I need the macro to do its thing and then simply display the output sheet. Thanks in advance!

As #Jeeped stated and referenced, avoid using Select and Activate, in addition it is safer to qualify references.
For example you can use Range("A1").Value to get a value of the cell A1 in the currently active worksheet, but what if the user didn't have that sheet active at the time or another proc had moved the view? you could get the value of cell A1 from potentially any worksheet.
It would be best to create a reference to the worksheet and then send all your work through it, this way you do not need to change the active worksheet and there is no ambiguity about where the range values are coming from.
For example: -
Option Explicit
Dim WkSht_I As Worksheet 'Input
Dim WkSht_P As Worksheet 'Process
Dim WkSht_O As Worksheet 'Output
Public Sub Sample()
Set WkSht_I = ThisWorkbook.Worksheets("Input")
Set WkSht_P = ThisWorkbook.Worksheets("Process")
Set WkSht_O = ThisWorkbook.Worksheets("Output")
MsgBox "Input A1 = " & WkSht_I.Range("A1").Value
MsgBox "Process A1 = " & WkSht_P.Range("A1").Value
MsgBox "Output A1 = " & WkSht_O.Range("A1").Value
Set WkSht_O = Nothing
Set WkSht_P = Nothing
Set WkSht_I = Nothing
End Sub
Converting your procedures to this method should be safer and clearer and you can set the active sheet just once for it to show content while the others or being worked on.

#Gary's method is the best method to go with when you are working with multiple worksheets.
If you are working with only two sheets, (Considering you have activesheet and target sheet) I am going to recommend
With Worksheets("Process")
Debug.Print .Range("A1")
Debug.Print Range("A1")
End With
Notice "." infront of Range.
The "." indicates that it is part of With
In other words, .Range("A1") is same as Worksheets("Process").Range("A1")
Because second Range("A1") does not have "." it is same as Activesheet.Range("B1") even it's inside of the With-End
If the activesheet is Process Then the out put will be same
But when you select worksheet other than Process, because activesheet changed, the output will be different.
This will avoide using Select which changes the activesheet

Related

VBA - copy specific rows from one sheet into another sheet when user closes file

I'm new to VBA and I'm struggling a lot with a file I want to build.
I have a main Sheet that in a simple way looks like this (starting at column B - A is an empty column):
main
This is a simplified version just for the example. The first table of the sheet varies from B13 to O92, the second varies from B104 to O114 but some of those rows might be empty.
My goal is to join rows with content from the first area with rows with content from the second area in a different sheet (Sheet1), add to the left a column with 1s and "Cell 0" (content of cell B1). Using the example, the result would be something like this:
Sheet1
Sheet1 will stay hidden as I'm using it as a source of information to a different file. In fact, I may not need the 1s column if I find a way to copy information in a different way - I'm doing it like this (wsSource is Sheet1):
lRow = wsSource.Columns("A").Find(1, SearchDirection:=xlPrevious, LookIn:=xlValues, LookAt:=xlWhole).Row
wsSource.Range("B1:N" & lRow).Copy
I was trying to do it so Sheet1 is "emptied" when the file is opened and edited when file is closed - so that if new rows are added or information updated, it gets into Sheet1 every time.
I've tried several stuff I found online but couldn't make it to work. My main problem is adding the specified rows one after the others but I'm also struggling to reset Sheet1 every time the file is opened and automatically running the macro when file is closed.
Any help would be really appreciated.
Hopefully this will get you started. Both subs need to be pasted in VBE under ThisWorkBook rather module or sheet(n).
The first sub will execute when the workbook is open.
Are you sure you want to clear your sheet under these circumstances?
You will never have access to your table (without workarounds) since it will clear when opening every time.
If this is what you need, see the below method to clear a dynamic range (Col A - D down to last cell used in Col A) on Sheet1 every time the workbook that houses this code is opened.
Private Sub Workbook_Open()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim ClearRange As Range
Application.ScreenUpdating = False
With ws
.Visible = xlSheetVisible
.Range("A1:D" & .Range("A" & .Rows.Count).End(xlUp).Row).ClearContents
.Visible = xlSheetHidden
End With
Application.ScreenUpdating = True
End Sub
Next, the below sub will only execute before the book is closing. This is where the bulk of your code will go to build your table.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Application.ScreenUpdating = False
ThisWorkbook.Sheets(1).Visible = xlSheetVisible
'Code goes here
ThisWorkbook.Sheets(1).Visible = xlSheetHidden
Application.ScreenUpdating = True
End Sub
You will need to qualify your objects (Ranges, Cells, etc.) directly (which sheet) since the code will not be housed in a sheet. The first sub uses a With block to qualify ranges and the second sub directly qualifies all objects with ThisWorkbook.Sheets(1).
Lastly, I recommend writing your code to build your table inside a module (qualify ranges!) so you can test and debug without needing to close/open your book continuously. Once you have the code working in a module, you can copy and paste the code directly into the 2nd sub here and you are good to go!

Copy and paste data from different worksheet to another worksheet in a same excel spreadsheet

Sub Save7()
Dim NextRow As Range
Set NextRow = Range("AC" & Sheets("Sheet1").UsedRange.Rows.Count)
Sheet3.Range("AC14:AG14").Copy
Sheet1.Activate
NextRow.PasteSpecial Paste:=xlValues, Transpose:=False
Application.CutCopyMode = False
Set NextRow = Nothing
End Sub
My purpose of this code is to copy data ( Five columns of 'NO' in AC14 to AG14) from sheet 3 and paste to sheet 1 where the last active cell is at.
The code above is working well, however I made some modification to the sheet tab name for sheet 1. Sheet 1 is now called "Equipment stuffs", while sheet 3 name is remaining unchanged.
After those changes, the macro stopped working. The cause is probably because I don't know how to declare "Equipment stuffs" in the code .
There's no need to do copy/paste to move data from one place on the spreadsheet to another. You should simply assign the Value of the respective Range objects, for example:
Sheet1.Range("NamedRange2").Value = Sheet1.Range("NamedRange2").Value
Also, use code names for the sheets, instead of Sheets("SheetName"), and defined named for the ranges, instead of Range("AC14:AG14", otherwise your code will stop working if the user renames the sheet or inserts or deletes any rows above your reference.
If you want to automate this a little you could collect the active workbook and loop through each sheet using wb.Worksheets. Then collect the name with targetSheet.Name.
Option Explicit
Public Sub getSheet()
Dim wb As Workbook
Dim targetSheet As Worksheet
Set wb = ActiveWorkbook
For Each targetSheet In wb.Worksheets
Debug.Print targetSheet.Name
Next targetSheet
End Sub
I’m brazilian hehe, I understood your question , I’ve a code for alter the data in same worksheet (I’ll attach it here), for you to change the data in another worksheet, you need put on:
Worksheets("NameWorkSheet) Activate
for the VBA that’s refers to this tab.

Multi language Excel VBA Application

I basically created an Excel VBA application that manipulate Excel worksheets, so in the code, I use the string "Sheet1" to refer to the first sheet of a workbook, but when I try to use this application with the same code with a french version of Excel, it doesn't work until I translate "Sheet1" to "Feuil1". So my question is, is there a way to automatically adapt the code to any version of Excel ?
You can use the following ways to get a sheet from code:
(1) using by Sheets(sheet_index)
This way cannot be adapt because it take the sheet by sheet index (sheet index are start from 1). When sheet are change place, it cannot access the right sheet.So, it should not use.
For example: Set Feuil1Sheet = Sheets(1)
(2) using by (Name) of VBA editor
I think this way should not use never, because it takes the sheet by code name which can only visible by VBA editor(it shows as (Name) field in sheet properties). I think you are using this way for getting the first sheet. So, you not get the right sheet. One thing you need to know is that code name of every first sheet may not be Sheet1 always. It can be Sheet2 or Sheet4, etc.
For example: Set Feuil1Sheet = Sheet1
(3) using Worksheets("sheet-name") or Sheets("sheet-name")
This last way is a very compatible way and can be adapt in anywhere Excel because it take the sheet by its name. So, If names are equal, you will get the right sheet. So, use this for getting the sheet.
For example: Set Feuil1Sheet = Worksheets("Feuil1") or Set Feuil1Sheet = Sheets("Feuil1")
The only possible way I can think of to always reference "sheet1" in the local language is the following code.
Option Explicit
Public Sub GetLocalNameForNewSheets()
Dim strSheetName As String
Dim i As Long
i = ActiveWorkbook.Sheets.Count
ActiveWorkbook.Sheets.Add After:=Worksheets(i)
strSheetName = ActiveWorkbook.Worksheets(i + 1).Name
Application.DisplayAlerts = False
ActiveWorkbook.Worksheets(i + 1).Delete
Application.DisplayAlerts = True
Debug.Print strSheetName
For i = 1 To Len(strSheetName)
While IsNumeric(Mid(strSheetName, i, 1))
strSheetName = Replace(strSheetName, Mid(strSheetName, i, 1), "")
Wend
Next i
Debug.Print strSheetName
Debug.Print strSheetName & "1"
End Sub
Basically, I am asking Excel to create a new sheet and name it for me. Then, I am getting the new name which is "sheet" in the local language and remove from the string the number part. At the end, you can add the number "1" to reference the first sheet.

How to access a closed Excel Workbook using vlookup vba

I'm trying to create a Excel VBA macro that uses VLOOKUP to access a range of cells in a closed workbook. I'm not too good at using the VBA editor, but it doesn't seem to show a lot of useful information about errors.
Sub WorkBookWithData()
Dim currentWb As Workbook
Set currentWb = ThisWorkbook
Dim currentWs As Worksheet
Set currentWs = currentWb.Sheets(1)
Dim strFormula As String
strFormula = "=VLOOKUP(currentWs.Range("B2"),'Macintosh HD:Users:myself:Documents:l[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!A1:B222,2,false)"
currentWs.Range("C2").Formula = strFormula
End Sub
Excel VBA editor is hanging up on the "strFormula = "=VLOOKUP..." section.
Thanks
Reference from Siddharth Rout's comments.
The main problem in your code is this line:
strFormula = "=VLOOKUP(currentWs.Range("B2"),'Macintosh HD:Users:myself:Documents:l[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!A1:B222,2,false)"
because of this code currentWs.Range("B2"). We know that you want to indicate Range("B2") of Current Sheet(same sheet). So, you can use as follow:
strFormula = "=VLOOKUP(B2,'Macintosh HD:Users:myself:Documents:l[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!A1:B‌​222,2,false)"
Why? It can use just B2 because you set formula to a cell which is in the same sheet. So, it is not need to indicate the Sheet Name.
And If you want to set a cell which is from other sheet, you need to indicate Sheet Name in that case. So, should use as follow:
strFormula = "=VLOOKUP(" & currentWs.name & "!B2,'Macintosh HD:Users:myself:Documents:l[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!A1:B222,2,false)"
This looks nothing like what I had previously, but it works.
Sub Check_Master_Values()
Dim newCurWb As Workbook
Set newCurWb = Workbooks(2)
newCurWb.Activate
newCurWb.Sheets(1).Range("C2").Formula = "=VLOOKUP(B2,'Macintosh HD:Users:myself:Documents:[Master_Terms_Users.xlsm]Master_Terms_Users.csv'!$A$1:$B$269,2,FALSE)"
End Sub
In my first attempt, I didn't follow the chain of assignments from workbook, to sheets, to ranges. As you can see in this code, I Dim a new Workbook - then the big ah-ha moment, I needed to assign it to the correct open workbook. Then, I activated the workbook, and finally accessed the Sheets object and Range.
I also know now that my workbook selection number will vary depending on how many other workbooks are open. The ThisBook didn't work because somehow in the process, the workbook that ThisBook referenced, changed. That is probably also why my initial code didn't work, in addition to the improper coding in the VLOOKUP.
It would be good if there was a way to specify which workbook on the fly.
Thanks to everyone who gave help on the VLOOKUP part.

Why do Excel sheets have to be activated before selection?

This code
Sheets(1).Activate
Sheets(2).Range("A1").Select
will fail in VBA because you can only use Select on an object which is Active. I understand this is the case.
What element of the Excel datamodel causes this to be the case? I would think there is an implicit intent from a user/coder to Activate any object immediately prior to using Select - I do not understand why VBA would not make this assumption, and, I am assuming there is a reason this distinction exists.
What part of Excel's datamodel prevents selection without activation?
As brettdj pointed out, you do not have to activate the sheet in order to select a range. Here's a reference with a surprisingly large amount of examples for selecting cells/ranges.
Now as for the why do I have to active the sheet first? I do not believe it is a fault of the datamodel, but simply a limitation of the select method for Ranges.
From experimentation, it looks like there are two requirements to select a range in Excel.
Excel must be able to update the UI to indicate what is selected.
The ranges parent (I.E. the sheet) must be active.
To support this claim, you also cannot select a cell from a hidden sheet.
Sheets(1).Visible = False
Sheets(1).Activate
'The next line fails because the Range cannot be selected.
Sheets(1).Range("A1").Select
Simply put, when it comes to Ranges, you cannot select one you cannot see.
I would have claimed this is a limitation of select all together, except that you can actually select an object in a hidden sheet. Silly Excel.
I know that this is a bit late to the party, but I discovered a hack to do this...
Try this code:
Sheets(1).Activate
Sheets(2).Range("A1").Copy
Sheets(2).Range("A1").PasteSpecial xlPasteFormulas
Application.CutCopyMode = False
Note that it is a hack, but it does the trick!!
#Daniel Cook: thanks for your response, but unfortunately Excel itself doesn't play by the same rules imposed on Excel Macros...
To illustrate, I'll briefly present my current problem...
I'm attempting to re-set a table's contents to a common state. This method will be applied to multiple tables across various sheets:
Public Sub restoreTable()
Dim myTableSheet As Worksheet: Set myTableSheet = Range("Table1").Parent
Dim myTable As ListObject: Set myTable = myTableSheet.ListObjects("Table1")
' --- Clear Table's Filter(s)
If myTable.ShowAutoFilter Then ' table has auto-filters enabled
Call myTable.Range.AutoFilter ' disables autofilter
End If
myTable.Range.AutoFilter ' re-apply autofilter
' --- Sort by Sequence number
Call myTable.Sort.SortFields.Clear ' if not cleared, sorting will not take effect
myTable.Sort. _
SortFields.Add Key:=Range("Table1[[#Headers],[#Data],[Column1]]"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
myTable.Sort.Header = xlYes
myTable.Sort.Orientation = xlTopToBottom
myTable.Sort.SortMethod = xlPinYin
Call myTable.Sort.Apply
myTable.Sort.SortFields.Clear
End Sub
For each use-case below, Table1 is found in Sheet1
Use-Case 1:
Activate Sheet1, select range A1
Run restoreTable
observe: range Sheet1 A1 remains selected
Use-Case 2:
Activate Sheet1, select range A1
Activate Sheet2
Run restoreTable
observe: range Sheet1 A1 is not selected, instead the range Table1[#Data] is selected
Solution
It's absolutely terrible, but this is the best solution I could find
Public Sub resotreTable_preserveSelection()
Dim curSheet As Worksheet: Set curSheet = ActiveSheet
Dim tableSheet As Worksheet: Set tableSheet = Range("Table1").Parent
' Change Sheet
tableSheet.Activate
' Remember Selection / Active Ranges
Dim originalSelection As Range: Set originalSelection = Selection
Dim originalActiveCell As Range: Set originalActiveCell = ActiveCell
' Restore Table
Call restoreTable
' Restore Old Selection
originalSelection.Select
originalActiveCell.Activate
' Change Back to old sheet
curSheet.Activate
End Sub
Note: in this case, the original* ranges are not necessary, but you get the point: you can buffer the original selection and restore it when you're finished
I really don't like excel
Of course you don't have to select or activate the sheet to select/activate the cell. My way is to use "On Error Resume Next" and "On Error GoTo 0". Code below selects first cell in every worksheet of a workbook without selecting it. The worksheets are even very hidden on this stage.
On Error Resume Next
For i_wks = 1 To wb_macro.Worksheets.Count
wb_macro.Worksheets(i_wks).Cells(1).Select
Next i_wks
On Error GoTo 0