Positioning an ActiveX Combobox in an Excel Document header - excel

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.

Related

Combo Box not showing on Excel VBA Form

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.

VBA: How to use the Object Browser?

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.

Missing Properties in VBA [duplicate]

I'd like to add a horizontal scrollbar to a VBA ListBox.
It appears that the built in ListBox does not add a horizontal scrollbar automatically. I have a number of fields whose contents exceed the width of the ListBox and are thus unreadable to the user.
I found this article, however the code fails, due to accessing hwnd of the ListBox (which is apparently not available in VBA). I'd rather not write a native DLL to accomplish this as I suspect there is a better way.
Any idea on how I can add a horizontal scrollbar to a VBA ListBox?
I'm open to the idea of using an alternate control rather than getting it to work with the ListBox specifically.
Did you try ColumnWidths property?
I have listbox with horizontal scroll bar. I just had to add ColumnWidths property.
For example I have
me.Listbox1.Columnwidts ="0.5 in;0.2 in;1.5 in;0.75 in;0.5 in"
Unless I'm missing something, a VBA listbox will automatically gain a horizontal scrollbar if the total of its ColumnWidths property exceeds its own width.
There are no properties I know of that affect this behaviour, i.e. I don't otherwise know how to force or disable display of the horizontal scrollbar.
Access will automatically add a horizontal scrollbar if the column width exceed the width of the listbox. HOWEVER, if you are using multiple columns, the first column cannot be set to 0. You must have at least some value in there, even if it's just 0.1" Hope this helps.
In that article, the only reason it's getting ScaleMode is to set the width of the horizontal scroll bar. You don't have to do that.
SendMessageByNum List1.hwnd, LB_SETHORIZONTALEXTENT, 800, 0
where 800 is the pixel width you want the list box to be able to scroll right to.
You will still need the hWnd. Best bet there is to use an external DLL (written in VB) which can enum through child windows of your process until it finds the windows class for the listbox (you will need to find some way to uniquely identify its parent, such as the window title/text or something). That same DLL could also do the SendMessage call above to set the horizontal text extent (perhaps also it could measure the width of the contained list items).
Handle to he list box can be obtained as follows :-
Dim ListHwnd As Integer
lstboxName.SetFocus
ListHwnd = GetFocus()
Use this ListHwnd as the first parameter to the sendmessage function...
We need to provide the declaration below,Since GetFocus function is not present in VBA by default
Private Declare Function GetFocus Lib "user32" () As Integer
In Visual Studio 2017, you can click on the list box, then go to the properties panel, and then (scroll down to) find the 'HorizontailScrollbar' property. By default this is property is set to false, so you should set it to true.
You know you have set the scroll bar properly when a small triangle appears in the top right corner of the list box.
Hope this helps.

Spotfire Where can I see how were the property controls set up?

I am trying to duplicate a page from one dashboard to the other. In order to do so, I need to create the same property controls that are on the original page to my new page. Where can I see how were the property controls set up?
I've tried several things:
1. under Document Property - Properties, I can only see the first value for that property control but still don't know what are the rest.
2. I am trying to dropbox-list the property control under text area, but when I click on the name of the control - the content does not show the corresponding setting of the control, which only let you to create/edit from the default.
Thank you so much for your help!
Since you stated you are trying to see what the mappings are to a property control used in the text area, you have to "edit the text area" to see it.
In the text area, Right Click > Edit Text Area > Double Click the Property Control
This will bring up the configuration, specifically what the values are set to.

DrawItem in listbox (VC++)

When we will use DrawItem for a listbox?
Normally, if the listbox is ownerdraw, we will use DrawItem. What are the other senarios we use drawitem?
To elaborate on Rashmi Pandit; A ListBox with override DrawItem can also be used to 'visualize' objects. In a project I'm working on, a ListBox is used to display rows from a database. Each row / item is visualized using formatted Strings, Icons etc.
Overriding DrawItem (and MeasureItem!) is ideal for this purpose. Of course, the internal structure has to be tweaked a bit (the standard Items property cannot be used for objects), but it is certainly worthwhile.
Message WM_DRAWITEM is sent only to owner-drawn List boxes.
You can use DrawItem when you want to override the default implementation and custom the way a listbox is drawn. For e.g. in the list there might be some item which should is the default item and you would want it to be highlighted so that the user knows it is the default item.
Here's an eg for a combo in C#: Higlighting a particular item in a combo box

Resources