ListBox Form Control Scrolling - excel

I've been doing a ton of research and I'm finally giving in and hoping the community can help. I have a FORM CONTROL list box, not an active x. I'm intentionally using form control for a variety of reasons that are not necessarily important (unless you can guide me how to 100% ensure activeX controls don't resize themselves on workbook open). I cannot, for the life of me, figure out how to get the form control list box to scroll to the selected value and put it in view. Here is what I have:
ActiveSheet.ListBoxes("List Box 13").Selected = 100
The list has 1000 values in it to be selected. When this runs, #100 is selected, but is not in view. The list box does not move.
How can I get the scrolling to occur so the selected value is at the top?
ActiveX would be:
.TopIndex
But that is not available for form controls.

Scroll to given listbox index to be displayed on top of visible list
I cannot, for the life of me, figure out how to get the form control list box to scroll to the selected value and put it in view.
Seems that actually there's no standard method (leaving aside API calls) to control the visibility of the listbox interior display for a form control list box as opposed to a Userform's ActiveX control list box.
Additional hints
For the sake of completeness (and due to comment) I demonstrate how to scroll into view in a Userform's listbox by combining both navigation properties - i.e. by setting .ListIndex as well as .TopIndex together with a defined index value :-), e.g. via a procedure as follows:
Example calls
ScrollTo 100 ' attention: zerobased
or
ScrollTo ActiveSheet.ListBoxes("List Box 13").Selected
Helper procedure
... sets the current ListIndex to e.g. 100 AND defines it as .TopIndex.
(Side note: of course targets at the very list end could be displayed even below .TopIndex depending on the actual .ListCount)
Private Sub ScrollTo(ByVal idx&)
' Purpose: Scroll to given target index to be displayed on top of visible list
' Site: https://stackoverflow.com/questions/56813550/listbox-form-control-scrolling
' Author: https://stackoverflow.com/users/6460297/t-m
Me.ListBox1.TopIndex = idx
Me.ListBox1.ListIndex = idx
End Sub

Related

How to prevent UserForm from covering controls on a Worksheet?

Using several API calls, I'm positioning a UserForm centered on the screen.
During navigation from this UserForm (a custom "MsgBox" equivalent), I am trying to show the user a button which is located on the sheet behind the UserForm.
Depending on the resolution and size of monitor, the sheet behind the form has different zoom factors, and most of the time the button being highlighted on the sheet is visible.
Sometimes the UserForm completely covers the button.
I have had some success determining whether the form is covering the button, but I'm running into problems which I assume are due to scaling.
Dim button as Shape
'helpBtnTop is used ByRef to provide the converted measurement
Dim helpBtnTop as Single
Set button = ThisWorkbook.Sheets("MySheet").Shapes("HelpButton")
'API Call in the following sub uses ConvertPixelsToPoints API to find the top using a conditional string arg
'"Pos" to look at only the Top measurement of the UserForm (left and Right won't matter for this use case).
ReturnPosition button.Top, sngTop:=helpBtnTop, Pos:="Top"
With UserForm
'My problem is right here - the code itself does not _fail to execute_ but UserForm.Top,
'button.Top, NOR helpBtnTop match up in any context. I know some of this
'has to do with Points vs Pixels, but I'm trying to determine which way I need to go for the
'proper conversion. Do I convert the UserForm.Top property to Points? Are they already in
'Points and thus need to be converted back to Pixels? Or should I be converting the button.Top
'Property instead, and then calculating from there?
'
If .Top >= button.top Then
.Top = button.top - .Height
End If
'For example - I have the top of my UserForm lined up directly in line
'(as close to pixel perfect as I can get) with the button - the various .Top properties are as follows:
'UserForm.Top = 379.5
'button.top = 386.25
'helpBtnTop = 357.75.
End With
I'll eventually include the .Height property of the UserForm in my figuring since I want to make sure the total value of all of the UserForm's area will not block the view of the button, but I would first like to understand what I need to do to compare apples to apples and not oranges.
If I take the top of each object and convert using ActiveWindow.PointsToPixelsY for the measurement, I get within 6 units (assuming Pixels in this case) to each other, so I would have to do some conversion to each and base the math on that. Is this my only alternative?

VBA Listbox not updating to reflect new source list when called from itself

