15

This thread discusses a problem I've been having with ActiveX objects in an Excel spreadsheet. It's a mess to read through and ultimately doesn't have a cohesive answer.

The problem is 100% reproduceable:

  1. Open workbook with ActiveX objects in spreadsheet while using a docking station
  2. Disconnect machine from docking station, triggering a resolution change (there are other causes too, mine is with a docking station, it seems changing resolution causes this)
  3. Click an ActiveX control - they immediately resize and the font changes size. The fontsize change is NOT a function of the .Font.Size parameter but something which cannot be changed after the problem occurs, other than continually increasing the fontsize

The only seemingly authoritative solution involves a MS patch (it was a "hotfix" several years ago, though, so it doesn't seem practical for full deployment) and registry edits, which is not practical for my use case.

I am looking for a way to either:

  1. Prevent this change from occuring
  2. Find the best work around

There is a lack of authoritative information on this problem online. I am intending to post my work around, however, it is not even close to ideal and I would much prefer a better solution.

enderland
  • 13,825
  • 17
  • 98
  • 152

8 Answers8

2

My work around is to programmatically iterate through all OLE objects on the sheet* and write code to the debugger, then include a button basically "resize objects" on the sheet - with instructions on why this problem is occurring.

This method will generate the code to drive that button.

It will not automatically update however - it is a snapshot and should only be used immediately prior to deployment of an app (if end users are going to have the button functionality).

The sequence then becomes:

  1. Run code generated with following method
  2. Save workbook immediately - this does NOT prevent the font changes from continuing to occur
  3. Reopen workbook and problem is "solved"

Private Sub printAllActiveXSizeInformation()
    Dim myWS As Worksheet
    Dim OLEobj As OLEObject
    Dim obName As String
    Dim shName As String

    'you could easily set a for/each loop for all worksheets
    Set myWS = Sheet1

    shName = myWS.name

    Dim mFile As String
    mFile = "C:\Users\you\Desktop\ActiveXInfo.txt"


    Open mFile For Output As #1
    With myWS
        For Each OLEobj In myWS.OLEObjects
            obName = OLEobj.name

            Print #1, "'" + obName
            Print #1, shName + "." + obName + ".Left=" + CStr(OLEobj.Left)
            Print #1, shName + "." + obName + ".Width=" + CStr(OLEobj.Width)
            Print #1, shName + "." + obName + ".Height=" + CStr(OLEobj.Height)
            Print #1, shName + "." + obName + ".Top=" + CStr(OLEobj.Top)
            Print #1, "ActiveSheet.Shapes(""" + obName + """).ScaleHeight 1.25, msoFalse, msoScaleFromTopLeft"
            Print #1, "ActiveSheet.Shapes(""" + obName + """).ScaleHeight 0.8, msoFalse, msoScaleFromTopLeft"

        Next OLEobj
    End With

    Close #1

    Shell "NotePad " + mFile



End Sub

*note: this will not find objects which are grouped, unfortunately, either.

enderland
  • 13,825
  • 17
  • 98
  • 152
1

The only 100% reliable workaround is to close and restart Excel (including any invisible instances). Any other solution has some problem.

That's one of the reasons why I avoid controls when possible. See here for an example.

Community
  • 1
  • 1
stenci
  • 8,290
  • 14
  • 64
  • 104
  • 1
    this solution worked for me, in order to restart Excel (including any invisible instances) i use the command `taskkill /f /im excel.exe` via cmd. – Jonathan Applebaum Jul 16 '17 at 10:34
1

This module was Created by dlmille of E-E March 20, 2011

This is an exercise to store active-x control settings in a workbook, on a sheet basis, preserving their settings if/when Excel gets "quirky" and shape sizes go askew While the ListBox has an IntegralHeight property whose side-affect of a FALSE setting will keep that control from going askew, and while command buttons have properties such as move/size with cells, etc., other controls are not as graceful.

The routine setControlsOnSheet(): 1) obtains the 6 common control settings, for every OLEObject (active-x) control on the active sheet, and 2) stores those settings into a string array, sControlSettings(), and 3) adds/updates a defined name (which is hidden) with those settings.

The defined name for each control on a sheet is built up based on the active sheet name and the control name (which should create a unique instance)

Process: The user creates whatever controls are going to be on the worksheet, and at any point, the setControlsOnSheet() routine can be run, to either initially store the settings for all controls, refresh those settings, or add new settings (as it does this for every control on the sheet).

