Powerpoint VBA - 在嵌入式 Excel OLE Object 中编辑 Table 的列名称
Powerpoint VBA - Editting Column Name of Table in Embedded Excel OLE Object
如果你 运行 下面的代码你会得到一个非常有趣的结果(只有 PowerPoint 运行ning,在 运行ning 之前关闭所有 Excel 的实例):
'Optional - Include the "Microsoft Excel 16.0 Object Library"
Option Explicit
Public Sub test()
Dim oslide As slide
Set oslide = ActivePresentation.Slides.add(1, ppLayoutBlank)
Dim oshape As Shape
Set oshape = oslide.Shapes.AddOLEObject(30, 30, 50, 50, "Excel.Sheet")
oshape.OLEFormat.Object.Sheets(1).ListObjects.add(1) 'xlSrcRange
oshape.OLEFormat.Object.Sheets(1).Cells(1, 1) = "fewewq"
oshape.OLEFormat.Object.Close
End Sub
嵌入的 object 已成功创建并且 table 与指定数据一起出现。但是,当您单击嵌入的 object 时,您会收到以下错误:
There isn't enough memory available to read Worksheet.
此 object 无法再以任何其他方式访问,object 的损坏性质在文档 close/open 上持续存在并重新启动。我已验证此问题发生在除我测试过的一个系统之外的所有系统上(PowerPoint/Excel 2016,Windows 7 X64)。
问题
所以我的问题是,任何人都可以重现这个吗?如果可以,为什么会这样?如果将行 "Cells(1, 1)" 更改为 "Cells(2, 1)" 没有问题,似乎编辑 table 的头部会导致某种特殊行为,这与编辑行或其他单元格不同.
研究
关于这个真的没有写过,大部分东西都没有
与此特定问题相关。
This post 声称这是字体太多的问题
安装(> 600)。我测试了这个,我只安装了241...
有 some posts 完全不相关,同样不是
分配到那里去。
我在 MS Word 中测试了相同的代码,似乎工作正常,问题似乎
隔离到 PowerPoint
我试过用代码做一个版本(损坏 object),然后用手做另一个版本(工作 object),保存它们并比较二进制输出(of only the embedded objects). This sounds cool, but it doesn't grant me any greater insight. I can't open with Excel the embedded objects separately as the objects seems to be stored in a proprietary format。二进制的中心区域看起来不同,但我不确定如何或为什么。到目前为止,我还没有发现一种方法可以将其解码为人类可读的信息。
After a significant delay and with proper attribution, I have cross posted this to the Microsoft forums. Maybe someone has some insight over there. I will actively maintain both posts. If I were 100% convinced this was a bug I might even consider opening an issue here.
您可以通过永远不关闭 OLEObject 来完全避免此问题,这会在 2010 年引起问题,尤其是与关联的图表行为结合使用时,您会变得孤立 excel windows 显示。不是很好的用户体验。我想我可以在后台打开一个隐藏的 excel window,然后在我完成嵌入式工作后终止...
我是 运行ning 版本:Microsoft Office 365 ProPlus:版本 1705(内部版本 8201.3103 Click-to-Run),但我也看到了 Microsoft Office Standard 2010 上的问题, 版本 14.0.7015.1000(32 位)。 table 的问题似乎在所有其他版本的 office 上都相同,但我想知道这是否会影响 2010 之前的 office 版本?
更新 1
我用图表尝试了同样的事情:
'Include the "Microsoft Excel 16.0 Object Library"
Option Explicit
Sub test()
Dim sld As slide
Dim shp As Shape
Dim pptWorkbook As Workbook
Set sld = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Set shp = sld.Shapes.AddChart
Set pptWorkbook = shp.Chart.ChartData.Workbook
pptWorkbook.Close SaveChanges:=True
Set pptWorkbook = shp.Chart.ChartData.Workbook
pptWorkbook.Sheets(1).Cells(1, 2) = "fewewq"
Application.ActivePresentation.Save
pptWorkbook.Close SaveChanges:=True
End Sub
如果您更改 header 行值,您将无法再访问嵌入的 object("Cells(1, 2)"),如果您更改另一个值 ("Cells(2, 1)") 它 运行很好。我假设这是同样的问题,我无法打开此代码后的图表数据 运行。如果我尝试以编程方式访问它,我会收到以下错误:
Run-time error '-2147467259 (80004005)':
Method 'Workbook' of object 'ChartData' failed
虽然只是 2016 年的问题,但我在 2010 年尝试了一些略有不同的方法,但没有发现任何问题。
更新 2
我终于明白为什么我不能在另一个系统上重现这个问题了。仅当 excel 的所有实例在进行更改后关闭时才会出现此问题。这意味着如果您在 运行 这段代码时打开一个单独的(不相关的)excel window,您将看不到问题。
只有当 PowerPoint 单独 运行 并且没有打开任何其他 Excel 电子表格时才能重现此问题。
它适用于以下内容(不添加 Excel 常量的 Excel 参考和实际值,在 Win7x64 上使用 PowerPoint 2010x86):
Option Explicit
Sub test()
Dim sld As Slide
Dim shp As Shape
Set sld = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Set shp = sld.Shapes.AddOLEObject(30, 30, 50, 50, "Excel.Sheet")
Dim listObject As Object ' listObject
Set listObject = shp.OLEFormat.Object.Sheets(1).ListObjects.Add(1) 'xlSrcRange = 1
shp.OLEFormat.Object.Sheets(1).Cells(1, 1) = "fewewq"
shp.OLEFormat.Object.Close
End Sub
只是不确定为什么设置了对象却不使用它们。
我找到了一个真正 "awesome" 的解决方法,至少对于表格而言:
Public Sub CreateTable()
'Create a dummy excel object in the background(run this before working with OLE objects)
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
xlApp.Workbooks.Add
Dim slide As slide: Set slide = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Dim shp As Shape: Set shp = slide.Shapes.AddOLEObject(30, 30, 50, 50, "Excel.Sheet")
shp.OLEFormat.Object.Sheets(1).ListObjects.Add (1) 'xlSrcRange
shp.OLEFormat.Object.Sheets(1).Cells(1, 1) = "fewewq"
shp.OLEFormat.Object.Close
'Kill it when the work is done
xlApp.Application.Quit
End Sub
图表版本:
Public Sub CreateChart()
'Create a dummy excel object in the background(run this before working with OLE objects)
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
xlApp.Workbooks.Add
Dim sld As slide
Dim shp As Shape
Dim pptWorkbook As Workbook
Set sld = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Set shp = sld.Shapes.AddChart
Set pptWorkbook = shp.Chart.ChartData.Workbook
pptWorkbook.Close SaveChanges:=True
'Use the Activate code to open the worksheet, typically only need for 2010
xlApp.Application.Wait Now + TimeValue("0:00:01")
shp.Chart.ChartData.Activate
shp.Chart.ChartData.Workbook.Windows(1).Visible = False
Set pptWorkbook = shp.Chart.ChartData.Workbook
pptWorkbook.Sheets(1).Cells(1, 2) = "fewewq"
Application.ActivePresentation.Save
'Added a wait condition before closing the document, not sure why this works...
Excel.Application.Wait Now + TimeValue("0:00:01")
pptWorkbook.Close SaveChanges:=True
'Kill it when the work is done
xlApp.Application.Quit
End Sub
当然,我对答案并不满意,因为它只是避免了问题,而不是解决根本原因。我仍然想更好地了解导致此行为的原因。如果失败,以真正的 VBA 方式,这可能是唯一可行的选择。
我可以在 Windows10-64/Excel2013-64 上一致地重现您的问题。这是一个错误,我们只能尝试检查到底出了什么问题。
将table的header更改为VBA时,ListColumn
固执地拒绝更新其名称。无论您是更改 header 单元格还是显式更改 ListColumn 的名称,都会发生这种情况!它仅在您编辑工作簿并手动更改单元格时更新,而不是从 VBA:
Public Sub Test()
Dim oslide As Slide
Set oslide = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Dim oshape As Shape
Set oshape = oslide.Shapes.AddOLEObject(30, 30, 250, 250, "Excel.Sheet")
With oshape.OLEFormat.Object
.Sheets(1).ListObjects.Add 1, .Sheets(1).Range("B2:D5") ' <-- put it anywhere
.Sheets(1).ListObjects(1).ListColumns(1).Name = "fewewq" ' <-- whether like this
'.Sheets(1).Range("B2").Value = "fewewq" ' <-- or like this
Debug.Print .Sheets(1).ListObjects(1).ListColumns(1).Range.Cells(1).Value 'fewewq
Debug.Print .Sheets(1).ListObjects(1).ListColumns(1).Name
''''''''''''''' Still prints Column1 ! ''''''''''''''''''
.Close
End With
End Sub
结果很明显:ListObject
table 被损坏,因为它在内部保存了在 [=81= 中找不到的列名(即 Column1
) ](header 是 fewewq
)。这导致了观察到的错误,不幸的是,显示的错误消息并不总是准确的。
当 Excel 实例已经是 运行 时,行为会改变并且 ListColumn
的名称 会 更新。似乎在编辑 header 时更新 table 内部数据的 "component" 在 PowerPoint VBA 中编辑时是 "not loaded"。仅当:
您在PPT中编辑工作簿in-place,手写
您有一个 Excel 实例 运行
共同点是加载了一些编辑器组件,而此编辑器是在编辑 header 时更新内部 table 数据的编辑器。
您在答案中找到的很好的解决方法,即在操作之前打开一个 xlApp,然后在操作之后将其关闭,与这些观察结果一致。
重要的是,Chart
object(在Update 1中)出现的"other"问题确实和你一样正确假设 ("I assume it's the same problem")。创建的图表链接到工作表中的 ListObject
table,并且 table 在第一行有其 header。因此,当您更改 header 中的单元格时,ListColumn
的名称不会更新,从而导致同样的损坏问题。
更新:另一个轻量级解决方法
在评论提出与打开先前 Excel 应用程序的解决方法相关的问题后,我试图找到一个 "lighter" 解决方法并找到了一个。
确信问题是由于未能在 table 中更新 ListColumn
的名称,我找到了 "force it" 更新其名称的方法。解决方法包括两个步骤:
将table的范围向右扩展一列,然后立即将其缩小回原来的范围。
这个操作只是强制 table 到 re-calculate 它的列名,仅此而已!现在 table 的列名是正确的,问题也消失了。
Public Sub Workaround()
Dim oslide As Slide: Set oslide = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Dim oshape As Shape: Set oshape = oslide.Shapes.AddOLEObject(30, 30, 250, 250, "Excel.Sheet")
With oshape.OLEFormat.Object.Sheets(1)
.ListObjects.Add 1 ' xlRange
.Range("A1").Value = "fewewq"
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Expand the table one column to the right than shrink it back
'
With .ListObjects(1)
.Resize .Range.Resize(, .Range.Columns.Count + 1)
.Resize .Range.Resize(, .Range.Columns.Count - 1)
End With
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
End With
With oshape.OLEFormat.Object
Debug.Print .Sheets(1).ListObjects(1).ListColumns(1).Range.Cells(1).Value ' fewewq
Debug.Print .Sheets(1).ListObjects(1).ListColumns(1).Name ' Now prints fewewq !
.Close
End With
End Sub
完成此操作后,您可以验证嵌入的工作表是editable,您可以关闭然后打开演示文稿,不会发现任何问题。我希望这会有所帮助:)
如果你 运行 下面的代码你会得到一个非常有趣的结果(只有 PowerPoint 运行ning,在 运行ning 之前关闭所有 Excel 的实例):
'Optional - Include the "Microsoft Excel 16.0 Object Library"
Option Explicit
Public Sub test()
Dim oslide As slide
Set oslide = ActivePresentation.Slides.add(1, ppLayoutBlank)
Dim oshape As Shape
Set oshape = oslide.Shapes.AddOLEObject(30, 30, 50, 50, "Excel.Sheet")
oshape.OLEFormat.Object.Sheets(1).ListObjects.add(1) 'xlSrcRange
oshape.OLEFormat.Object.Sheets(1).Cells(1, 1) = "fewewq"
oshape.OLEFormat.Object.Close
End Sub
嵌入的 object 已成功创建并且 table 与指定数据一起出现。但是,当您单击嵌入的 object 时,您会收到以下错误:
There isn't enough memory available to read Worksheet.
此 object 无法再以任何其他方式访问,object 的损坏性质在文档 close/open 上持续存在并重新启动。我已验证此问题发生在除我测试过的一个系统之外的所有系统上(PowerPoint/Excel 2016,Windows 7 X64)。
问题
所以我的问题是,任何人都可以重现这个吗?如果可以,为什么会这样?如果将行 "Cells(1, 1)" 更改为 "Cells(2, 1)" 没有问题,似乎编辑 table 的头部会导致某种特殊行为,这与编辑行或其他单元格不同.
研究
关于这个真的没有写过,大部分东西都没有 与此特定问题相关。
This post 声称这是字体太多的问题 安装(> 600)。我测试了这个,我只安装了241...
有 some posts 完全不相关,同样不是 分配到那里去。
我在 MS Word 中测试了相同的代码,似乎工作正常,问题似乎 隔离到 PowerPoint
我试过用代码做一个版本(损坏 object),然后用手做另一个版本(工作 object),保存它们并比较二进制输出(of only the embedded objects). This sounds cool, but it doesn't grant me any greater insight. I can't open with Excel the embedded objects separately as the objects seems to be stored in a proprietary format。二进制的中心区域看起来不同,但我不确定如何或为什么。到目前为止,我还没有发现一种方法可以将其解码为人类可读的信息。
After a significant delay and with proper attribution, I have cross posted this to the Microsoft forums. Maybe someone has some insight over there. I will actively maintain both posts. If I were 100% convinced this was a bug I might even consider opening an issue here.
您可以通过永远不关闭 OLEObject 来完全避免此问题,这会在 2010 年引起问题,尤其是与关联的图表行为结合使用时,您会变得孤立 excel windows 显示。不是很好的用户体验。我想我可以在后台打开一个隐藏的 excel window,然后在我完成嵌入式工作后终止...
我是 运行ning 版本:Microsoft Office 365 ProPlus:版本 1705(内部版本 8201.3103 Click-to-Run),但我也看到了 Microsoft Office Standard 2010 上的问题, 版本 14.0.7015.1000(32 位)。 table 的问题似乎在所有其他版本的 office 上都相同,但我想知道这是否会影响 2010 之前的 office 版本?
更新 1
我用图表尝试了同样的事情:
'Include the "Microsoft Excel 16.0 Object Library"
Option Explicit
Sub test()
Dim sld As slide
Dim shp As Shape
Dim pptWorkbook As Workbook
Set sld = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Set shp = sld.Shapes.AddChart
Set pptWorkbook = shp.Chart.ChartData.Workbook
pptWorkbook.Close SaveChanges:=True
Set pptWorkbook = shp.Chart.ChartData.Workbook
pptWorkbook.Sheets(1).Cells(1, 2) = "fewewq"
Application.ActivePresentation.Save
pptWorkbook.Close SaveChanges:=True
End Sub
如果您更改 header 行值,您将无法再访问嵌入的 object("Cells(1, 2)"),如果您更改另一个值 ("Cells(2, 1)") 它 运行很好。我假设这是同样的问题,我无法打开此代码后的图表数据 运行。如果我尝试以编程方式访问它,我会收到以下错误:
Run-time error '-2147467259 (80004005)':
Method 'Workbook' of object 'ChartData' failed
虽然只是 2016 年的问题,但我在 2010 年尝试了一些略有不同的方法,但没有发现任何问题。
更新 2
我终于明白为什么我不能在另一个系统上重现这个问题了。仅当 excel 的所有实例在进行更改后关闭时才会出现此问题。这意味着如果您在 运行 这段代码时打开一个单独的(不相关的)excel window,您将看不到问题。
只有当 PowerPoint 单独 运行 并且没有打开任何其他 Excel 电子表格时才能重现此问题。
它适用于以下内容(不添加 Excel 常量的 Excel 参考和实际值,在 Win7x64 上使用 PowerPoint 2010x86):
Option Explicit
Sub test()
Dim sld As Slide
Dim shp As Shape
Set sld = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Set shp = sld.Shapes.AddOLEObject(30, 30, 50, 50, "Excel.Sheet")
Dim listObject As Object ' listObject
Set listObject = shp.OLEFormat.Object.Sheets(1).ListObjects.Add(1) 'xlSrcRange = 1
shp.OLEFormat.Object.Sheets(1).Cells(1, 1) = "fewewq"
shp.OLEFormat.Object.Close
End Sub
只是不确定为什么设置了对象却不使用它们。
我找到了一个真正 "awesome" 的解决方法,至少对于表格而言:
Public Sub CreateTable()
'Create a dummy excel object in the background(run this before working with OLE objects)
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
xlApp.Workbooks.Add
Dim slide As slide: Set slide = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Dim shp As Shape: Set shp = slide.Shapes.AddOLEObject(30, 30, 50, 50, "Excel.Sheet")
shp.OLEFormat.Object.Sheets(1).ListObjects.Add (1) 'xlSrcRange
shp.OLEFormat.Object.Sheets(1).Cells(1, 1) = "fewewq"
shp.OLEFormat.Object.Close
'Kill it when the work is done
xlApp.Application.Quit
End Sub
图表版本:
Public Sub CreateChart()
'Create a dummy excel object in the background(run this before working with OLE objects)
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
xlApp.Workbooks.Add
Dim sld As slide
Dim shp As Shape
Dim pptWorkbook As Workbook
Set sld = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Set shp = sld.Shapes.AddChart
Set pptWorkbook = shp.Chart.ChartData.Workbook
pptWorkbook.Close SaveChanges:=True
'Use the Activate code to open the worksheet, typically only need for 2010
xlApp.Application.Wait Now + TimeValue("0:00:01")
shp.Chart.ChartData.Activate
shp.Chart.ChartData.Workbook.Windows(1).Visible = False
Set pptWorkbook = shp.Chart.ChartData.Workbook
pptWorkbook.Sheets(1).Cells(1, 2) = "fewewq"
Application.ActivePresentation.Save
'Added a wait condition before closing the document, not sure why this works...
Excel.Application.Wait Now + TimeValue("0:00:01")
pptWorkbook.Close SaveChanges:=True
'Kill it when the work is done
xlApp.Application.Quit
End Sub
当然,我对答案并不满意,因为它只是避免了问题,而不是解决根本原因。我仍然想更好地了解导致此行为的原因。如果失败,以真正的 VBA 方式,这可能是唯一可行的选择。
我可以在 Windows10-64/Excel2013-64 上一致地重现您的问题。这是一个错误,我们只能尝试检查到底出了什么问题。
将table的header更改为VBA时,ListColumn
固执地拒绝更新其名称。无论您是更改 header 单元格还是显式更改 ListColumn 的名称,都会发生这种情况!它仅在您编辑工作簿并手动更改单元格时更新,而不是从 VBA:
Public Sub Test()
Dim oslide As Slide
Set oslide = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Dim oshape As Shape
Set oshape = oslide.Shapes.AddOLEObject(30, 30, 250, 250, "Excel.Sheet")
With oshape.OLEFormat.Object
.Sheets(1).ListObjects.Add 1, .Sheets(1).Range("B2:D5") ' <-- put it anywhere
.Sheets(1).ListObjects(1).ListColumns(1).Name = "fewewq" ' <-- whether like this
'.Sheets(1).Range("B2").Value = "fewewq" ' <-- or like this
Debug.Print .Sheets(1).ListObjects(1).ListColumns(1).Range.Cells(1).Value 'fewewq
Debug.Print .Sheets(1).ListObjects(1).ListColumns(1).Name
''''''''''''''' Still prints Column1 ! ''''''''''''''''''
.Close
End With
End Sub
结果很明显:ListObject
table 被损坏,因为它在内部保存了在 [=81= 中找不到的列名(即 Column1
) ](header 是 fewewq
)。这导致了观察到的错误,不幸的是,显示的错误消息并不总是准确的。
当 Excel 实例已经是 运行 时,行为会改变并且 ListColumn
的名称 会 更新。似乎在编辑 header 时更新 table 内部数据的 "component" 在 PowerPoint VBA 中编辑时是 "not loaded"。仅当:
您在PPT中编辑工作簿in-place,手写
您有一个 Excel 实例 运行
共同点是加载了一些编辑器组件,而此编辑器是在编辑 header 时更新内部 table 数据的编辑器。
您在答案中找到的很好的解决方法,即在操作之前打开一个 xlApp,然后在操作之后将其关闭,与这些观察结果一致。
重要的是,Chart
object(在Update 1中)出现的"other"问题确实和你一样正确假设 ("I assume it's the same problem")。创建的图表链接到工作表中的 ListObject
table,并且 table 在第一行有其 header。因此,当您更改 header 中的单元格时,ListColumn
的名称不会更新,从而导致同样的损坏问题。
更新:另一个轻量级解决方法
在评论提出与打开先前 Excel 应用程序的解决方法相关的问题后,我试图找到一个 "lighter" 解决方法并找到了一个。
确信问题是由于未能在 table 中更新 ListColumn
的名称,我找到了 "force it" 更新其名称的方法。解决方法包括两个步骤:
将table的范围向右扩展一列,然后立即将其缩小回原来的范围。
这个操作只是强制 table 到 re-calculate 它的列名,仅此而已!现在 table 的列名是正确的,问题也消失了。
Public Sub Workaround()
Dim oslide As Slide: Set oslide = ActivePresentation.Slides.Add(1, ppLayoutBlank)
Dim oshape As Shape: Set oshape = oslide.Shapes.AddOLEObject(30, 30, 250, 250, "Excel.Sheet")
With oshape.OLEFormat.Object.Sheets(1)
.ListObjects.Add 1 ' xlRange
.Range("A1").Value = "fewewq"
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Expand the table one column to the right than shrink it back
'
With .ListObjects(1)
.Resize .Range.Resize(, .Range.Columns.Count + 1)
.Resize .Range.Resize(, .Range.Columns.Count - 1)
End With
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
End With
With oshape.OLEFormat.Object
Debug.Print .Sheets(1).ListObjects(1).ListColumns(1).Range.Cells(1).Value ' fewewq
Debug.Print .Sheets(1).ListObjects(1).ListColumns(1).Name ' Now prints fewewq !
.Close
End With
End Sub
完成此操作后,您可以验证嵌入的工作表是editable,您可以关闭然后打开演示文稿,不会发现任何问题。我希望这会有所帮助:)