Edit:
Playing around further, it seems that you can't assign a new array to a listbox via the .list=somelist approach when the assignment happens in response to a click on the listbox itself. Or rather, you can assign the list, but it simply won't visually populate the listbox...although Excel seems to think it's there.
The .additem or .removeitem methods do however result in a visual change when called from a listbox click, which means you have to build your new array up that way I guess. How tedious.
You can however feed a listbox an entirely new array using the .list=somelist approach via a CommandButton-initiated action. But the user has to obviously click a button to do this. Which in my case below defeats the purpose.
Edit Over.
I'm designing a UserForm to help filter PivotTables. It's a cross between the existing Pivot Filter functionality and a Slicer. Here's what you see if you double-click on a PivotField header:
Note the Search field at the top, and the three buttons immediately below that search field. If you type something into that field, then instead of displaying everything that's currently filtered, you instead get a list of any matches, and you can then apply those search results to the underlying PivotTable via those three CommandButtons. The first cb simply filters the PivotTable to reflect the search, and the other two let you add or remove any search result from an existing filter.
I want to do away with those three command buttons, and instead (in the event that a search is performed) simply list those three options at the top of the ListBox above any search results returned. Clicking on those three options will then trigger the exact same code as currently triggered by the Command Button.
Here's how that looks currently if I actually type something in that Search box (Note I haven't yet removed the three command buttons this does away with from that Search frame):
I've added a simple bit of code to the lbResults_Change() event handler that checks if a user clicks any of those first three options. All that code does is trigger the exact same routines as would be triggered if they'd simply clicked on the actual command buttons themselves:
For i = 0 To 4
If Me.lbResults.Selected(i) Then Exit For
Next i
Select Case i
Case 0: cmdApplySearch_Click
Case 1: cmdAddToFilter_Click
Case 2: cmdSubtractFromFilter_Click
Case 3: Me.lbResults.Selected(3) = False
End Select
Here' the problem: The listbox gets updated just fine if I click on those command buttons, as you can see from the below. The Pivot has been filtered accordingly, and those contextual search options have been removed from the top of the listbox (and the search field cleared):
But the listbox does NOT get updated if the exact same routine is triggered from a click on one of those top three options in listbox itself:
As you can see from the above screenshot, it still shows those three options at the top, even though they are NOT in the array that I assigned to the listbox, as evidenced by the screenshot below:
But as you could see from the earlier screenshot, it shows 7 items in the ListBox instead of the three there actually are. But there are indeed just three items that should be showing in that list box:
? .ListCount
3
? .List(0)
263213: ICT Systems Test Engineer
? .List(1)
263299: ICT Support and Test Engineers nec
? .List(2)
839313: Product Tester
Basically, as soon as I try to update what's in the listbox via a click on the listbox itself, I can't update it.
It doesn't seem to matter if I set focus to something other than the listbox before the filtering code executes, and I've even tried completely clearing the Listbox with .clear. It just doesn't clear, until I manually click on one of those command buttons again.
Anyone have any pointers?
Ah, what an idiot I am for overlooking the painfully obvious solution. The ListBox list happily redraws in response to any event other than the ListBox_Click event, right? So all I needed to do was to use the ListBox_Click event to determine what got clicked (as I currently do), and then use the ListBox_MouseUp event to trigger the actual updating of the ListBox list. Works a treat.
Hopefully this post will save someone else two days of pain in the future. Probably me.

Setting the minimum width of a ComboBox & AutoSize