Care should be taken to ensure all settings "look right" (e.g., Excel has as yet to get "quirky", or the user has just adjusted one to many of his controls and is ready to "save" their settings. Otherwise, any improperly sized controls' settings would get stored.

Rather than make this routine process intensive, the ThisWorkbook event for sheet activate will "reinitialize" all settings for all controls that exist on the sheet that was just selected. This way, the control settings on the sheet are "restored" to their most recently saved settings, thus "forever?" avoiding the Excel "quirky" resizing consequence.

As a potential enhancement, this app could be embedded in a class module as part of an add-in, thus keeping any related code out of the users "normal" programming environment. E.g., the sheet activate event trapping would be captured in the class module, rather than the user having to add it to his/her ThisWorkbook module.

Const CONTROL_OPTIONS = "Height;Left;Locked;Placement;Top;Width" 'some potentially useful settings to store and sustain

Function refreshControlsOnSheet(sh As Object)'routine enumerates all objects on the worksheet (sh), determines which have stored settings, then refreshes those settings from storage (in the defined names arena)

Dim myControl As OLEObject
Dim sBuildControlName As String
Dim sControlSettings As Variant

For Each myControl In ActiveSheet.OLEObjects
    sBuildControlName = "_" & myControl.Name & "_Range" 'builds a range name based on the control name
    'test for existance of previously-saved settings
    On Error Resume Next
    sControlSettings = Evaluate(sBuildControlName) 'ActiveWorkbook.Names(sBuildControlName).RefersTo 'load the array of settings
    If Err.Number = 0 Then ' the settings for this control are in storage, so refresh settings for the control
        myControl.Height = sControlSettings(1)
        myControl.Left = sControlSettings(2)
        myControl.Locked = sControlSettings(3)
        myControl.Placement = sControlSettings(4)
        myControl.Top = sControlSettings(5)
        myControl.Width = sControlSettings(6)
    End If
    Err.Clear
    On Error GoTo 0
Next myControl      
End Function

Private Sub storeControlSettings(sControl As String)
Dim sBuildControlName As String
Dim sControlSettings(1 To 6) As Variant ' set to the number of control settings to be stored
Dim oControl As Variant

Set oControl = ActiveSheet.OLEObjects(sControl)

'store the settings to retain, so they can be reset on demand, thus avoiding Excel's resizing "problem"
'create array of settings to be stored, with order dictated by CONTROL_OPTIONS for consistency/documentation

sControlSettings(1) = oControl.Height
sControlSettings(2) = oControl.Left
sControlSettings(3) = oControl.Locked
sControlSettings(4) = oControl.Placement
sControlSettings(5) = oControl.Top
sControlSettings(6) = oControl.Width


sBuildControlName = "_" & sControl & "_Range" 'builds a range name based on the control name

Application.Names.Add Name:="'" & ActiveSheet.Name & "'!" & sBuildControlName, RefersTo:=sControlSettings, Visible:=False 'Adds the control's settings to the defined names area and hides the range name
End Sub


Public Sub setControlsOnSheet()
Dim myControl As OLEObject

If vbYes = MsgBox("If you click 'Yes' the settings for all controls on your active worksheet will be stored as they CURRENTLY exist. " & vbCrLf & vbCrLf _
                & "Are you sure you want to continue (any previous settings will be overwritten)?", vbYesNo, "Store Control Settings") Then

    For Each myControl In ActiveSheet.OLEObjects 'theoretically, one could manage settings for all controls of this type...
        storeControlSettings (myControl.Name)
    Next myControl

    MsgBox "Settings have have been stored", vbOKOnly
End If
Application.EnableEvents = True 'to ensure we're set to "fire" on worksheet changes
End Sub
0

Similar problems exist for Comments and Shapes. One workaround is to write a macro to record the .Width and .Height properties as well as the sheet position properties of each object on an unused worksheet. Then write a second macro to re-establish these properties on demand.

Gary's Student
  • 95,722
  • 10
  • 59
  • 99
  • You are suggesting my [current work around](http://stackoverflow.com/a/19385914/1048539). It doesn't find grouped objects, unfortunately... – enderland Oct 15 '13 at 16:15
  • @enderland: Instead of using `OLEObjects` for looping, did you try it with shapes? – Siddharth Rout Jan 30 '14 at 21:29
  • @SiddharthRout aww you just made me realize the method I'm using for [this question](http://stackoverflow.com/q/21466989/1048539) also won't find grouped objects :( – enderland Jan 30 '14 at 21:44
  • To find grouped objects, use shapes. OleObjects have a type 12, Form Controls have 8 and Grouped shapes have 6 I believe... – Siddharth Rout Jan 30 '14 at 21:45
  • Garry, sorry to have hijacked your post. @enderland: We can carry this conversation under your post if you want. – Siddharth Rout Jan 30 '14 at 21:46
0

This was happening to me in the past (after or while using a distant connection to my PC), but I had come up with a solution to resize the commandbuttons and their fonts using the Workbook_WindowActivate event (this could be done through a "reset settings" button as well I suppose).

Anyhow, I thought all was fixed until today when I used again a distant connection and two commandbuttons started to misbehave. I found out that those 2 commandbuttons had the Placement property set to 2 (Object is moved with the cells) while I had set it to 3 (Object is free floating) for the others in the past.

But before finding this, I was trying to set the font size of the buttons to what I wanted (through the properties window), but Windows was disregarding any number I was using, up until I changed the height of the button... all of a sudden it read the font size property and adjusted it accordingly.

I am not sure if the placement property is actually part of the issue, but just to be sure, I use the 2 solutions:

(1) placement is set to 3

(2) my "auto-resize" function that triggers with the Workbook_WindowActivate event increases the button and font size a little before reducing them back to what they should. But maybe solution (1) would be sufficient... I have no time to test right now. Here's the code for my Workbook_Activate event:

Worksheets(1).Shapes("CommandButton1").Top = 0
Worksheets(1).Shapes("CommandButton1").Left = 206.25
Worksheets(1).Shapes("CommandButton1").Width = 75
Worksheets(1).OLEObjects(1).Object.Font.Size = 10
Worksheets(1).Shapes("CommandButton1").Height = 21
Worksheets(1).Shapes("CommandButton1").Height = 18.75
Worksheets(1).OLEObjects(1).Object.Font.Size = 8

Now all works fine. Took me some time in the past to find a solution on the net. I hope this will help at least one person out there ;-)

Allan Pereira
  • 2,572
  • 4
  • 21
  • 28
Xeliax
  • 1
0

I had several issues with the buttons, font size being one of them. I also had buttons resizing and the pictures within them resizing. I could programatically change the button size back, but couldn't find a way to change the picture size that way. I think I've found what may be the ultimate solution to these problems.

If I delete the MSForms.exd file from (in my case) C:\Users{UserName}\AppData\Local\Temp\Excel8.0 while you're in the screen resolution you'd like to view the buttons in and then restart Excel, these problems seem to vanish. There are other .exd files you may need to delete for other applications. Some of them are:

C:\Users\[user.name]\AppData\Local\Temp\Excel8.0\MSForms.exd

C:\Users\[user.name]\AppData\Local\Temp\VBE\MSForms.exd

C:\Users\[user.name]\AppData\Local\Temp\Word8.0\MSForms.exd

There's one for PowerPoint as well, but I can't seem to locate the related support document (which does not really call out these specific problems as far as I can remember)

tbaker818
  • 121
  • 1
  • 10
0

I think @RuiHonori had the best answer, but in order for me to get my controls on all my sheets to where i wanted them to be - which all happened to be the same size - I used this:

Sub SizeControls()
    Dim myControl As OLEObject
    Dim WS As Worksheet
    For Each WS In ThisWorkbook.Worksheets
        For Each myControl In WS.OLEObjects
            myControl.Height = 42.75
            myControl.Width = 96
        Next myControl
    Next WS
End Sub
0

I prepared a solution which is a variation on Rui Honorio's suggestion.

I placed a multi-column combobox on the sheet. My version of the "store" routine loops through all OLE Objects on a sheet (except for the aforementioned combobox) and records the name and selected attributes.

The combobox is then a rather compact / embedded component of the sheet. It doesn't take up any cells on the parent worksheet (or on any other sheet for that matter). It can be placed in an obscure location or hidden altogether.

Either a trigger or manual run of the "refresh" routine can then take the attributes from each list-item in the combobox and reset them for each control.

I'm very surprised and extremely frustrated that Microsoft hasn't fixed this bug. I've had intermittent encounters with it for years!