【问题标题】:Excel VBA advanced diagram manipulationExcel VBA 高级图表操作
【发布时间】:2013-12-02 14:14:28
【问题描述】:

我遇到了一个关于使用 VBA 在 Excel 中高级操作图表的非常具体的问题。

我想根据这个截图尝试解释一下。

根据我的理解以及经过数小时的文献和网络研究,无法在绘图中产生可比较且恒定的结果,因为有几个属性您无法操作,并且某些命令未正确执行。我使用 VBA 将两个图表的绘图区域的宽度设置为 700(手动生成图表后):

ActiveChart.PlotArea.Width = 700

之后,一个宽度是 698.12,一个是 712.34(比较绘图区域的右端)。 此外,根据 y 轴刻度的最大值(80 对 100),绘图区域的左边界是可变的。这些问题的结果是绘图区域不一致。

为什么这对我来说如此重要? 好吧,假设您有一个用于项目预测等的 excel 计算工具。这被多个部门使用。 G。您公司中的人员,因此应该始终看起来相同并且具有可比性。这些预测的一部分是容量规划,应该在图表中可视化。因为这些项目有不同的里程碑 e. G。不同的项目阶段,这些图表应显示代表这些阶段的条形图。 使用辅助轴将不起作用,因为无法将其与主轴同步以使其看起来不错。总有一个偏移量。 所以计划是在这些图表中/上绘制形状。为此,据我了解,我需要绘图区域和列等的确切位置来计算这些条形和其他形状的相对位置。

我希望我的解释足以让您了解我的目标。所以我会回答我的问题:

为什么 Excel 在每种情况下都以不同的方式解释我的命令(绘图区域宽度)? 是否有可能确定地修复/定义绘图区域? 是否有比 msdn 和迄今为止我发现的所有其他来源中记录的更多可操作对象/属性?我如何获得这些?

期待您的回复。

编辑:

根据 RBarryYoung 的要求,我编写了一些代码,以便您可以重现该问题。当然,这次没有出现右边框不同的问题。但至少 y 轴的宽度以及绘图区域的可变宽度(例如绘图区域左边框的可变位置)的问题是可重现的。如果你自己画一些线,你会看到左边框和列本身是偏移的。

Sub DrawChart()

Dim wkb As Workbook
Dim wks As Worksheet
Dim chart1 As Chart
Dim chart2 As Chart
Dim table1 As ListObject
Dim table2 As ListObject
Dim r1 As Range
Dim r2 As Range

Set wkb = ThisWorkbook
Set wks = wkb.Sheets(1)

With wks

    .Cells(1, 1).Value = "Date"
    .Range(.Cells(1, 2), .Cells(1, 10)).Formula = "=today()+column()"
    .Cells(2, 1).Value = "Budget"
    .Range(.Cells(2, 2), .Cells(2, 10)).Formula = "=5*column()"

    .Cells(4, 1).Value = "Date"
    .Range(.Cells(4, 2), .Cells(4, 10)).Formula = "=today()+column()"
    .Cells(5, 1).Value = "Budget"
    .Range(.Cells(5, 2), .Cells(5, 10)).Formula = "=20*column()"


    Set table1 = .ListObjects.Add(SourceType:=xlSrcRange, Source:=Range(Cells(1, 1), Cells(2, 10)), xllistobjecthasheaders:=xlYes)
    table1.Name = "table1"
    Set table2 = .ListObjects.Add(SourceType:=xlSrcRange, Source:=Range(Cells(4, 1), Cells(5, 10)), xllistobjecthasheaders:=xlYes)
    table2.Name = "table2"

Set r1 = Range(.Cells(7, 2), .Cells(17, 15))
Set r2 = Range(.Cells(34, 2), .Cells(44, 15))

Set chart1 = .ChartObjects.Add(r1.Left, r1.Top, r1.Width, r1.Height).Chart

