I don't know if this is the right place for my question, but: how do I use the object and the browser? I feel so inept when it comes to helping myself. I know I can google stuff (and I do, a lot), but I want to be able to use all resources at hand.
Let's take the border of a chart. Google helped me out once again and told me I can change it like this:
Sheets("Sheet1").ChartObjects(1).Chart.ChartArea.Border.LineStyle = xlContinuous
But how do I figure this out with the object browser? Let's say I type in "chart". I get a long list and after going through this, it's probably not how I figure it out because I'd have to know that I'm looking for ChartArea. Still, one question:
I found ChartArea for an entry where the Library is Excel, Class is Chart and Member is empty - does member being empty tell me something, is this something I should look for?
Anyway, moving on, I type in "border". I would've expected to find something in "class" that has something to do with chart. But I don't. So how am I supposed to know how to find what I'm looking for?
And while I'm at it, let me ask about the Microsoft help. I googled my way to the Border.LineStyle property. Obviously there's the code example that tells me about using it with Charts().ChartArea, but again, can I do this more methodically? On the left hand side, you can see LineStyle is a property of Border. From there, how do I move up one level? How do I see that Border is/can be a property of ChartArea?
TL;DR:
The ChartArea.Border property is hidden, you need to toggle "show hidden members" on in the Object Browser to see it.
Below is essentially everything there is to know about the Object Browser.
Library Filter & Search Box
The top part looks like this:
That dropdown contains all referenced type libraries, identified by their programmatic name:
Excel: the Excel type library, defines things like Worksheet, Range, etc.
Office: a dependency of the Excel type library; defines things like CommandBars.
stdole: another dependency; defines lower-level things like StdFont and StdPicture.
VBA: the VBA standard library, defines things like MsgBox, Collection, etc.
VBAProject: the type library of your compiled VBA project.
You'll want to use that dropdown to limit what you're looking at to the specific type library you're exploring - for example, Excel. Under the dropdown, there's a search box you can use to search for strings that appear in part of an identifier and populate the "search results" view - but you know that already.
Show Hidden Members
Right-click an empty area in the toolbar; select "Show hidden members" - now the object browser and InteliSense will be listing members that are otherwise hidden, and you'll quickly discover that the Excel type library is much larger than it seems.
Edit Module/Member Descriptions
Navigate to your VBAProject library, and find one of your modules in the left pane; the right pane will be listing the members of that module. Right-click either the module or one of its members, and select "Properties" - the "Member Options" dialog pops up and lets you enter a description:
Module and member descriptions show up in the bottom pane when they exist:
If you exported that module, you would see that it now has a hidden VB_Description attribute with a string value that matches what you entered for a description.
If you're using Rubberduck, you can use special comments ("annotations") to control these hidden attributes, too:
'#ModuleDescription("This module contains some boring recorded macros.")
Option Explicit
'#Description("Does something...")
Public Sub Macro1()
'...
End Sub
Rubberduck annotations can also control/synchronize other hidden attributes that the Object Browser isn't exposing, but I digress.
The left pane ("classes") displays all the types in the selected library; the right pane lists the members of the selected type, grouped by kind (properties, methods, events, etc.); what you must keep in mind, is that no matter how many members are named the same as types/classes/interfaces, a member is a member, not a type.
Taking this expression:
Sheets("Sheet1").ChartObjects(1).Chart.ChartArea.Border.LineStyle = xlContinuous
We can start with finding what object type the Sheets member call belongs to. If we filter for the Excel library and search for Sheets, we find 2 interesting results where a member is named Sheets:
Application.Sheets
Workbook.Sheets
This means unless that line of code is in the code-behind of ThisWorkbook, what we're calling can't be Workbook.Sheets - but we're not qualifying it with Application either! If we reveal hidden members, we discover a hidden Global class and a _Global interface that both expose a Sheets member! From there we can infer that the Excel object model is "redirecting" our unqualified Sheets call to the Application object, which looks like it's giving us the Sheets member of whatever the ActiveWorkbook is. In any case, the relationship between _Global and Global is confusing: we select _Global.Sheets and the bottom panel tells us we're looking at a member of Excel.Global:
Notice the property doesn't have any parameters: it simply yields a reference to a Sheets object. So we look at the returned Sheets type - either by clicking the hyperlink in the bottom panel, or by browsing the left panel to find the Sheets collection type (which conveniently happens to have the same name as the Sheets property of the Global, Application, and Workbook classes).
Note that the Workbook.Worksheets property also yields a Sheets collection object.
Like all other collection classes, the Sheets class has a default member, and this one is hidden, it's named _Default, and it returns an Object. We can guess that the property is forwarding the call to the Item indexer, because collection classes normally expose a way to access their items by index or by name/key (by convention it's named Item but sometimes it's something else, like Recordset.Fields)... but now that property also returns an Object.
Default Members
Classes in VBA can have a member (only one!) that can be implicitly invoked when the object is coerced into a value. This member has a hidden VB_UserMemId attribute with a value of 0, and the object browser identifies it with a blue/cyan dot on the member's icon. That's how Application.Name gets output when you write Debug.Print Application; that's also how you get Range.Value when you Let-coerce a Range object into a Variant or any other non-object type without using the Set keyword... and it's why the Set keyword is required when assigning object references: without it the compiler wouldn't have a way to tell whether you mean to assign the object itself or its default member value... which can very well be another object reference.
In general, it's best to avoid implicit default member calls and be explicit, so that the code says what it does, and does what it says.
At this point we're stumped, just like the compiler is: every further member call on that line of code is only resolvable at run-time - it's all late-bound, and when you type it you get no IntelliSense, no autocompletion, no compile-time validation: even Option Explicit can't save you from a typo, and if you make one you'll know because VBA will throw error 438 "I can't find that member" at you.
Sheets._Default returns an Object: not all sheets are Worksheet objects - a Chart could be a sheet as well! That's why we usually prefer to use the Workbook.Worksheets property instead, so that we're certain to get a Worksheet object. Right? "Sheet1" is a Worksheet, we know as much!
We could restore early binding by declaring a Worksheet variable:
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Worksheets("Sheet1")
sheet.ChartObjects(1).Chart.ChartArea.Border.LineStyle = xlContinuous
So we browse to the Worksheet type in the left pane, find its ChartObjects method (it's a Function), which also returns an Object. Looks like naming properties after their type is a common convention in the Excel type library - there's a ChartObjects object collection in the left pane, and we can probably assume its items are ChartObject objects; so we find the ChartObject class again in the left pane, and see that it has a Chart property that returns a Chart object:
At this point we can restore early binding further down the chain of member calls, by extracting another variable:
Dim targetChartObj As ChartObject
Set targetChartObj = sheet.ChartObjects(1)
targetChartObj.Chart.ChartArea.Border.LineStyle = xlContinuous
The ChartArea property yields a ChartArea object, so we find the ChartArea class in the left panel, ...and see that it has a hidden Border property!
The ChartArea.Border property returns a Border object, which again we find in the left panel to see that it has a LineStyle property... of type Variant. How are we supposed to know xlContinuous is even a thing then? Is there no hope?
At this point we could google up Border.LineStyle and see if the docs give us a clue about the legal values, ...or we could try to search for LineStyle in the search box...
...and see that there's an XlLineStyle enum with a member named xlContinuous, alongside all other constants defined under that enum. A quick online search brings up the official docs and confirms that Border.LineStyle wants an XlLineStyle enum value!
Now, this was moving left-to-right. Going right-to-left, you can work your way up by leveraging the search box; searching for "Border" with hidden members visible, lists the ChartArea.Border member in the search results.
When member is empty then the object is a Class
Many objects can have a border. I don't see a border property on either Chart or ChartArea. This makes it hard to tell what objects have a border. If you can configure a border in the GUI that's a good indicator that you can do it in code.
This is the top of the documentation: https://learn.microsoft.com/en-us/office/vba/api/overview/excel/object-model
I use the link I gave in A3. I never use the object viewer inside excel. The microsoft documentation doesn't always have everything you need. You will find obscure webpages that have undocumented features. How do people learn this arcane art? Either trial and error, or it's passed down from one wizard to the next.
Related
I have a form with multiple Combo boxes. I was doing some appearance tweaking of the form and one of the boxes is not showing anywhere. If I try to add a new combobox with the same name it says it is not unique.
I tried Opening the form with a message in the box "Here I am" but it did not show. I don't get any compile errors as there are multiple references to the field in my code. Is there anyway to find it (Me.cmb_Photographer)?
It could be a bunch of different things. Perhaps the visible property is set to No or the control is behind another control. You might also have mislabeled something so Name property is different from the Control Source property.
In any case you should be able to go into design mode, open the property sheet and use the dropdown to find the control you're looking for. It should highlight the control on the form.
Was working on a new project today when I noticed this "Unknown" control type in the toolbox - I haven't seen this before. Does anyone know what this is?
This is the "RefEdit" control.
When it's active, and using the mouse, it allows the user to select a cell, range of cells (by holding mouse or with Shift), or Multiple Ranges of Cells (with Ctrl). (arrow keys do not work). The selection can be on a different sheet to the one the control is on.
It returns a string that represents the range selected, I.e.
Sheet1!$A$1,
Sheet1!$A$2:$B$2 or
Sheet1!$A$1,Sheet1!$A$2:$B$2,Sheet1!$A$3:$C$3
etc, respectively.
bettersolutions.com has probably the most info I can find on this.
As the user can type into this control, it Does Not necessarily return a Valid range!
Interestingly, the "Unknown" control type tooltip is probably because of https://peltiertech.com/unspecified-painfully-frustrating-error/ due to apparent general RefEdit flakiness: https://peltiertech.com/refedit-control-alternative/
Similarly to how objects on a slide can be named, and called upon & selected by that name, I would like to shift between, move to & select slides using a designated name.
So where I would currently employ, for instance:
PPPres.Slides(1).Select
I need to do something along the lines of:
PPPres.Slides("Slide Name").Select
mainly because the slides are potentially dynamic, and I'm not keen on changing references for every slide within each block of code every time the slide changes.
Honestly can't find any features for actually naming a slide within Powerpoint. I have read features about doing this by naming the Title Object, but this doesn't seem to make sense to me, nor does it actually work for me.
Hope you can help!
PowerPoint names its slides in order, so the first slide is named "Slide1", the second "Slide2", etc...
You can use the default name or you can manually change it, like in this example:
ActivePresentation.Slides("Slide2").Name = "Hello" 'Changing the default name to "Hello"
ActivePresentation.Slides("Hello").Select 'Using the new Name to access the Slide
Hope this helps.
I have emulated a hamburger menu (implemented as a textbox) that triggers a dropdown with various options that I want to display various tabs of an Excel workbook (though the specific purpose of the textbox is not relevant to my question). Is it possible to show the same textbox object (or any other object) with the same name and calling the same macros/vba code? I would like to avoid having to write a separate [tbName]_click, etc. event handlers for the each tab where I want it to appear (and will eventually want to have the hamburger menu displayed on various pages dynamically -- but that's a subject for another day).
Thx...
D.
The code for the hamburger menu (for which I already have working code) is implemented as a textbox ,but could be ANY object that triggers a macro when clicked. I don't think posting that code would be helpful. I have not yet begun witing code to place the copies of the object on different tabs. Before I begin writing that code, I was simply hoping for guidance on an APPROACH.-- not so much the code to do so as much as either a verbal description or even simple pseudocode showing how to copy the object from a source tab to a new or different target tab. That, and whether the object, after being copied to the target tab, can have the same name and trigger the same macro. There are other behaviors I want the object to display, but I can figure those out myself, and there's no need to bring them up here.
I have quite a simple question but cannot find a simple answer.
I have created a combobox and would like to place it in the header/footer of my document so it does not cover up data fields. See below:
Does anyone happen to know how to move it up there? I assume it will require VBA.
Here is a capture that demonstrates how far I can drag the box:
Thanks,
Dan
Consider the Worksheet interface.
It exposes a Shapes collection, which is [ab]used to hold the ActiveX controls you put on it. As you probably already know, an ActiveX control's Top property can't be negative; if you programmatically make it negative, it's only going to be set to 0. The ActiveX controls' setter for the Top property might look something like this:
Public Property Let Top(ByVal value As Long)
If value < 0 Then value = 0
mTop = value
End Property
Then there's a PageSetup property getter, that returns a PageSetup object - that's where you can configure, well, the page setup, including margins and custom headers. Notice the PageSetup interface doesn't expose anything like a Shapes collection: there's simply no support for ActiveX controls in the PageSetup object.
As a comment correctly pointed out, you can instead configure your PageSetup to have minimal margins and no content, and then do whatever you intended to put in the page header on the worksheet's client area instead - with the PrintTitleRows property you can have that "heading" appear at the top of every page, simulating a "page header" inside the client area where ActiveX controls are allowed to exist.