VBA Macro Coding - vba

I've been trying to make a Macro, but I'm having trouble figuring it out. Here's what it should do.
Macro function: When the macro is used it should switch to either a sheet called "Products" only if the current tab is NOT the "Products" tab, and if the current tab is the "Products" tab is should go to the previously visited tab.
Use: Let's say I'm on sheet index 3 and use the macro--it should activate the "Products" tab, and if I press it again it should return me to sheet index 3.
I've been trying to use ActiveSheet.Index and Sheets("Products").Index in some way, but I think I need to use something beyond my current knowledge of Visual Basics. I haven't used the Public function when declaring global variables and passing information between stuff much either.
Can someone point me in the right direction or tell me what I should use/look into? Is this even possible in VBA?

What you want is a global variable. Make a module and put in a global variable like such:
Global GblPreviousSheetName As String
Then, in ALL of your sheets, put the following code:
Private Sub Worksheet_Deactivate()
GblPreviousSheetName = Me.Name
End Sub
This will capture whenever a user or code changes sheets and set the Global variable to that sheet name.
Then, in your procedure, do this:
Public Sub Test()
If GblPreviousSheetName = "" Then
GblPreviousSheetName = "Sheet1" 'Put default sheet here (for first time workbook opens)
End If
'Run whatever code you want.
ActiveWorkbook.Sheets(GblPreviousSheetName).Activate
End Sub
Note that if the user changes sheets before pressing your button, it will log this too. If you only wish to log the changes that are made by your code, then instead of putting in the "Worksheet_Deactivate" code, then just set the global variable in your code.

Related

Screen Object not found

I have a Project in Excel. I have a module with sub Load to populate the ActiveForm with data in an Excel table that is tagged to go into that respective form. The idea is that whichever Form is active, I can call Load and get the data from the Excel table.
I am trying to use this simple code to get the name of the active form, like I have seen in so many examples
Debug.Print Screen.activeform.Name
However, the Screen object cannot be found. I get "Variable Not Defined" error.
Is this something that can be added via references? I have searched high and low. Or, can I pass a reference to the "Me" to the module?
Here is the code I have in the module to populate whichever form the user opens:
Public Sub Load()
Dim rw As Long
Set wb = ThisWorkbook
Set wsInputs = wb.Worksheets("Inputs")
Set loInputs = wsInputs.ListObjects("tInputs")
With loInputs
For rw = 1 To .DataBodyRange.Rows.Count
If .ListColumns("Form").DataBodyRange.Rows(rw) = screen.activeform Then
screen.activeform.Controls(.ListColumns("Control Name").DataBodyRange.Rows(rw).Value) _
= .ListColumns("Value").DataBodyRange.Rows(rw).Value
End If
Next rw
End With
End Sub
The different forms are just different categories of data for input into text and combo boxes that read back and forth from the form to Excel, of if there is data in Excel and the user opens that form, it is pre-populated.
I can include a screenshot but its just a bunch of labels and input boxes.
Thanks.
I was able to get this to work by having the function accept the form as a parameter:
Public Sub LoadData(frmLoad As Object)
And simply pass Me to the function:
LoadData Me
Perhaps the is poor design but it works. And therefor I don't need to include the LoadData function in each form.
Matt

Global worksheet variable for userform in excel

I am building a userform that adds data to a worksheet. I have a bunch of sub-routines for my userform, but I'm having issues accessing the variable I set to my worksheet. It's currently a local variable (in a sub) and have tried placing it in a module as discussed here: Can a worksheet object be declared globally in Excel VBA. I've done some further searching but didn't quite get the results I wanted.
I'm quite new to VBA and new to programming in general. I've used Excel quite a bit and want to do more by creating macros and such using VBA. Here's the code I'm currently using:
sub savebutton_click()
Dim trees As Worksheet
Set trees = ThisWorkbook.Sheets("Sheet1")
trees.Cells(1, 1) = Me.TextTreeName
trees.Cells(1, 2) = Me.TextTreeType
End sub
Obviously I cannot access local variables from another subroutine, so I have to make 'trees' global. I created a module and replaced Dim with Public, placed the second line of code in Workbook_Open(), and then tried accessing the 'trees' variable. I get an "Invalid outside procedure" and highlights the code in Workbook_Open() when I hit 'Debug'.
Essentially I just want to be able to access, say, trees.Cells(5,6) from any sub and I'm not sure what else to do with it. Any ideas? Thank you!
It must be a matter of placement ... if you open the VBA IDE and select the ThisWorkbook item in your VBAProject. Double click that item to open it, Select Workbook in the top left dropdown, Select Open in the top right dropdown. This will create your Workbook_Open Sub in the ThisWorkbook object:
Private Sub Workbook_Open()
Set trees = ThisWorkbook.Sheets("Sheet1")
End Sub
Right click your VBAProject and Add Module. In that module you put the global variable:
Public trees As Worksheet
Next you create your form, put the button on that and double click the button. This will generate the button event:
In my case:
Private Sub CommandButton1_Click()
trees.Cells(1, 1) = Me.TextTreeName
trees.Cells(1, 2) = Me.TextTreeType
End Sub
Now if you close the Excel Workbook (save the code and the workbook first) and reopen the Workbook the Workbook_Open() will kick in and set the Worksheet. Now call your Form, and click the button. This will fill the two cells on the given sheet....

