如何停止ActiveX对象在Office中自动更改大小?

15

这篇文章讨论了我在Excel电子表格中使用ActiveX对象时遇到的问题。但是,文章太过混乱,最终没有提供一个连贯的答案。

这个问题可以100%重现:

  1. 在使用底座的情况下打开带有ActiveX对象的工作簿
  2. 将机器从底座上拆下来,会引发分辨率变化(也有其他原因,我的是与底座有关,似乎分辨率变化会导致此问题)
  3. 单击ActiveX控件 - 它们立即调整大小并更改字体大小。字体大小的变化与.Font.Size参数无关,而是发生问题后无法更改的其他事物,除非不断增加字体大小。

唯一看起来可靠的解决方案涉及到一个微软补丁(几年前是一个“热修复”,所以对于全面部署似乎不实用),还需要进行注册表编辑,这在我的使用场景下不实用。

我正在寻找以下两种解决方法:

  1. 防止出现此更改
  2. 找到最佳解决方案

关于这个问题的权威信息很少。我打算发布我的解决方案,但它离理想状态差得远,我更希望有一个更好的解决方案。

8个回答

2
我的解决方法是通过程序遍历工作表上的所有OLE对象,并编写代码到调试器,然后在工作表上包括一个基本的“调整对象大小”按钮 - 并附上为什么会出现这个问题的说明。
这种方法将生成驱动该按钮的代码。
但它不会自动更新 - 它是一个快照,应该仅在部署应用程序之前立即使用(如果最终用户将具有按钮功能)。
然后的步骤如下:
1. 运行使用以下方法生成的代码 2. 立即保存工作簿 - 这不会阻止字体更改继续发生 3. 重新打开工作簿,问题就“解决”了
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

*注意:这种方法无法找到被分组的对象,很遗憾。

@SiddharthRout 看起来.Shapes.OLEObjects一样存在分组问题。 - enderland

1

这个模块是由E-E的dlmille于2011年3月20日创建的。

这是一个练习,用于在工作簿上按表格保存Active-X控件的设置,以保留它们的设置,如果/当Excel变得“古怪”时形状大小会失调。虽然ListBox有一个IntegralHeight属性,其FALSE设置的副作用将使该控件不会失调,而命令按钮具有诸如随单元格移动/调整大小等属性,但其他控件则没有那么优雅。

setControlsOnSheet()例程: 1) 获取当前活动工作表上每个OLEObject(Active-X)控件的6个常见控件设置, 2) 将这些设置存储到一个字符串数组sControlSettings()中, 3) 添加/更新一个定义名称(隐藏),其中包含这些设置。

每个工作表上每个控件的定义名称都是基于活动工作表名称和控件名称(应该创建一个唯一实例)构建的。

过程: 用户创建将要放置在工作表上的任何控件,并且在任何时候,可以运行setControlsOnSheet()例程来初始存储所有控件的设置、刷新这些设置或添加新的设置(因为它对工作表上的每个控件都执行此操作)。

