【问题标题】:How can I identify the document that contains an embedded chart?如何识别包含嵌入图表的文档?
【发布时间】:2013-06-07 21:12:18
【问题描述】:

我有一个适用于活动工作簿的 Excel 的 COM 加载项,虽然它大部分都可以工作,但我在一个特定的场景中遇到了问题。

如果我在使用插入->图表创建的 Word 2010 文档中有一个图表,那么当我单击图表工具->设计->编辑数据时,它会打开包含图表数据的工作簿。我的外接程序可以(大部分)使用该工作簿。

但是,我的加载项需要知道保存工作簿的文件夹,在这种情况下,我想使用 包含文档的文件夹(Word 文档或 PowerPoint演示文稿)已保存。但是,我找不到任何方法来获取有关容器文档的任何信息 - 事实上,我什至找不到方法来告诉我正在处理的工作簿 嵌入在文档中。

是否有任何方法可以让我访问容器文档?

【问题讨论】:

  • 我不确定这是否是您要查找的内容,但是...要检查是否嵌入了 Workbook(数据),您可以通过以下方式进行检查:ActiveDocument.InlineShapes(1).Chart.ChartData.IsLinked 将返回 @ 987654323@ 如果工作簿是嵌入的,true 如果它没有嵌入但链接...如果它链接到其他 Excel 文件,您可以通过这种方式检查文件路径:ActiveDocument.InlineShapes(1).Chart.ChartData.Workbook.Path
  • @KazJaw:抱歉,但“ActiveDocument”只有在我以编程方式访问容器文档时才有效。这就是问题的重点。因为我的加载项是 Excel 加载项,所以它只能“看到”工作簿。我真正希望的是像“ThisWorkbook.ContainerDocument”这样的东西,但据我所知,没有这样的东西。
  • 您是否尝试识别包含图表的Word 文档?或者,正如我到目前为止所假设的那样,嵌入式ChartData 的路径(不存在)?
  • 我正在尝试识别容器文档,是的。
  • 好的。因此,由于“大部分”中的宏/添加适用于 ChartData 工作簿,您是如何做到的?如果您没有使用加载项打开 Word 文件并激活 ChartData 我猜您手动执行这些操作(打开 Word 文件,并激活图表数据,它会在 Excel 中显示它,然后您可以在其中运行您的ChartData 上的加载项/宏)。对吗?

标签: vba vsto office-2007 office-2010 office-2013


【解决方案1】:

我很确定通过Insert | Chart 功能区创建的图表不是链接文档,因此它没有.Path 属性。您应该不需要路径,您可以直接访问工作簿和图表对象:

要访问ChartData 工作簿/工作表对象,您可以执行以下操作:

Sub OpenChartData(shp as InlineShape)


Dim shp As InlineShape
Dim cht As Chart
Dim wb As ChartData

    If shp.Type = wdInlineShapeChart Then
        Set wb = shp.Chart.ChartData
        Set cht = shp.Chart  '## In case you need to manipulate the Chart options like Title, Axes, etc... you can use this variable.
        wb.Activate  '## Activate the chart's ChartData sheet

        ' do stuff to the worksheet

        wb.Workbook.Application.WindowState = -4140  '## Hide the ChartData when you're finished.
    End If

End Sub

评论更新:

图表数据是或者链接的工作簿,或者不是。如果它不是链接的工作簿,那么它作为具有完整路径的“已保存”文件等不存在于某处。

回答您的问题:

Are there any methods that would give me access to the container document?

您可以通过ChartData 对象访问容器文档。

但是,您不想使用此对象,因为您坚持或错误地理解该工作簿被“保存”在某处,而这仅仅是识别此工作簿保存在 何处 的问题,以便您的宏/加载项无需任何修改即可工作。

你的假设是错误的。工作簿没有保存在某个地方,它完全封装在 ChartData 对象中,它是 Microsoft Word 对象模型的一部分。

来自 MSDN

新对象 ChartData 已添加到 VBA 对象模型中,用于 Word 提供对基础链接或嵌入数据的访问 图表。每个图表都有与之相关联的用于绘制图表的数据 Word 中的图表。图表数据可以从外部链接 Excel 工作簿,或作为图表本身的一部分嵌入。图表数据 对象封装了对 Word 中给定图表数据的访问。为了 例如,下面的 VBA 代码示例显示,然后最小化, Word 中活动文档所包含的每个图表的图表数据。

http://msdn.microsoft.com/en-us/library/office/ff821389.aspx

所以,你的选择是:

  1. 重新设计宏以与ChartData 对象兼容,或者
  2. 在 Excel 中创建图表并作为 OLEObjects 插入/粘贴到 DOC,而不是使用 Word 的 Insert | Chart
  3. 尝试将以前使用 Word Insert | Chart 创建的所有图表转换为 OLEObjects。

进一步阅读:

Update Chart Data

Creating Charts with VBA