With chart1
    .ChartType = xlColumnStacked
    .SetSourceData Source:=Range("table1[#All]"), PlotBy:=xlRows
    .HasLegend = False
    .ChartArea.Height = 320
    .ChartArea.Width = 620
    .PlotArea.Height = 300
    .PlotArea.Width = 600
End With

Set chart2 = .ChartObjects.Add(r2.Left, r2.Top, r2.Width, r2.Height).Chart

With chart2
    .ChartType = xlColumnStacked
    .SetSourceData Source:=Range("table2[#All]"), PlotBy:=xlRows
    .HasLegend = False
    .ChartArea.Height = 320
    .ChartArea.Width = 620
    .PlotArea.Height = 300
    .PlotArea.Width = 600
End With

End With

End Sub

【问题讨论】:

  • 仅供参考:如果您可以发布图片链接,我们可以为您将其添加到您的帖子中。
  • 你能给我们一个方法来为我们自己复制这个吗?这将使弄清楚可能发生的事情变得容易得多。
  • 我可以上传excel宏文件吗?
  • 否,但您可以将源代码剪切并粘贴到您的问题中,然后使用编辑按钮(“{ }”)将其格式化为代码。

标签: vba excel diagrams


【解决方案1】:

如果我的理解正确,您想构建如下所示的同步图表:

基于散点折线图类型的同步图表是使用 OpenXML SDK 和 C++/CLI 生成的。但是你的情况应该是一样的。

此外,根据y轴刻度的最大值(80 vs. 100),绘图区域的左边框是可变的。

PloatArea 边距由 Excel 控制。因此,在绘图上分配了足够的空间来放置值轴的刻度标签,因为 PlotArea 会自动更改大小,尽管给定宽度或高度,如您所见。在此之前,相同的最小/最大值、相对轴位置和刻度位置已在每个图表上同步。标题和图例被禁用以防止意外对齐,如您的代码示例。

为了在 VBA 中同步 PlotArea 的水平放置,请使用 InsideLeft 和 InsideWidth 属性,如下所示:

Sub test_synch()
  With ActiveSheet
    synch_plot_areas .ChartObjects(1), .ChartObjects(2)
  End With
End Sub

Sub synch_plot_areas(ByVal ch1 As ChartObject, ByVal ch2 As ChartObject)
  Dim v_min As Double, v_max As Double, v_delta As Double

  'Align left
  v_min = ch1.Left: If v_min > ch2.Left Then v_min = ch2.Left
  ch1.Left = v_min: ch2.Left = v_min

  'Synchronization of external chart object width
  v_min = ch1.Width: If v_min > ch2.Width Then v_min = ch2.Width
  ch1.Width = v_min: ch2.Width = v_min

  'Margins is controlled by Excel
  'Hence .InsideWidth is sychnronized first to minimum to prevent PlotArea's constraints on margins and placement
  v_min = ch1.Chart.PlotArea.InsideWidth: If v_min > ch2.Chart.PlotArea.Width Then v_min = ch2.Chart.PlotArea.InsideWidth
  With ch1.Chart.PlotArea
    v_delta = .InsideWidth - v_min
    .Width = .Width - v_delta
  End With
  With ch2.Chart.PlotArea
    v_delta = .InsideWidth - v_min
    .Width = .Width - v_delta
  End With

  '.Left is sychnronized second by maximum margin: now there is enough space for Value axis on both charts
  v_max = ch1.Chart.PlotArea.InsideLeft: If v_max < ch2.Chart.PlotArea.InsideLeft Then v_max = ch2.Chart.PlotArea.InsideLeft
  With ch1.Chart.PlotArea
    v_delta = v_max - .InsideLeft
    .Left = .Left + v_delta
  End With
  With ch2.Chart.PlotArea
    v_delta = v_max - .InsideLeft
    .Left = .Left + v_delta
  End With

End Sub

在 PlotArea 同步之前:

使用 test_synch 宏同步 PlotArea 后:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-27
    • 2010-11-18
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 1970-01-01
    相关资源
    最近更新 更多