Though I know how to enumerate (in VBA code) the WorkbookQuery objects in a whole Workbook, I need to know how to do so for just one sheet. Here is the code that works for the whole Workbook...
Option Explicit
Public Sub EnumerateWorkbookQueries()
Dim q As WorkbookQuery
For Each q In ThisWorkbook.Queries
Debug.Print q.Name
Next q
End Sub
I understand that WorkbookQuery objects are (as the name implies) collected in the workbook, but the data they return goes into tables that are on specific worksheets. When you click onto one of those tables, Excel knows to highlight its associated WorkbookQuery object in the Queries list (assuming the user has that open).
For each Query displayed on a sheet, there is an automatically created Workbook scoped Name that referes to a ListObject, that displays the Query result (View them in the Name Manager). Those ListObject's have a WorkbookConnection property, whose name is related to the Query name.
If you have a Query named say MyQuery (displayed on a sheet) there will be a ListObject whose WorkbookConnection is named Query - MyQuery.
If you look at the "Existing Connections" dialog in Excel, the connections are listed with the "Query - " prefix, but if you edit a connection, the name property is editable without that prefix. On commiting a name change the prefix is re-added automatically. Editing the name of a Query updates the WorkbookConnection name, and visa versa.
You can gear off this to check for Queries on any given sheet
Public Sub EnumerateWorksheetQueries(ws As Worksheet)
Dim lo As ListObject
Dim qt As QueryTable
If ws.ListObjects.Count > 0 Then
For Each lo In ws.ListObjects
Set qt = Nothing
On Error Resume Next
Set qt = lo.QueryTable
On Error GoTo 0
If Not qt Is Nothing Then
Debug.Print ws.Parent.Queries(Mid$(lo.QueryTable.WorkbookConnection.Name, 9)).Name
End If
Next
End If
End Sub
Call it somthing like this
Sub Demo1
EnumerateWorksheetQueries ActiveSheet
End Sub
Or
Sub Demo2()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Debug.Print "Queries on " & ws.Name
EnumerateWorksheetQueries ws
Next
End Sub
Note: One gotcha, the default Name of the ListObject is also related to the Query, but can be changed by the user. When a ListObject name is changed, the names of the Query and WorkbookConnection do NOT update.
Related
Sub searchBoys()
'profile is the name being searched
Dim profile As String
Dim ws As Worksheet
profile = LCase(Sheet8.Range("searchName").Value)
For Each ws In ActiveWorkbook.Worksheets
If profile = Trim(LCase(ws.name)) Then
ws.Select
Exit Sub
End If
Next ws
End Sub
Trying to do a small little project where I create an excel page containing fun facts about each of my friends. From the main page, the user would search their name, (referenced as profile) and the active worksheet would switch to the one pertaining to them.
Select Matching Worksheet
ThisWorkbook means the workbook containing this code.
If a worksheet named after the Profile variable exists (case is irrelevant), it will be selected. Otherwise, nothing will happen.
Option Explicit
Sub SearchBoys()
Dim Profile As String: Profile = CStr(Sheet8.Range("SearchName").Value)
On Error Resume Next
ThisWorkbook.Worksheets(Profile).Select
On Error GoTo 0
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 have to create an Excel sheet automatically with vba.
Some cells need an Onchange Event Listener and I wanted to know if there is a way to create this Event Listener automatically by calling a macro instead of writing it down everytime in every sheet code ?
Thank you
I'm going to answer this question because I think it might have some relevance to quite a few other people too, so the code below should get you started in the right direction.
However, there is an expectation on this site that you try to help yourself at least to the same extent as we try to help you. The commenters have mentioned the VBA Object Model, Application Events and AddIns. It shouldn't be beyond the wit of most people to then research these key words (say with a google search). It's not really acceptable simply to say you "dunno where to put the code or what to do", and, in all honesty, doesn't particularly motivate people to help you - put another way, you're pretty lucky to get an answer with that post and comment.
I don't want to get into a huge comment exchange on exactly how to code your specific case. The code here is an example and I would expect you then to research it further. So here goes ...
Insert a class module (research that if you don't know how) and name it - I've called mine cApp. This will enable you to access the Application object and capture its events, like so:
Option Explicit
Private WithEvents mApp As Application
Private mSheetList As Collection
Private Sub Class_Initialize()
Dim ws As Worksheet
'Create instance of the sheet collection
Set mSheetList = New Collection
'If you wanted to add any existing sheets to be checked for changes,
'then you'd do it here.
'Just for an example, I'm using any existing sheets whose name contains "LoP".
For Each ws In ThisWorkbook.Worksheets
If InStr(ws.Name, "LoP") > 0 Then
mSheetList.Add ws
End If
Next
'Create instance of Application
Set mApp = Application
End Sub
Private Sub mApp_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim ws As Worksheet
'Test if the changed sheet is in our list.
'Check if the Sh object is a worksheet.
If TypeOf Sh Is Worksheet Then
'Loop through out list of sheets and see if the Sh object is in the list.
For Each ws In mSheetList
If Sh Is ws Then
'Check if the changed range is in the desired range of your sheet.
'In this example, we'll say it has to been in the range "A1:B2".
If Not Intersect(Target, ws.Range("A1:B2")) Is Nothing Then
MsgBox ws.Name & "!" & Target.Address(False, False) & " has changed."
End If
Exit For
End If
Next
End If
End Sub
Private Sub mApp_WorkbookNewSheet(ByVal Wb As Workbook, ByVal Sh As Object)
'A new sheet has been created so add it to our sheet list.
If Wb Is ThisWorkbook Then
If TypeOf Sh Is Worksheet Then
mSheetList.Add Sh
End If
End If
End Sub
You then want to create an instance of this class. I've done it in a standard Module:
Option Explicit
Private oApp As cApp
Public Sub RunMe()
'Create instance of your app class
Set oApp = New cApp
End Sub
You'd then call the RunMe routine somewhere within your code. You might choose to do this in your Workbook_Open() event, but it could be anywhere of your choosing.
I've commented the code pretty heavily so you can see what it's doing and you can always research each of the keywords if you're not sure what they're doing.
I am trying to find the sheet name that has a specific table name on it. For example:
Set sheetNM = ActiveWorkbook.Names("ratetable").RefersToRange.Parent.Name
Something like that, but would pull the name of the sheet, so I can activate that sheet in order to pull information from it.
This is not something I recommend but as you are referencing the ActiveWorkbook, you can drop the ActiveWorkbook and retrieve it simply as,
dim pws as worksheet, sws as string
sws = range("ratetable").parent.name
set pws = range("ratetable").parent
debug.print sws & " - " & pws.name
While a structured table (aka ListObject object) is listed in the Formulas ► Name Manager, it does not have all of the properties of a defined name. Unfortunately, everything you can do with a name you cannot always do with a ListObject as a ListObject's parent is the Worksheet object, not the workbook.
You can use error trapping to find the sheet containing a table with a given name:
Function FindTableSheet(TableName As String) As String
Dim ws As Worksheet
Dim LO As ListObject
Dim shName As String
For Each ws In Sheets
On Error Resume Next
Set LO = ws.ListObjects(TableName)
If Err.Number = 0 Then
FindTableSheet = ws.Name
Exit Function
Else
Err.Clear
End If
Next ws
FindTableSheet = "Not Found"
End Function
To test it, I named one of my sheets "Data" and added a table called "ratetable" to that sheet. I didn't, however, create any table called "table tennis". I then ran:
Sub test()
Debug.Print FindTableSheet("ratetable")
Debug.Print FindTableSheet("table tennis")
End Sub
With the output:
Data
Not Found
I know this post is old, but for what it's worth, I think the OP was on the right track (looking for the parent name) with the initial code that you originally posted. Calling the table's parent works for me:
ActiveSheet.ListObjects("TableName").Parent.Name
I have a piece of script that’s in module1 that checks if an option button is clicked.
The option button is placed in Sheet1, name “Info”, so I thought the script below would work
Sub checkClicked()
dim Page as worksheet
set Page as worksheets(“Info”)
Debug.print Page.optClicked
End sub
But when I did it like this it says method or data member not found. It would only work if I replace it with
…
Debug.print Sheet1.optClicked
…
Can anyone give me an insight why this happens?
Think of Sheet1 as a "subclass" of "worksheet" - when you add controls to the sheet you're adding new members. A generic worksheet object doesn't have a member which represents your option button, whereas Sheet1 does.
Sub Test()
Dim sht As Worksheet
Dim sht1 As Sheet1
Set sht = ThisWorkbook.Sheets("Sheet1")
Set sht1 = Sheet1
Debug.Print sht.optClicked 'error
Debug.Print sht1.optClicked 'OK
End Sub
Set Page = ActiveWorkbook.Worksheets("Info") should work. I think worksheets is no real property in VBA...
Also, your debug print code looks weird, use debug.print("bla")..
Do you have Option explicit activated?
Try Set Page = Worksheets("Info") and do NOT use these curly “” quotes - just in case (for Excel formulas this DOES matter).
The argument within Worksheets is the name of the worksheet you are interested in, i.e. "Sheet1".
Other approach: the ActiveX controls on sheet are accessible from two collections: Shapes and OLEObjects. You could use the OLEObjects collection to get access to your checkbox.
Sub checkClicked()
Dim Page As Worksheet
Set Page = Worksheets("Info")
' 1/ ActiveX check box in Shapes collection
Dim myShape As Shape
Set myShape = Page.Shapes("optClicked")
' --------------------------------------
' 2/ ActiveX check box in OLEObjects collection
Dim myOLEObject As OLEObject
Set myOLEObject = Page.OLEObjects("optClicked")
' Use Object property to get access to your check box
Dim myCheckBox As Variant
Set myCheckBox = myOLEObject.Object
If (TypeOf myCheckBox Is MSForms.CheckBox) Then
Debug.Print myCheckBox.value
End If
End Sub