应注意确保所有设置“看起来正确”(例如,Excel尚未变得“古怪”,或者用户刚刚调整了太多控件并准备“保存”它们的设置。否则,任何大小不当的控件设置都将被存储。
为了避免这种例行程序过于繁琐,工作簿事件可在选定表格激活时“重新初始化”该表格上存在的所有控件的所有设置。这样,该表格上的控件设置将“恢复”到其最近保存的设置,从而“永远?”避免了Excel“古怪”的调整后果。
作为一个潜在的增强功能,该应用程序可以作为附加组件的一部分嵌入到类模块中,从而使任何相关代码都不会出现在用户的“正常”编程环境中。例如,表格激活事件捕获将被捕获在类模块中,而不是用户必须将其添加到他/她的ThisWorkbook模块中。
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

1

唯一可靠的解决方法是关闭并重新启动Excel(包括任何不可见的实例)。任何其他解决方案都存在问题。

这就是我尽可能避免使用控件的原因之一。请参阅此处的示例。


1
这个解决方案对我很有效,为了重新启动Excel(包括任何不可见的实例),我使用命令taskkill /f /im excel.exe通过cmd。 - Jonathan Applebaum

0
过去,在我使用远程连接到我的PC时,曾经发生这种情况,但我已经想出了一个解决方案,通过使用Workbook_WindowActivate事件来调整命令按钮及其字体的大小(当然,也可以通过“重置设置”按钮来完成)。
不管怎样,我认为所有问题都已经得到解决,直到今天我再次使用远程连接,两个命令按钮开始表现异常。我发现那2个命令按钮的放置属性被设置为2(对象随单元格移动),而我过去已将其设置为3(对象自由浮动)。
但在发现这个问题之前,我尝试通过属性窗口设置按钮的字体大小,但Windows会忽略我使用的任何数字,直到我改变了按钮的高度……突然间,它读取了字体大小属性并相应地进行了调整。
我不确定放置属性是否实际上是问题的一部分,但为了确保万无一失,我使用了2种解决方法:
(1)将放置属性设置为3

(2)我的“自动调整大小”功能会在Workbook_WindowActivate事件触发时将按钮和字体大小稍微增加,然后再将它们缩小到应有的大小。但也许解决方案(1)已经足够了……我现在没有时间测试。这是我Workbook_Activate事件的代码:

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

现在一切都正常了。过去我花了一些时间在网络上寻找解决方案。希望这能至少帮助到一个人 ;-)


0

评论和形状也存在类似的问题。一种解决方法是编写一个宏来记录每个对象的.Width.Height属性以及工作表位置属性,并将其保存在未使用的工作表上。然后编写第二个宏,在需要时重新建立这些属性。


你建议我使用当前的解决方法。不幸的是,它无法找到分组对象... - enderland
@enderland:你试过使用形状(shapes)来循环,而不是使用OLE对象吗? - Siddharth Rout
@SiddharthRout 噢,你让我意识到我正在使用的方法对于这个问题也无法找到分组对象 :( - enderland
要查找分组对象,请使用形状。OleObjects 的类型为 12,表单控件为 8,分组形状为 6,我想是这样的... - Siddharth Rout
Garry,抱歉我劫持了你的帖子。@enderland:如果你愿意,我们可以在你的帖子下继续这个对话。 - Siddharth Rout

0

我在按钮方面遇到了几个问题,其中之一是字体大小。我还遇到了按钮和其中的图片调整大小的问题。我可以通过编程方式将按钮大小改回来,但找不到一种方法来改变图片大小。我认为我已经找到了可能是这些问题的终极解决方案。

如果我从(在我的情况下)C:\ Users {UserName} \ AppData \ Local \ Temp \ Excel8.0中删除MSForms.exd文件,并在您想要查看按钮的屏幕分辨率中重新启动Excel,则这些问题似乎会消失。您可能需要删除其他应用程序的其他.exd文件。其中一些文件包括:

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

还有一个针对PowerPoint的,但我似乎找不到相关的支持文档(据我记得并没有明确指出这些具体问题)


0

我准备了一个方案,这是对Rui Honorio的建议的一种变化。

我在工作表上放置了一个多列组合框。 我的“存储”程序循环遍历工作表上的所有OLE对象(除了上述组合框),并记录名称和选定的属性。

然后,组合框是工作表的相当紧凑/嵌入式组件。 它不占用父工作表(或任何其他工作表)上的任何单元格。它可以放置在偏僻的位置或完全隐藏。

然后触发器或手动运行“刷新”程序可以获取组合框中每个列表项的属性,并为每个控件重置它们。

我非常惊讶和极度沮丧,Microsoft没有修复此错误。我多年来一直时断时续地遇到它!


0

我认为@RuiHonori的回答是最好的,但为了让我控制所有工作表上的控件到我想要的位置 - 所有这些控件都恰好是相同的大小 - 我使用了以下代码:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接