I've looked all over for this and think I'm just hitting a mental brick wall for something simple. But still. I'm writing a quick program to help me with some mileage spreadsheets for different vehicle. Each vehicle has its on worksheet within the spreadsheet, I'm using GemBox in VB.net.
Basically, dending on which button you press it chooses the correct sheet for the corresponding vehicle. I cannot find anything, anywhere that tells me how to choose a different existing sheet as the active worksheet.
This is my test code atm.
Public Sub SetMiles(vehicle As String)
Dim wb = ExcelFile.Load(file)
Dim ws = wb.Worksheets.ActiveWorksheet(vehicle)
loc = "F12"
ws.Cells(loc).Value = "800"
End Sub
In GemBox.Spreadsheet you don't need to set the sheet as active in order to use it.
In other words, let's say you have an Excel file which has "Sheet1" and "Sheet2". To write into those sheets you can use the following:
Dim wb = ExcelFile.Load(File)
Dim ws = wb.Worksheets("Sheet1")
ws.Cells("A1").Value = "Foo"
ws = wb.Worksheets("Sheet2")
ws.Cells("A1").Value = "Bar"
You can also use the following:
Dim wb = ExcelFile.Load(File)
Dim ws = wb.Worksheets(0)
ws.Cells("A1").Value = "Foo"
ws = wb.Worksheets(1)
ws.Cells("A1").Value = "Bar"
So, I believe that what you need is the following:
Public Sub SetMiles(vehicle As String)
Dim wb = ExcelFile.Load(File)
Dim ws = wb.Worksheets(vehicle)
Loc = "F12"
ws.Cells(Loc).Value = "800"
End Sub
Last, in case you do need to set some sheet as active, then you can do that with GemBox.Spreadsheet as following:
wb.Worksheets.ActiveWorksheet = wb.Worksheets(vehicle)
However, again GemBox.Spreadsheet doesn't care if the sheet is active or not, you can access and modified it regardless of that. By setting the sheet as active, that sheet will be the first visible one that you see when you open that file in an Excel application.
wb.Sheets(vehicle).Activate is the simplest way.
Although I recommend that you also validate the vehicle string to ensure that Sheet actually exists. You can then either ignore, display a message or create a new sheet.
I was assuming that you wanted to activate the sheet so that the user can do manual input. If you are doing automated input (no user interaction), then you are better off not activating the sheet. Something along the lines of:
Public Sub SetMiles(vehicle As String, wb as Workbook, loc as string, Mileage as string)
' passing the values is better encapsulation for OOP purposes
' in your example above, loc="F12", Mileage = "800"
' You have passed the Mileage as a string - but you could also use a numeric value.
' Validate sheet name here if important.
' Validate range name here if important.
wb.Sheets(vehicle).Range(loc).Value = Mileage
End Sub
Edit: Appears GemBox uses Worksheets instead of Sheets.
Related
I am trying to copy data from one worksheet to another. I have a workbook that has about 62 worksheet tabs.
The part that is especially tricky for me is that the worksheet the data needs to be copied to will not always be the same.
I have a dropdown menu that lists 62 different pieces of equipment. This is shown in G1 in the worksheet named "HOME". I want the text to copy over to the correct tab based on the selection.
I figured out how to copy over specific text, when I do this I see the word "TEXT" show up on the specified worksheet.
Sheets(Range("g1").Value).Activate
Range("a1").Value = "TEXT"
I cannot figure out how to copy over G4:G24 from my "HOME" worksheet to another worksheet based on the same drop-down menu.
This is what I tried.
Private Sub CommandButton1_Click()
Worksheets("HOME").Range("g4:g24").Copy
Sheets(Range("g1").Value).Activate
Range("a1").Value = "TEXT"
Sheets(Range("g1").Value).Activate
Range("f4").PasteSpecial
End Sub
Be explicit about workbook and worksheets - never use Range/Cells without qualifying a worksheet (though you can get away with it in a worksheet code module if you're referring to the associated worksheet).
Private Sub CommandButton1_Click()
Dim wb As Workbook, ws As Worksheet
Set wb = ThisWorkbook 'or ActiveWorkbook?
With wb.Worksheets("HOME")
Set ws = wb.Worksheets(.Range("G1").Value) 'create a worksheet reference
ws.Range("A1").Value = "TEXT" '...and use it
.Range("g4:g24").Copy ws.Range("f4")
End With
End Sub
See for example: What is the default scope of worksheets and cells and range?
Generally speaking you have a good start there, but it can be accomplished in much fewer lines with much more speed like this:
Sub ExampleSub()
Dim SheetName As String
SheetName = Worksheets("HOME").Range("A1").Value
Worksheets("HOME").Range("G4:G24").Value = Worksheets(SheetName).Range("G4:G24").Value
End Sub
It's not even necessary to use the variable SheetName, but it can help keep things simple, it can also now be reused later in the subroutine.
An alternative to reference sheets is to make the variable a worksheet:
Sub ExampleSub()
Dim SheetName As Worksheet
Dim HomeSheet As Worksheet
Set HomeSheet = Worksheets("HOME")
Set SheetName = Worksheets(HomeSheet.Range("A1").Value)
HomeSheet.Range("G4:G24").Value = SheetName.Range("G4:G24").Value
End Sub
So I am trying to write a Macro for Excel, that adds 2 worksheets from an excel file to a new one.
Therefore, I try this:
Sub addfile()
Dim sheet1 As Worksheet
Dim sheet2 As Worksheet
Set sheet1 = Sheets.Add(Type:="C:\Users\Helge\AppData\Roaming\Microsoft\Templates\page1.xltx")
Set sheet2 = Sheets.Add(Type:="C:\Users\Helge\AppData\Roaming\Microsoft\Templates\page2.xltx")
End Sub
When I test it, it imports the first page, but the 2nd page gives me a Runtime error 1004.
Why does this happen?
And is there another way to get 2 sheets from one excel file to another via vba?
Much to my surprise this version of your code actually worked for me.
Sub addfile()
Dim Sheet1 As Worksheet
Dim Sheet2 As Worksheet
Set Sheet1 = Sheets.Add(Type:=Environ("Userprofile") & "\OneDrive\Desktop\Template1.xltx")
Set Sheet2 = Sheets.Add(Type:=Environ("Userprofile") & "\OneDrive\Desktop\Book2.xlsx")
Debug.Print Sheet1.Name, Sheet2.Name
End Sub
The reason for my surprise is that Sheet1 and Sheet2 are the default CodeName for the first and second worksheets in any workbook. Therefore there is a conflict of naming between the Sheet1 in the workbook and the Sheet1 you declare which should come to the surface not later than Debug.Print Sheet1.Name. In fact, it may have. I didn't check which name was printed. But the code didn't crash. Since it crashes on your computer, perhaps you have an older version of Excel. Try to stay clear of variable names that Excel also uses. Or there is something wrong with the path & file name, which is hard to tell in that syntax and therefore kept me fooled for quite some time too.
In fact, I discovered the above only after finding out that my Desktop was on OneDrive and not before I had written the function below which is designed to avoid the use of Sheets.Add. It also has some extras such as being able to specify the sheet to take from the template (you could have one template with 2 or more sheets). You can specify an index number or a sheet name. And the function will give a name to the copy, too, if you specify one.
Private Function AddWorksheet(ByVal Template As String, _
TabId As Variant, _
Optional ByVal TabName As String) As Worksheet
Dim Wb As Workbook
Dim Path As String
Dim FileName As String
Set Wb = ThisWorkbook ' change to suit
' make sure the path ends on "\"
Path = "C:\Users\Helge\AppData\Roaming\Microsoft\Templates\"
With Workbooks.Open(Path & Template)
.Sheets(TabId).Copy After:=Wb.Sheets(Wb.Sheets.Count)
.Close
End With
Set AddWorksheet = ActiveSheet
If Len(TabName) Then ActiveSheet.Name = TabName
End Function
You can call the function from a sub routine like this:-
Sub AddWorksheets()
Dim Tab1 As Worksheet
Dim Tab2 As Worksheet
Application.ScreenUpdating = False
Set Tab1 = AddWorksheet("Page1.xltx", 1, "New Tab")
Set Tab2 = AddWorksheet("Page2.xltx", "Sheet1", "Another new Tab")
Application.ScreenUpdating = True
End Sub
Please observe the difference between the two function calls.
I am struggling with proper syntax for setting variables as ranges...
Specifically, I'm testing a function I want to use in an app that creates new profiles and store the data, I will store that data on a hidden sheet, so they can be recalled at run time.
I'm currently construction a userform in order to create a new profile, the profile data needs to be stored to the first free column on the hidden sheet.
(where I will have to create a dynamic namedRange, so that i can use that range to save the associated data, and update the listbox in the userform)
Right now, I'm stumped by this:
Sub TestFindLastFunctions()
Dim wb As Workbook
Set wb = ThisWorkbook
'wb.activate 'shouldn't be neccesary
Dim ws As Worksheet
Set ws = sh_02CRepStorage
'ws.activate 'shoudn't be neccesary
Dim trgtCol As Long
trgtCol = LastColInSheet(ws) + 2
Debug.Print trgtCol ' so far so good
'Cells(1, trgtCol).Select 'another debug check - only works if sheet activated
Dim trgtCell As Range
Set trgtCell = ws.Cells(1, trgtCol) '<------- problem line
Debug.Print trgtCell '<----- prints "" to the immediate window.
End Sub
The LastColInSheet function is copied form Ron de bruin's page: https://www.rondebruin.nl/win/s9/win005.htm it simply returns a column number, in this case: 4.(One problem with it is if the sheet is empty, it returns an error, wondering if this can be fixed with an if statement in the function.)
I've tried many iterations of the problem line, some work but only if the storage sheet is activated, and give an error if not activate or selected, as the sheet will be hidden, I need this to work without activating the sheet, (although I could switch off screen activation?).
But I understand that it is best practice to avoid extraneous selects and activates, how can I just point directly to what I want and save that range into a variable?
It just doesn't seem like it should be so difficult, I must be missing something obvious.
It also seems like it shouldn't need so many lines of code to do something so simple.
I tried some more iterations of the "problem line" after some more searching...
-The real problem was with the debug.print line
Sub TestFindLastFunctions()
Dim wb As Workbook
Set wb = ThisWorkbook
'wb.activate 'shouldn't be neccesary
Dim ws As Worksheet
Set ws = sh_02CRepStorage
'ws.activate 'shoudn't be neccesary
Dim trgtCol As Long
trgtCol = LastColInSheet(ws) + 2
Debug.Print trgtCol ' so far so good
'Cells(1, trgtCol).Select 'debug Only works if already on sheet
Dim trgtCell As Range
'Set trgtCell = ws.Range _
(ws.Cells(1, trgtCol), ws.Cells(1, trgtCol))
' unnecessarily complex, but correct if using .range?
'but works if insisting on range
Set trgtCell = ws.Cells(1, trgtCol) 'back to original
Debug.Print trgtCell.Address '<---problem was here?
End Sub
Can I set up a variable x = "Sheet1"
In order to do:
x.Range("A3")
instead of
Sheet1.Range("A3")?
What type of variable should it be? I tried string and it didn't work.
Thanks
Update:
I would like a method that won't be affected by changing the worksheet name. i.e.
Sheet1.Range("A3") will always refer to the same worksheet even if I change the worksheet name to "peanuts", at least that's what I thought.
You want to declare it a Worksheet Object:
Dim x as WorkSheet
Since it is an object we must Set the sheet:
Set x = WorkSheets("Sheet1")
or if you want to use the code name:
Set x = Sheet1
Then yes you can use it:
x.Range("A3")...
I think you're mixing two different declarations
Declaring a sheet (must set the sheet)
dim ws as worksheet
set ws = sheets("sheet1")
ws.cells(1,1).value = ""
Declaring a string as the name of a sheet (can utilize the NAME of the sheet as a string)
dim ws_name as string
ws_name = "sheet1"
sheets(ws_name).cells(1,1).value = ""
Additionally you could use the sheet index, which does not utilize the name of the sheet (if you change it later); this is a little different than the previous two, but this example (using a loop) helps more clearly explain how the index can be utilized
dim i as long
for i = 1 to sheets.count step 1
sheets(i).cells(1,1).value = ""
next i
and a simple use of a sheet index
sheets(1).cells(1,1).value = ""
It should be worksheet. The syntax would be:
Dim x as Worksheet
Set x = Sheet1
after that you can use x.range("A3") to refer to Cell A3 in sheet1
You want a Worksheet variable. The "name" you're referring to is the Name property, and that isn't in code; it's the "tab name" of the sheet, that the user can change on a whim and that, for that reason, you don't want to have to hard-code anywhere if you can avoid it.
But it looks like you're referring to a sheet that exists in ThisWorkbook at compile-time; each sheet has a (Name) property that you can edit in the Properties toolwindow (F4). By default that name is Sheet1, and VBA takes that name and makes it a project-scope identifier you can use anywhere you need to refer to that particular sheet.
So if you change a sheet's (Name) to PeanutsSheet, then you can use PeanutsSheet in your code:
PeanutsSheet.Range("A1").Value = 42 '<~ that's the "CodeName", and users can't easily break it
And that is preferable to referring to that same sheet by its "tab name":
ThisWorkbook.Worksheets("Peanuts").Range("A1").Value = 42 '<~ breaks if tab is ever renamed
Declaring a variable for a sheet that exists in ThisWorkbook at compile-time, is completely redundant:
Dim ws As Worksheet
Set ws = Sheet1 '<~ variable 'ws' is 100% redundant
Using such variables makes the code confusing and harder to follow than it needs to be, because now you have 2 (or more) identifiers referring to the same thing.
But this is worse:
Set ws = ThisWorkbook.Worksheets("Sheet1") '<~ now it's redundant *and* super frail
I am trying to simplify some code, and wondered whether I would be able to use an If statement to set a different open workbook variable, depending on a few conditions of a defined range.
basically something like
dim ws as worksheet: set ws = Thisworkbook.worksheet("worksheet name")
dim r as range: set range = ws.range("A cell which has an if statement in it to display a number based on another cells contents")
dim wb as workbook
this is where I want to vary the actual workbook set as wb
if r.value = 1 then
set wb = Open a workbook
elseif r.value = 2 then
set wb = Open another workbook
Ideally I would then do the same for ws2 which would be the specific worksheet variable for the specified workbook above
Not sure if this method will work and wondered if I was on the right track. I have code which opens a workbook, finds values in various rows, inserts rows, copies cell contents., between two ws variables, etc. And it works, but I need ot add more workbook options and Id rather not have multiple macros with the only difference being the variable for the second workbook to open and work with.
Its OK - tried the above and it seems to work fine - just lacked a bit of confidence I suppose.