簡體   English   中英

Excel VBA高級圖操作

[英]Excel VBA advanced diagram manipulation

關於使用VBA在Excel中進行圖表的高級操作,我遇到了一個非常具體的問題。

我想嘗試根據此屏幕截圖對其進行解釋。

我的圖

根據我的理解以及經過數小時的文獻和網絡研究之后,無法在繪圖圖中產生可比較且恆定的結果,因為有些屬性您無法操作,某些命令無法正確執行。 我使用VBA將兩個圖表的繪圖區域的寬度設置為700(在手動生成圖表之后):

ActiveChart.PlotArea.Width = 700

之后,一個寬度為698.12,一個寬度為712.34(比較繪圖區域的右端)。 此外,基於y軸比例的最大值(80對100),繪圖區域的左邊界是可變的。 這些問題的結果是繪圖區域不一致。

為什么這對我如此重要? 好吧,假設您有一個用於項目預測等的excel計算工具。該工具已被多個部門(例如公司中的人員)使用,因此應該始終看起來相同且具有可比性。 這些預測的一部分是容量規划,應該在圖表中進行可視化。 由於此類項目具有不同的里程碑,例如不同的項目階段,因此這些圖應顯示代表這些階段的條形圖。 使用輔助軸將不起作用,因為無法將其與主軸同步以使其看起來不錯。 總會有一個偏移量。 因此,計划是在這些圖中繪制形狀。 以我的理解,要做到這一點,我需要繪制區域和列的確切位置等,以計算這些條形圖和其他形狀的相對位置。

我希望我的解釋足以使您了解我要做什么。 因此,我將回答我的問題:

為什么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

如果我理解正確,那么您想構建如下的同步圖表: 同步散點圖

使用具有C ++ / CLI的OpenXML SDK生成了基於散點圖的同步圖表。 但是針對您的案例的方法應該相同。

此外,基於y軸比例的最大值(80對100),繪圖區域的左邊界是可變的。

PloatArea邊距由Excel控制。 因此,如您所見,由於給定了寬度或高度,由於PlotArea會自動更改大小,因此在圖上分配了足夠的空間來放置Value軸的刻度標簽。 在此之前,相同的最小/最大值,相對軸位置和刻度位置已在每個圖表上同步。 標題和圖例被禁用,以防止意外對齊,如您的代碼示例中所示。

為了在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同步之前: synch_PlotArea_before

在使用test_synch宏進行PlotArea同步之后: synch_PlotArea_after

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM