You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

执行VBA代码后Excel按钮位置与尺寸异常问题求助

问题描述

我编写了如下VBA代码用于清理表格行:

Sub code_clearance_cable()
Dim ws As Worksheet, dict
Dim lastrow As Long, i As Long, n As Long
Dim key As String
Dim xCell As Range
Dim xRng1 As Range

Dim fso, ts
Set fso = CreateObject("Scripting.FilesystemObject")
Set ts = fso.CreateTextFile("debug.txt")

Set dict = CreateObject("Scripting.Dictionary")
Set ws = ThisWorkbook.Sheets("Cable Work Order")
Set xRng1 = ws.Columns("H")
With ws
    lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
    For i = lastrow To 2 Step -1
         If Len(Trim(.Cells(i, "H"))) = 0 Then
            key = Trim(.Cells(i, "A"))
            If dict.exists(key) Then
               .Rows(i).Delete
               n = n + 1
            Else
               dict.Add key, i
            End If
        Else
            key = ""
        End If
        ts.writeline i & " A='" & .Cells(i, "A") & "' H='" _
            & .Cells(i, "H") & "' key='" & key & "' n=" & n
     Next
  End With
  ts.Close

 End Sub

尽管已将按钮设置为不随单元格移动和大小调整,但执行该代码后,关闭并重新打开文档时,表单控件和ActiveX按钮的位置与尺寸均出现异常。请问能否通过编程方式解决该问题?

解决方案

可以通过编程方式锁定控件的位置和尺寸,在删除行的代码执行前后添加控件属性设置逻辑,具体方法如下:

方法1:操作前锁定控件,操作后确认(推荐)

在删除行操作前,先将工作表上所有表单控件和ActiveX控件的位置行为强制设置为固定,执行完删除操作后再确认属性:

Sub code_clearance_cable()
Dim ws As Worksheet, dict
Dim lastrow As Long, i As Long, n As Long
Dim key As String
Dim xCtrl As Object ' 遍历控件用

Dim fso, ts
Set fso = CreateObject("Scripting.FilesystemObject")
Set ts = fso.CreateTextFile("debug.txt")

Set dict = CreateObject("Scripting.Dictionary")
Set ws = ThisWorkbook.Sheets("Cable Work Order")
Set xRng1 = ws.Columns("H")

' --- 新增:锁定所有控件位置 ---
' 处理表单控件
For Each xCtrl In ws.Shapes
    If xCtrl.Type = msoFormControl Then
        xCtrl.Placement = xlFreeFloating ' 固定不随单元格变动
        xCtrl.Locked = True
    End If
Next
' 处理ActiveX控件
For Each xCtrl In ws.OLEObjects
    xCtrl.Placement = xlFreeFloating
    xCtrl.Locked = True
Next
' --- 锁定结束 ---

With ws
    lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
    For i = lastrow To 2 Step -1
         If Len(Trim(.Cells(i, "H"))) = 0 Then
            key = Trim(.Cells(i, "A"))
            If dict.exists(key) Then
               .Rows(i).Delete
               n = n + 1
            Else
               dict.Add key, i
            End If
        Else
            key = ""
        End If
        ts.writeline i & " A='" & .Cells(i, "A") & "' H='" _
            & .Cells(i, "H") & "' key='" & key & "' n=" & n
     Next
  End With

' --- 再次确认控件属性,防止意外变动 ---
For Each xCtrl In ws.Shapes
    If xCtrl.Type = msoFormControl Then
        xCtrl.Placement = xlFreeFloating
    End If
Next
For Each xCtrl In ws.OLEObjects
    xCtrl.Placement = xlFreeFloating
Next

ts.Close

 End Sub

方法2:删除行后重置控件位置

如果方法1无效,可以在删除行前记录控件的原始位置和尺寸,操作完成后用记录值重置:

Sub code_clearance_cable()
Dim ws As Worksheet, dict
Dim lastrow As Long, i As Long, n As Long
Dim key As String
Dim xCtrl As Object
Dim ctrlProps As Object ' 存储控件原始属性

Dim fso, ts
Set fso = CreateObject("Scripting.FilesystemObject")
Set ts = fso.CreateTextFile("debug.txt")

Set dict = CreateObject("Scripting.Dictionary")
Set ws = ThisWorkbook.Sheets("Cable Work Order")
Set xRng1 = ws.Columns("H")
Set ctrlProps = CreateObject("Scripting.Dictionary")

' --- 记录控件原始位置和尺寸 ---
For Each xCtrl In ws.Shapes
    If xCtrl.Type = msoFormControl Then
        ctrlProps.Add xCtrl.Name, Array(xCtrl.Top, xCtrl.Left, xCtrl.Width, xCtrl.Height)
    End If
Next
For Each xCtrl In ws.OLEObjects
    ctrlProps.Add xCtrl.Name, Array(xCtrl.Top, xCtrl.Left, xCtrl.Width, xCtrl.Height)
Next
' --- 记录结束 ---

With ws
    lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
    For i = lastrow To 2 Step -1
         If Len(Trim(.Cells(i, "H"))) = 0 Then
            key = Trim(.Cells(i, "A"))
            If dict.exists(key) Then
               .Rows(i).Delete
               n = n + 1
            Else
               dict.Add key, i
            End If
        Else
            key = ""
        End If
        ts.writeline i & " A='" & .Cells(i, "A") & "' H='" _
            & .Cells(i, "H") & "' key='" & key & "' n=" & n
     Next
  End With

' --- 重置控件位置和尺寸 ---
For Each xCtrl In ws.Shapes
    If ctrlProps.exists(xCtrl.Name) Then
        xCtrl.Top = ctrlProps(xCtrl.Name)(0)
        xCtrl.Left = ctrlProps(xCtrl.Name)(1)
        xCtrl.Width = ctrlProps(xCtrl.Name)(2)
        xCtrl.Height = ctrlProps(xCtrl.Name)(3)
        xCtrl.Placement = xlFreeFloating
    End If
Next
For Each xCtrl In ws.OLEObjects
    If ctrlProps.exists(xCtrl.Name) Then
        xCtrl.Top = ctrlProps(xCtrl.Name)(0)
        xCtrl.Left = ctrlProps(xCtrl.Name)(1)
        xCtrl.Width = ctrlProps(xCtrl.Name)(2)
        xCtrl.Height = ctrlProps(xCtrl.Name)(3)
        xCtrl.Placement = xlFreeFloating
    End If
Next
' --- 重置结束 ---

ts.Close

 End Sub

额外注意事项

  • 如果工作表处于保护状态,需先解除保护(ws.Unprotect Password:="你的密码"),操作完成后再重新保护(ws.Protect Password:="你的密码")
  • 可在代码开头添加Application.EnableEvents = False,结尾添加Application.EnableEvents = True,避免删除行时触发控件的意外事件

内容的提问来源于stack exchange,提问作者Geographos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 15:40:38