【讨论】:

  • 它不是链接 Excel 文档,但是当您编辑数据时,它确实会在Excel 中打开;我很确定它一个成熟的 Excel 工作簿。 (相比之下,该图表不是 Excel 图表)。该工作簿确实有一个 Path 属性 - 它只是空白,与尚未保存的工作簿大致相同。无论如何,按照上面的示例从文档中访问图表对我的情况没有帮助,因为我的 Excel 加载项对文档一无所知 - 它只能看到工作簿。这是我问题的症结所在。
  • 你是什么意思“它只能看到工作簿”?如果您可以看到工作簿,那么您可以使用所有标准 Excel 对象模型来操作该工作簿中的数据。我想也许可以澄清您的问题:您要对工作簿做什么,而您的宏无法做到这一点?如果您可以发布您的宏代码,或许我们可以找出为什么它不起作用,并提出解决方法。
  • 来自我的问题:“我的加载项需要知道保存工作簿的文件夹,在这种情况下,我想使用保存文档的文件夹”。我不愿意找到一种方法来重写我的加载项以删除此要求,因此我不想分心问题的重点。假设为了争论,它只需要在某个地方记录文件夹(它不需要,但据我所知,这没有区别)。
  • 问题在于,从您的插件当前需要的意义上说,此文档并未“保存”。 ChartData 工作表被压缩为打开的 xml DOCX/DOCM 文件格式的一部分,并且是 Word 文档的一部分,而不是“链接”到您的 DOC 文件的某些外部 Excel 文件。我相当肯定,如果不对您的加载项进行一些修改,则无法解决此问题,A) 修改加载项以使其识别 ChartData 工作簿,或 B ) 将所有图表转换为带有外部链接 XLSX 数据的 OLEObjects 的更糟糕的命题。祝你好运。
  • 查看修订以获取更多详细信息。 ]
【解决方案2】:

让我们再试一次......

然后创建另一个加载项(我将给出一个 XLAM 的示例),或者您可以将您的 COM 加载项修改为此,或者确保这个新加载项正在运行。此插件将捕获应用程序级 App_WorkbookActivate 事件,并检查新工作簿名称是否可能来自 Microsoft Word。

如果工作簿符合此条件,因为它正在触发 App_WorkbookActivate 事件,那么假设 MS Word 中的当前 ActiveDocument 是容器似乎相当安全。

然后,我们只需设置一些对象变量来捕获Word.Application,然后只需获取ActiveDocument,它是.Path,它是.Name,我们可以将这些值存储在命名变量中Excel 工作簿。

您可以在Names 管理器中查看它们,或者通过引用它们的名称.Names("docPath").Names("docName") 以编程方式访问它们。

将其放入 XLAM 文件中的标准模块中:

Sub Auto_Open()
    Application.Run "ThisWorkbook.Workbook_Open" 'just in case
End Sub

以下代码位于 XLAM 文件的 ThisWorkbook 模块中:

Option Explicit
Private WithEvents App As Application
Dim dictWorkbooks As Object
Private Sub Workbook_Open()
    '## Instantiate the public variables for this Add-in:
    Set App = Application
    Set dictWorkbooks = CreateObject("Scripting.Dictionary")
End Sub

Private Sub App_WorkbookActivate(ByVal Wb As Workbook)
    '## Attempt to determine if a Workbook is opened from MS Word,
    '   and if so, store the container document's path & name in
    '   named variable/range in the Workbook.
    Dim wdApp As Object
    Dim wdDoc As Object
    Dim docPath As String
    Dim docName As String
    Dim w As Integer

    If Wb.Name Like "Chart in Microsoft Word" Then
        'Get out of here if we already have this workbook activated.
        If dictWorkbooks.Exists(Wb.Name) Then Exit Sub
        Set wdApp = GetObject(, "Word.Application")
        Set wdDoc = wdApp.ActiveDocument
        docPath = wdDoc.Path
        docName = wdDoc.Name
        dictWorkbooks.Add Wb.Name, docName

        With Wb
            On Error Resume Next
            .Names("docPath").Delete
            .Names("docName").Delete
            On Error GoTo 0
            .Names.Add Name:="docPath", RefersToR1C1:=docPath
            .Names("docPath").Comment = "A variable stores the parent DOC file's path"
            .Names.Add Name:="docName", RefersToR1C1:=docName
            .Names("docName").Comment = "A variable stores the parent DOC file's name"
        End With
    End If

End Sub
Private Sub App_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)
    '## If you open multiple charts from the word document, without closing the Workbook
    ' they will be assigned unique names. However, if you open & close multiple Workbook
    ' they will all have the same name "Chart in Microsoft Word".  This method will
    ' remove an existing Key from our Dictionary when a workbook is closed, in order to
    ' prevent false matches.
    If dictWorkbooks.Exists(Wb.Name) Then _
        dictWorkbooks.Remove Wb.Name
End Sub

【讨论】:

  • 谢谢,是的 - 使用 GetObject(或等效项),然后使用 ActiveDocument(或 ActivePresentation)是我保留的丑陋后备。
  • 没问题。我很确定我不遗余力,但就是想不出任何办法——本机——来获取你想要获取的信息。这似乎是一个非常安全的黑客攻击。我的猜测是,“其他应用程序中的图表”根本没有设计为与独立 Excel 工作簿中的图表相同的方式使用,所以这是一个差异。似乎是一个奇怪的疏忽,但众所周知,MS 又一次将 实际用户 排除在他们的开发讨论之外....如果您确实想出了其他方法,很想知道它.干杯。
  • 嗯,实际上,我的计划是从ActiveDocument 开始,遍历文档中的所有图表,然后检查ChartData 属性。我可以忽略IsLinked 为假的那些。那我看看ChartData.Workbook属性;如果未激活图表数据,则会引发错误。如果没有错误,那么我可以测试 ChartData.Workbook.Name 并将其与实际工作簿名称相匹配 - 这将是“...中的图表 2”等。(如果我在活动文档中找不到它,我可以尝试其他文件)。我认为这样更安全,并且无需维护“状态”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-15
  • 1970-01-01
  • 2019-11-27
  • 2017-03-17
  • 1970-01-01
  • 2018-10-26
相关资源
最近更新 更多