从python运行excel宏

时间:2015-01-23 03:47:25

标签: python excel excel-vba python-3.x vba

我正在使用以下代码从Python运行Excel宏:

import pymysql
import datetime
import csv
import math
import os
import glob
import sys
import win32com.client
import numpy
from tkinter import *
from tkinter import ttk
import tkinter.messagebox

def run_macro():
    print('macro')

    #this if is here because if an executable is created, __file__ doesn't work
    if getattr(sys, 'frozen', False):
        name = (os.path.dirname(sys.executable) + '\\Forecast template.xlsm')

    else:
        name = str(os.path.dirname(os.path.realpath(__file__)) + '\\Forecast template.xlsm')

    print(name)

    #this part runs the macro from excel
    if os.path.exists(name):
        xl=win32com.client.Dispatch("Excel.Application")
        xl.Workbooks.Open(Filename=name, ReadOnly=1)
        xl.Application.Run("ThisWorkbook.LoopFilesInFolder")
        xl.Application.Quit() # Comment this out if your excel script closes
        del xl

    print('File refreshed!')

我似乎遇到了这个问题,在运行之后,我打开任何excel文件,我只得到一个灰色的窗口:

enter image description here

知道为什么会这样吗?另外我如何在Excel中添加一些只打开文件的代码? (不是为了获取信息,而是在Excel中打开该文件)

额外的问题:如何解决所有打开的Excel文件?

编辑:我刚检查了宏,这很好用,问题似乎来自于我运行代码时。

新编辑:

这是宏的代码:

Sub LoopFilesInFolder()

    Dim wb1 As Workbook
    Dim wb2 As Workbook
    Dim path As String
    Dim file As String
    Dim extension As String
    Dim myFileName As String

    Application.ScreenUpdating = False
    Application.DisplayAlerts = False

    Set wb1 = ActiveWorkbook

    path = ActiveWorkbook.path & "\csvs\"

    extension = "*.csv"
    file = Dir(path & extension)

    Do While file <> ""

        Set wb2 = Workbooks.Open(Filename:=path & file)
        wb2.Activate

        'this section is for the avail heads file, basically it just opens it and copies the info to the template
        If wb2.Name = "avail_heads.csv" Then
            Range("A1").Select
            Range(Selection, Selection.End(xlDown)).Select
            Range(Selection, Selection.End(xlToRight)).Select
            Selection.Copy

            wb1.Activate

            Worksheets("raw data").Range("B88").PasteSpecial xlPasteValues
        End If

        'this section is for the forecast file, basically it just opens it and copies the info to the template
        If wb2.Name = "forecast.csv" Then
            Range("A1").Select
            Range(Selection, Selection.End(xlDown)).Select
            Range(Selection, Selection.End(xlToRight)).Select
            Selection.Copy

            wb1.Activate

            Worksheets("raw data").Range("B74").PasteSpecial xlPasteValues
        End If

        'this section is for the income file, basically it just opens it and copies the info to the template
        If wb2.Name = "income volume.csv" Then
            Range("A1").Select
            Range(Selection, Selection.End(xlDown)).Select
            Range(Selection, Selection.End(xlToRight)).Select
            Selection.Copy

            wb1.Activate

            Worksheets("raw data").Range("B3").PasteSpecial xlPasteValues
        End If

        'this section is for the outgoing volume file, basically it just opens it and copies the info to the template
        If wb2.Name = "outgoing_volume.csv" Then
            Range("A1").Select
            Range(Selection, Selection.End(xlDown)).Select
            Range(Selection, Selection.End(xlToRight)).Select
            Selection.Copy

            wb1.Activate

            Worksheets("raw data").Range("B36").PasteSpecial xlPasteValues
        End If

        'this section is for the required heads file, basically it just opens it and copies the info to the template
        If wb2.Name = "required_heads.csv" Then
            Range("A1").Select
            Range(Selection, Selection.End(xlDown)).Select
            Range(Selection, Selection.End(xlToRight)).Select
            Selection.Copy

            wb1.Activate

            Worksheets("raw data").Range("B102").PasteSpecial xlPasteValues
        End If

        wb2.Close
        file = Dir

    Loop

    'myFileName = ActiveWorkbook.path & "\forecast_for_w" & Format(Now, "ww") + 1

    myFileName = ActiveWorkbook.path & "\yoda_forecast"

    ActiveWorkbook.SaveAs Filename:=myFileName, FileFormat:=xlWorkbookNormal

    'MsgBox "Done!"

    Application.DisplayAlerts = True

End Sub

2 个答案:

答案 0 :(得分:4)

我在赏金上花了差不多一个星期,我真的不知道之前有多少人遇到过这个问题。把头发撕了一个多星期,考虑多次跳出办公室的窗户后,我想出了问题所在。

你的问题不在python(有点),但主要是在VBA代码上,我刚刚添加了

Application.ScreenUpdating = True

最后,问题停止了。不确定是否在宏完成时没有更新的excel错误或者一旦宏完成就不允许屏幕更新的python错误。但是在这之后一切都很好。

谢谢!

答案 1 :(得分:0)

您需要在调度后将可见性设置为True:

xl = win32com.client.Dispatch("Excel.Application")
xl.Application.Visible = True

另外,调用宏不应该需要ThisWorkbook

xl.Application.Run("LoopFilesInFolder")

为了能够再次关闭工作簿,您需要将其分配给变量:

wb = xl.Workbooks.Open(Filename=name, ReadOnly=1)
wb.Close(SaveChanges=False)

我编写了包xlwings以简化操作:

from xlwings import Workbook, Range
wb = Workbook(r'C:\path\to\workbook.xlsx')  # open a workbook if not open yet
Range('A1').value = 123  # Write a value to cell A1
wb.close()  # close the workbook again

运行宏还没有实现,但是issue已经开放了。在此期间,您可以通过执行此操作(从上面开始):

wb.xl_app.Run("macro_name")