I was wondering if this is possible to do or not. I am pretty sure it’s not, but wanted to see if it was and someone else might know how. I am using Excel 2010 and everything is being done with VBA. What I would like to do is set a ComboBox with a minimum width size and then AutoSize if typed data becomes longer than the length of the ComboBox.
OK, so let me clarify some misconceptions or questions that I am going to get asked about, such as why I would want to allow users to type in a ComboBox. On another sheet, apart from the sheet that the ComboBox is on, I have a list of items. As items are typed in here the ComboBox is populated with the new item, I also have it sorting the list in alphabetical order and it spell checks them too, as they are being added.
I then have the code to also check for the longest length of text in each cell and the ComboBox will size to the longest length of text within its list, so it can fully be read in the dropdown.
I also want users to be able to type in the ComboBox for items that are not in the list already. The list is for just the most common items used, but often other miscellaneous stuff needs to be entered. I don’t want the miscellaneous stuff added to the list within the ComboBox, so I just want the user to be able to type in data within the ComboBox, but if it is used a lot they can add it to the list on the other sheet.
In case someone is wondering, I do have spellcheck working for the ComboBox when users type data in. All I did was make the cell that the ComboBox is over equal to the text in the ComboBox when the ComboBox is deactivated (LostFocus), then I spellcheck that cell, followed by making the ComboBox equal to the cell that was just spellchecked.
Anyway, as already mentioned I do have the ComboBox’s width set to the longest item in the list using code. Is there a way that I can somehow keep the ComboBox’s minimum width set to this size, but then the width will increase when the user is typing data in that becomes longer than what the box is currently set to? I am guessing this would be easy to do if I was to adjust it after the user finished typing (when the ComboBox LostFocus), but is it possible to do this while they are typing? Setting the AutoSize will not work, because it will ignore the size of the longest item in the list, and shrink to almost nothing, making it impossible to see the items in the list. The other issue with AutoSize is that you can’t read items in the list as you are typing. Like when you are typing it will prefill items from the list as you are typing, but the prefilled items can’t be read when using AutoSize.
I guess it is possible to do, I just figured it out. The iLength is what determines the default minimum width size should be, which is slightly larger than the size of a column in a different sheet where the ComboBox is pulling its data from. I just did some basic calculations to figure that the length (character count) of text being typed in the notes field is about 4.5 times smaller than the default length. Of course, the 4.5 would change if I used a different sized font. If the typed text (based on the calculation) becomes greater than the default size, I set the ComboBox to AutoSize, otherwise AutoSize was set to False. Then when I cleared the data from the field I just have the code in the clear button to reset the ComboBox back to the default size and to set AutoSize to False. This works perfectly.
Private Sub cboNotes_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim iLength As Integer
iLength = Sheets("Notes").Range("A1").Columns.Width + 20
If Len(cboNotes.Value) * 4.5 < iLength Then
cboNotes.Width = Sheets("Notes").Range("A1").Columns.Width + 20
cboNotes.AutoSize = False
Exit Sub
Else
cboNotes.AutoSize = True
Exit Sub
End If
End Sub

Add/Remove controls dynamically in .NET 2.0 CF Forms project

I am working on a mobile 2.0 project that is displaying a list of custom controls (each containing labels and check box). I want to find a better way to keep track of control positions.
The controls are contained within a scrollable panel.
The hierarchy of controls is basically like this
Menu Type 1
Menu Sub Type 1
Menu Item 1
Menu Item 2
Menu Type 2
Menu Sub Type 2
Menu Item 3
Menu Item 4
And the way I add them initially is panel.Controls.Add(controlToAdd)
And each subsequent control's position is determined by the previous control:
newControl.Top = lastControl.Bottom
That works fine on initial load, but I now need to be able to add/remove controls. I know I can just
find where I need to insert it
set the new controls location
change the positions of all controls that follow it (offset based on the height of the new control)
But that seems like a "bad" way since if the control always adds at the front, every single latter control needs updating. Is there a way to better manage the positions of all the controls to ease additions and removals dynamically?

How to select the first item of a combo box in an Access Web-compatible form?

I've created an Access Web database on SharePoint 2010 and I'm editing its forms with Access 2010.
One form includes a set of cascading combo boxes that I've created following these tutorials
Combo Box in Access and Cascading Combo Boxes. The actual data binding is working as expected.
The issue is that when the cascaded combo boxes receive their bound values, the selected item is left blank and I'd like it to pick the first element by default i.e. combo.items(0)
I understand that I'll have to add some sort of macro to select the first element. However, I haven't found a way to do so.
Currently the primary combo boxes invoke through an after update event a requery action on the cascaded combos.
Is there another action that could force as well the selection of the first bound item?
Take a look at http://www.access-programmers.co.uk/forums/showthread.php?t=38754
You can do this trick OnLoad. So your VBA code behind the form will look something like:
Private Sub Form_Load()
Me.cboTestCombo = Me.cboTestCombo.Column(0, 0)
End Sub
You may need to play around with the indices on Column(N, N) - the example above worked for me to place the first entry from my data rowsource in the combo at start.

Resources