Excel VBA, Code name appearing with sheet name

Why is that when I have the following VBA code:
public sub Run
End Sub
Sometimes it appears as Run in the macro list on the view tab but sometimes it appears as sheet1!Run?
You've put the macro into one of the worksheet code sheets. This probably occurred by opening the VBE with a right-click to the worksheet name tab and choosing View Code.
The macro can reside there but it will remain Private to that worksheet unless specifically declared otherwise. Generally, a module sheet is the preferred location.
It's also a bad idea to name your macros with reserved words. Run is a function as in Application.Run and your macro can only cause confusion if it carries the same name.

Shapes not tied to worksheets?

ok so,
I was hoping to have some stuff in my excel app persist, as in hang around, and I want something a little more reliable than global variables as these are reset when code is edited or if say the app is halted. (which does often happen)
So I've been using shapes, and they work good, but they rely on at least one worksheet always being constant right? as shapes are tied to sheets, if the sheet with the shapes gets deleted the shapes go away. And the users often delete / add new sheets, theres no one sheet that is always a constant, and they wouldnt let me force that on them either.
so is there a way to make shapes tied to workbooks instead of sheets? so then if a sheet is deleted with shapes on it, the shapes wont disapear.
any help or other suggestions appeciated
Edit
Thanks again to: #David Zemens for the answer that got me through, just in case anyone ever looks at this down the road, the code to add a named range is: workbook.Names.Add Name:="Name", RefersTo:="value" - you NEED to add refersto or it will error. you can put in a temp value like "temp" and set the value later, but you have to have refers to when you add
You can use Named Ranges to save string data between sessions. They can be children of the Workbook or of specific Worksheets. You will want the former. From the Formula Ribbon, Names Manager, Define Name like so:
Then, in your VBA, you can retrieve and set this range's value like:
Public Const CSVFileName as String = "sFileName"
Sub YourSubroutine()
Dim nm As Name
Set nm = ActiveWorkbook.Names(CSVFileName)
'Get the value:
MsgBox Replace(Replace(nm.Value, "=", vbNullString), """", vbNullString)
'Set the value:
nm.Value = "C:\documents\filename.CSV"
End Sub
The value associated with the Named Range persists beyond runtime, it is basically a property of the workbook.
I will post this now for you to review. I will try to work up an example of the XML Customer Data, and will revise my answer with that, later.

Easy way to find cell reference in excel vba

I am working on a spreadsheet with lots of VBA code in it. Most cell references use numbers, e.g.
Worksheets("Sheet1").Cells(someRow, someColumn)
I am wondering if there is any easy way to find out exactly which cell is being referenced - is it possible to put a breakpoint on this line of code, and then see which cell it will refer to (using the traditional "BA10" style) or will I have to calculate it each and every time using divs and mods?
Not all the references are hard coded, and I would really like to be able to work out where data is being pulled from, as the cell is accessed (not necessarily changed).
(edit) Is it possible to do this without changing the original source line, e.g. in an event module or something?
Debug.Print Worksheets(1).Cells(10, 53).Address(False, False)
returns BA10
There is another option. If you are making changes to a sheet, you can catch the Change event on the Worksheet, and pump out the changed range like so:
Private Sub Worksheet_Change(ByVal Target As Range)
Debug.Print "CHANGED -> " & Target.Address(False, False)
End Sub
Each change to the sheet will be output to your Immediate window like thus:
CHANGED -> G10
CHANGED -> G11:G28
There is also the SelectionChange event as well, but that's unlikely to be too useful. There is no event for just "reading" cells.
You can use Address.
Debug.print Worksheets("Sheet1").Cells(10, 53).Address
Will print the ranges address for you in the Immediate Window.
Is that what you are looking for?
You can also change your reference style to R1C1 in:
tools\options\general\R1C1 reference style
this way you will be able to know what the code is refereeing to.
Another way to go would be to add a watch in the VBE (Visual Basic Editor). You can do this by going to View>Watch Window to make sure the watch window is visible. Then from Debug menu click Add Watch. If you do this in break mode the context will already be set for you so all you have to do is paste in the expression you want watched and it will be visible. This of course works best on range objects (ex: rngFoo.Address as the expression) but you can paste in things like Worksheets(1).Cells(10, 53).Address.
Use the following to know which cell is calling the function:
Application.Caller.Address
Example:
Function Addition(va As Double, vb As Double) As Double
Addition = va + vb
MsgBox "Cell calling function Addition is " & Application.Caller.Address
End Function
Whenever this function is calculated a message box indicates the cell address calling it.
Be aware that calling this function from another VBA function will send an error. Check http://www.cpearson.com/Excel/WritingFunctionsInVBA.aspx