更改图表的属性会在更改其位置后中断

时间:2011-10-27 01:03:47

标签: ruby excel vba win32ole

在下面的代码中,可以自行更改图表标题或其位置,但更改其位置后更改其标题不起作用,如标准错误记录所示。

根据What is error code 0x800A01A8 coming out of Excel ActiveX call?,0x800a01a8表示“需要对象。”,但我认为#{chart.ole_obj_help.name}表示对象存在。

出了什么问题?

代码后面是日志记录。

require "win32ole"

class ExcelOutputter
  def initialize(workbook_filename)
    @workbook_filename = workbook_filename
    # Create an instance of the Excel application object
    @excel = WIN32OLE.new('Excel.Application')
    # Make Excel visible
    @excel.Visible = 1
    # Add a new Workbook object
    @workbook = @excel.Workbooks.Add
  end

  def create_chart(title)
    # http://rubyonwindows.blogspot.com/2008/06/automating-excel-creating-charts.html
    chart = @workbook.Charts.Add
    # Select a worksheet for source data
    worksheet = @workbook.Worksheets("Sheet1")
    # Excel insists on having source data, even if it's empty. Picky, isn't it?
    chart.SetSourceData('Source' => worksheet.Range("$A$1:$B$6"))
    chart.HasTitle = true
    STDERR.puts "#{__method__}: Before renaming the freshly created #{chart.ole_obj_help.name}, the title is #{chart.ChartTitle.Characters.Text.inspect}"
    chart.ChartTitle.Characters.Text = title
    STDERR.puts "#{__method__}: The chart has been created, and is still a #{chart.ole_obj_help.name} and now has a title of #{chart.ChartTitle.Characters.Text.inspect}"
    chart
  end

  def change_chart_title(chart, new_title)
    STDERR.puts "#{__method__}: Apparently the chart object is still a #{chart.ole_obj_help.name}"
    old_title = chart.ChartTitle.Characters.Text
    chart.ChartTitle.Characters.Text = new_title
    STDERR.puts "#{__method__}: The chart object is still a #{chart.ole_obj_help.name} and has been renamed from #{old_title.inspect} to #{chart.ChartTitle.Characters.Text.inspect}"
  end

  def move_chart(chart, target_worksheet_name)
    xlLocationAsObject = 2
    chart.Location("Where" => xlLocationAsObject, "Name" => target_worksheet_name)
    STDERR.puts "#{__method__}: The chart object is still a #{chart.ole_obj_help.name} and has been moved to #{target_worksheet_name.inspect}"
  end

  def write_to_file
    # Save the workbook
    @workbook.SaveAs(@workbook_filename)
    # Close the workbook
    @workbook.Close
    # Quit Excel
    @excel.Quit
  end

  def self.show_everything_works_if_you_do_not_change_a_moved_chart
    STDERR.puts "#{__method__}: Starting"
    excel_outputter = ExcelOutputter.new("chart_location_confusion.xlsx")
    chart = excel_outputter.create_chart("If you saw this it would mean change_chart_title never worked")
    excel_outputter.change_chart_title(chart, "Show that change_chart_title works")
    excel_outputter.move_chart(chart,  "Sheet2")
    # Don't change the chart title after changing its location
    # excel_outputter.change_chart_title(chart, "If you saw this it would mean change_chart_title works after you called move_chart")

    another_chart = excel_outputter.create_chart("If you saw this it would mean change_chart_title never worked")
    excel_outputter.change_chart_title(another_chart, "Check that change_chart_title or move_chart isn't broken permanently")
    excel_outputter.move_chart(another_chart, "Sheet3")
    excel_outputter.write_to_file
    STDERR.puts "#{__method__}: Finishing"
    STDERR.puts("\n\n")
  end

  def self.try_renaming_after_moving_the_same_chart
    STDERR.puts "#{__method__}: Starting"
    excel_outputter = ExcelOutputter.new("chart_location_confusion.xlsx")
    chart = excel_outputter.create_chart("If you saw this it would mean change_chart_title never worked")
    excel_outputter.change_chart_title(chart, "change_chart_title works before you call move_chart")
    excel_outputter.move_chart(chart,  "Sheet2")
    begin
      # This will raise an exception
      excel_outputter.change_chart_title(chart, "Will not get here")
    rescue
      STDERR.puts "#{__method__}: It didn't work"
      raise
    else
      STDERR.puts "#{__method__}: It worked after all!"
    end
  end
end

if __FILE__ == $0
  ExcelOutputter.show_everything_works_if_you_do_not_change_a_moved_chart
  ExcelOutputter.try_renaming_after_moving_the_same_chart
end

产生

show_everything_works_if_you_do_not_change_a_moved_chart: Starting
create_chart: Before renaming the freshly created _Chart, the title is ""
create_chart: The chart has been created, and is still a _Chart and now has a title of "If you saw this it would mean change_chart_title never worked"
change_chart_title: Apparently the chart object is still a _Chart
change_chart_title: The chart object is still a _Chart and has been renamed from "If you saw this it would mean change_chart_title never worked" to "Show that change_chart_title works"
move_chart: The chart object is still a _Chart and has been moved to "Sheet2"
create_chart: Before renaming the freshly created _Chart, the title is ""
create_chart: The chart has been created, and is still a _Chart and now has a title of "If you saw this it would mean change_chart_title never worked"
change_chart_title: Apparently the chart object is still a _Chart
change_chart_title: The chart object is still a _Chart and has been renamed from "If you saw this it would mean change_chart_title never worked" to "Check that change_chart_title or move_chart isn't broken permanently"
move_chart: The chart object is still a _Chart and has been moved to "Sheet3"
show_everything_works_if_you_do_not_change_a_moved_chart: Finishing


