How to prevent UserForm from covering controls on a Worksheet? - excel

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?

Related

Auto fit a non activex userform shapes and boxes to different screen sizes?

Challenge
Userform pictures/shapes and textboxes does not fit to different screen sizes.
I have different users with different desktop/laptop screen sizes
Misconception
I don't want to fit userform itself, I just want to fit objects(combobox/pictures) instead.
What I have tried
I tried to convert it to an active x form (to fix the shapes regardless of the screen size) instead but it would take a long time to rename shapes and re-write the code. (Not time efficent)
I tried to fix the width, top, height, disable/enable auto fit for all objects as well as userform, but still don't fit.
I tried to recognize the screen size and then fit objects, not time efficient
I need to fit shapes inside a non active x userform to fit all screen sizes, any ideas?
It worked only when I converted the USERFORM (Code & Design) to ActiveX Form (Worksheet).
Only thing to change from (ME.Object Name) to (Thisworkbook.worksheets("Name").ObjectName)
It took some time but worked finally.

ListBox Form Control Scrolling

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

Determine Visible Worksheet Area Size in Points

I am trying to determine the visible worksheet area in points. So far, I have tried the Application.Width, but that gives me the entire area including the scroll bars, and likewise Application.Height includes the ribbon and horizontal scroll bar. What I need specifically is the size of only this viewable worksheet area.
Something I have tried so far is looking at the visible range. For example, if I can see A1 thru AA40, then I can use the code
Debug.Print ws.Range("A1:AA40").Width
Debug.Print ws.Range("A1:AA40").Height
The only problem with this is if I can see half of column AB and half of row 41, then I don't have the full size. Also, it is not adjustable if I decide to change the application window size to half the screen.
I have no need for converting into the number of pixels, I just need the point sizes. Does anyone know a way to get the visible area size, or at the very least how to resize a range to fit only this visible area?
You can access the Windows collection of Application and use the Width and Height properties of items of that collection. E.g.
Debug.Print Application.Windows(1).Width
Debug.Print Application.Windows(1).Height
You can also refer to ActiveWindow and get the properties from that as well.
Example:
Grid's dimensions:
?Activewindow.activepane.VisibleRange.Height, Activewindow.activepane.VisibleRange.Width
The above worked for me, returning the dimensions of only Excel's grid which could be seen on my screen- no scrollbars, no Ribbon, no formula bar - just cells displayed.

How to make a shape follow a row when sorting?

I've created a macro that I assigned to a shape, which allows me to click on the shape to hide or show a picture. This works great !
What I want to do now is link this shape to a row of a spreadsheet, in a way that when I sort my spreadsheet, my shape follows the same row. It currently stays on the same cell when I sort (I do select all of the cells when I sort)
What I've tried so far :
-I have right clicked and set the properties of the shape to "move and size with cells". This does not prevent the problem.
-Typing "=the_name_of_the_cell" into the cell containing the shape, but it doesnt work.
Thanks in advance !
edit : rephrased it
You can use the shape's .Left and .Top properties to move it to a fixed range on your worksheet. To keep it in a certain row you need only the .Top property.
The following example assumes you want to keep a shape called "Example" on row 7:
ActiveWorksheet.Shapes("Example").Top = ActiveWorksheet.Range("7:7").Top
The shape's property of Move and size with cells will work, but the shape has to precisely fit inside a single-cell for this to work when sorting.
Click the shape, hold the Alt key and resize each of the corners. It should snap into each of the cell's corners (with a little care). Increase the Zoom if it helps.
Hide some text in the cell behind your shape and it should follow with your sort. That worked for me. I also have the shape properties set to "Move and Size With Cells". For example, I have a DELETE button on my row. The button text says "DELETE". The button shape is small and fits in one cell, and so behind it, I typed the word DELETE. The button shape covers it so no one can see it and I also made the font color WHITE so it will not show when printed.

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

Resources