使用win32com / python重新计算使用加载项的Excel工作表

时间:2018-07-12 06:32:18

标签: win32com

问题描述:我一直在手动使用与excel加载项配合使用的电子表格。我正在尝试使用win32com和python使其自动化。我可以将值输入到输入单元格中,但是工作表不会重新计算。当我尝试读取输出单元格时,出现如下所述的错误。另外,在运行下面的代码之后,当我手动打开工作表时,我看到计算出的单元格都说#VALUE!。手动,我可以按CTRL + ALT + F9,然后重新计算工作表,不留下#VALUE!细胞。请注意,当我说“计算单元格”时,这些单元格依赖于VBA宏/外接程序一部分的功能。

主要问题:如何从python强制重新计算工作表?

代码:

import win32com.client
import win32api

def open_util():
    excel = win32com.client.Dispatch("Excel.Application")
    wb1 = excel.Workbooks.Open(r'C:\...the add-in.xla') 
    wb = excel.Workbooks.Open(r'C:\...the file name.xlsm')
    ws = wb.Worksheets('the sheet name')

    # get the values from two cells.
    myInput = ws.Cells(1,1).Value # this is an input cell, not calculated
    myOutput = ws.Cells(1,2).Value # this cell is calculated
    print("The original value of myOutput is : ", myOutput)


    # put a new value into the input cell. 
    newInput = 42
    ws.Cells(1,1).Value = newInput

    # Now I want the sheet to recalculate and give me a new output.
    # (when manually operating this spreadsheet, I just input a new value,
    # and the whole sheet automatically recalculates)
    # Note: these two lines of code appear not to have any effect.
    ws.EnableCalculation = True
    ws.Calculate()

    # get the new output
    newOutput = ws.Cells(1,2).Value 

    wb.Close(True)

    print("newOutput is : ", newOutput)
    return True # I haven't finished writing the function... no return value yet.

输出:

The original value of myOutput is : 10 # this is fine.
newOutput is :  -2146826273 # when I open the spreadsheet, this cell now says #VALUE!

关于插件:我正在使用与化学相关的软件,该软件基本上是一个复杂的电子表格和execel插件。代码中的输出单元格显示“ #VALUE!”:它们使用命名的公式,这些公式位于我看不到的宏中(我想不放弃与化学相关的软件的代码)。

类似的问题:我发现了this similar question。就我而言,我不确定加载项是否包含在计算单元中。无论如何,我尝试添加答案中建议的代码:

def open_util():
    excel = win32com.client.Dispatch("Excel.Application")
    excel.AddIns.Add("rC:\...\add-in.xla").Installed = True # <-- This is the line I added.
    ...

但是,这只会生成一条错误消息:

Traceback (most recent call last):
  File "C:\...\my_program_name.py", line 246, in <module> 
open_util()
  File "C:\...\my_program_name.py", line 216, in open_util
excel.AddIns.Add("C:\...\add-in.xla").Installed = True
  File "C:\Users\00168070\AppData\Local\Programs\Python\Python36-32\lib\site-packages\win32com\gen_py\00020813-0000-0000-C000-000000000046x0x1x9\AddIns.py", line 35, in Add
, CopyFile)
pywintypes.com_error: (-2147352567, '例外が発生しました。', (0, 'Microsoft Excel', 'Add method of AddIns class failed', 'xlmain11.chm', 0, -2146827284), None)

(注意:我认为日语的意思是“发生了异常”。)

其他问题:是否有关于excel可用的python / win32com函数以及如何使用它们编写程序的文档? (例如,直到在别人的代码的碎片中看到它,我才知道我需要代码行“ ws.EnableCalculation = True”。)我只找到了一些教程。

1 个答案:

答案 0 :(得分:0)

有点晚了,但是我遇到了类似的问题。我也在使用第三方加载项。我相信这是造成问题的原因。

  1. 测试用例以查看

    ws.EnableCalculation = True

    ws.Calculate()

正在工作

import time
import win32com.client

xlApp = win32com.client.Dispatch("Excel.Application")
xlApp.Visible = True  # so we can see what is happening
wb = xlApp.Workbooks.Open(excel_wb)  # make excel wb a saved file where A1 = A2 + A3
ws = wb.ActiveSheet


for x in range(9):
     ws.EnableCalculation = False
     ws.Range('A2').Value = x
     ws.Range('A3').Value = 2 * x

     print(ws.Range('A1').Value)  # value in A1 should remain the same
     time.sleep(10)
     ws.EnableCalculation = True
     ws.Calculate()
     # value in A1 should update
     print(ws.Range('A1').Value)  # value in A1 should be updated

这对我来说很好。我们的预期输出为0、3、3、6、6、9等,因为它在更新前保持不变。

  1. 如果此代码对您有用,则可能是插件问题。对于我的插件,问题是“幻像” excel实例,该实例在关闭excel工作簿后会挂出并干扰插件。

要解决此问题,请2a。使用finally语句在程序和2b的结尾处关闭excel。在主函数的开头显式添加一个命令行excel kill

2a。

def quit_xl(xlApp, xlWB=None, save=True):
    if xlWB is not None:
        xlWB.Close(save)
    xlApp.Quit()
    del xlApp

2b。

import subprocess  # be careful - make sure that an outside user can't pass anything in

def kill_xl():
    try:
        kill_excel = """"“taskkill / f / im 
        excel.exe”"""  # command prompt to kill all excel instances
        subprocess.run(kill_excel, shell=True)
        return 0
    except Exception as e:
        return 1

放在一起:

def main():
    kill_xl()
    xlApp = win32com.client.Dispatch("Excel.Application")
    try:
        pass # main part of function
    except Exception as e:
        pass # if something goes wrong
    finally:
        quit_xl(xlApp)