try_renaming_after_moving_the_same_chart: Starting
create_chart: Before renaming the freshly created _Chart, the title is ""
create_chart: The chart has been created, and is still a _Chart and now has a title of "If you saw this it would mean change_chart_title never worked"
change_chart_title: Apparently the chart object is still a _Chart
change_chart_title: The chart object is still a _Chart and has been renamed from "If you saw this it would mean change_chart_title never worked" to "change_chart_title works before you call move_chart"
move_chart: The chart object is still a _Chart and has been moved to "Sheet2"
change_chart_title: Apparently the chart object is still a _Chart
try_renaming_after_moving_the_same_chart: It didn't work
chart_location_confusion_replication.rb:30:in `method_missing': ChartTitle (WIN32OLERuntimeError)
    OLE error code:0 in <Unknown>
      <No Description>
    HRESULT error code:0x800a01a8

        from chart_location_confusion_replication.rb:30:in `change_chart_title'
        from chart_location_confusion_replication.rb:75:in `try_renaming_after_moving_the_same_chart'
        from chart_location_confusion_replication.rb:87

修改:如果我将图表创建更改为以下内容:

  def create_chart(title)
    # Select a worksheet for source data
    worksheet = @workbook.Worksheets("Sheet1")
    # http://rubyonwindows.blogspot.com/2008/06/automating-excel-creating-charts.html
    chart = worksheet.Shapes.AddChart.Chart
    # Excel insists on having source data, even if it's empty. Picky, isn't it?
    chart.SetSourceData('Source' => worksheet.Range("$A$1:$B$6"))
    chart.HasTitle = true
    STDERR.puts "#{__method__}: Before renaming the freshly created #{chart.ole_obj_help.name}, the title is #{chart.ChartTitle.Characters.Text.inspect}"
    chart.ChartTitle.Characters.Text = title
    STDERR.puts "#{__method__}: The chart has been created, and is still a #{chart.ole_obj_help.name} and now has a title of #{chart.ChartTitle.Characters.Text.inspect}"
    chart
  end

并将excel_outputter.write_to_file添加到try_renaming_after_moving_the_same_chart的末尾并关闭show_everything_works_if_you_do_not_change_a_moved_chart,然后我

try_renaming_after_moving_the_same_chart: Starting
create_chart: Before renaming the freshly created _Chart, the title is ""
create_chart: The chart has been created, and is still a _Chart and now has a title of "If you saw this it would mean change_chart_title never worked"
change_chart_title: Apparently the chart object is still a _Chart
change_chart_title: The chart object is still a _Chart and has been renamed from "If you saw this it would mean change_chart_title never worked" to "change_chart_title works before you call move_chart"
move_chart: The chart object is still a _Chart and has been moved to "Sheet2"
change_chart_title: Apparently the chart object is still a _Chart
change_chart_title: The chart object is still a _Chart and has been renamed from "change_chart_title works before you call move_chart" to "Will not get here"
try_renaming_after_moving_the_same_chart: It worked after all!

但是当我在Excel中查看时,图表的标题为change_chart_title works before you call move_chart,而不是Will not get here。但是,以下VBA有效:

Sub Tester3()
    Dim cht As Object

    Debug.Print "Start"
    Set cht = Sheet2.Shapes.AddChart.Chart
    Debug.Print TypeName(cht)       'Chart
    cht.SetSourceData Sheet1.Range("B4:C15")
    Debug.Print TypeName(cht)       'Chart
    cht.ChartTitle.Characters.Text = "Second title"
    cht.Location Where:=xlLocationAsObject, Name:="Sheet2"
    cht.ChartTitle.Characters.Text = "Third title"
    Debug.Print TypeName(cht)       'Chart
    Debug.Print cht.Name            'Sheet2 Chart 7
End Sub

1 个答案:

答案 0 :(得分:1)

如果我没记错的话,工作表中嵌入的图表和图表之间存在一些差异。这些差异可能会破坏您的“图表”参考,使其在移动后不再指向“相同”对象。一点VBA显示同样的事情:

Sub Tester()

    Dim cht As Object

    Set cht = ThisWorkbook.Charts.Add()
    cht.SetSourceData Sheet1.Range("B4:C15")
    Debug.Print TypeName(cht)       'Chart
    cht.Location Where:=xlLocationAsObject, Name:="Sheet1"
    Debug.Print TypeName(cht)       'Object
    Debug.Print cht.Name            'Error: object required
End Sub

编辑:将嵌入图表移动到另一张图表也不起作用:

Sub Tester2()

    Dim cht As Object

    Set cht = Sheet1.Shapes.AddChart.Chart
    cht.SetSourceData Sheet1.Range("B4:C15")
    Debug.Print TypeName(cht)       'Chart

    cht.Location Where:=xlLocationAsObject, Name:="Sheet2"
    Debug.Print TypeName(cht)  'Chart
    Debug.Print cht.Name       'Error: Method 'Name' of object _chart failed

End Sub

是否有某些原因需要将图表创建为图表而不直接在工作表上创建?