Python <-> Excel 和 PowerPoint 控件。如何检查任务是否完成?

问题描述 投票:0回答:1

我正在使用 pywin32 包从 Python 控制 Excel 和 PowerPoint。我正在 Excel 中创建数据透视图,然后将这些图表复制到 ppt 幻灯片中。我如何检查特定任务是否已完成并且可以继续其他任务?当我立即运行代码时,通常会出现一些错误或 Excel 完全崩溃。我尝试在一些操作后添加一些“随机”延迟,然后效果更好。但我想等待完成特定操作所需的确切时间。

import win32com.client as win32
import sys
import time
import pandas as pd


#Pivot table config
rows = ['Temperature [°C]', 'Vdd [V]']
columns = ['Sample']
filters = []

xlsx_filepath = r"C:\Users\phrcka\Desktop\Excel_macro_test\DC_20230606_1407_test.xlsx"
ppt_filepath = r"C:\Users\phrcka\Desktop\Excel_macro_test\Python_test.pptx"

# construct the Powerpoint application object    
pptApp = win32.Dispatch("PowerPoint.Application")    
pptApp.Visible = True

#Open a template ppt file and make a copy
ppt_original =  pptApp.Presentations.Open(ppt_filepath)
ppt_original.SaveAs(r"C:\Users\phrcka\Desktop\Excel_macro_test\Python_test_new.pptx")
ppt_original.Close()

#Open the copy
ppt = pptApp.Presentations.Open(r"C:\Users\phrcka\Desktop\Excel_macro_test\Python_test_new.pptx")


# construct the Excel application object
xlApp = win32.Dispatch('Excel.Application')
xlApp.Visible = True

# Create workbook 
wb = xlApp.Workbooks.Open(xlsx_filepath)

# Create worksheets
ws_data = wb.Worksheets("Sheet1")
ws_pivot = wb.Worksheets("Demo")

#Loading data to dataframe
df = pd.read_excel(xlsx_filepath)                                              # load the xslx file as data_frame
header_values = df.columns.values                                              # extract the header from xlsx file
items_to_remove = rows + columns + filters + ['Corner']
values = list(filter(lambda x: x not in items_to_remove, header_values))       # Remove the fields which are already used in pivot chart. The rest values will be ploted.





def clear_pts(ws):
    for pt in ws.PivotTables():
        pt.TableRange2.Clear()

def insert_pt_field_set1(pt, rows, columns, filters, value):
    pt.ClearTable()                                                            # Cleasr all pivot fields
    
    xlApp.CalculateUntilAsyncQueriesDone()
    
    #Pivot rows
    i = 1
    field_rows = {}
    if len(rows) > 0:
        for row in rows:
            field_rows[row] = pt.PivotFields(row)
            field_rows[row].Orientation = 1                                    # Orientation = 1 means Pivot rows in excel    
            field_rows[row].Position = i
            i += 1
      
    #Pivot columns
    i = 1
    field_columns = {}
    if len(columns) > 0:
        for column in columns:
            field_columns[column] = pt.PivotFields(column)
            field_columns[column].Orientation = 2                               #Orientation = 2 means Pivot colums in excel
            field_columns[column].Position = i
            i += 1
    #Pivot filters
    i = 1
    field_filters = {}
    if len(filters) > 0:
        for filter_string in filters:  
            field_filters[filters] = pt.PivotFields(filters)    
            field_filters[filters].Orientation = 3                              #Orientation = 3 means Pivot filters in excel
            field_filters[filters].Position = i
            i += 1

    #Pivot value
    field_values = {}
    field_values[value] = pt.PivotFields(value)
    field_values[value].Orientation = 4                                         #Orientation = 4 means Pivot values in excel
    field_values[value].Function = -4106                                        #Value set to Average
    
    xlApp.CalculateUntilAsyncQueriesDone()  
      
    #Custom filters 
    field_rows['Temperature [°C]'].PivotItems("0").Visible = False
    field_rows['Temperature [°C]'].PivotItems("45").Visible = False

def pivot_chart_create(ws_pivot):
    
    ws_pivot.Activate()
    ws_pivot.Cells(3,3).Select()                                                  # select cell within area of Pivot table
    ws_pivot.Shapes.AddChart2(-1, 4).Select                                       # create a Pivot chart from pivot table data: -1 means dafault style, 4 means line type of chart
                                                  

def pivot_chart_adjust_and_copy(ws_pivot, rows, values):
    
    ActiveChart = ws_pivot.ChartObjects(1).Chart
    chart_settings(ActiveChart, rows, values)
    ws_pivot.ChartObjects(1).Copy()                                             # Copy the first chart which is on the sheet ws_pivot

    
def rgbToInt(rgb):                                                             # Convert RBG number to int
    colorInt = rgb[0] + (rgb[1] * 256) + (rgb[2] * 256 * 256)
    return colorInt

def chart_settings(ActiveChart, label_x, label_y):                             # adjust line colors and axis labeling
    
    ActiveChart.FullSeriesCollection("SPEC_MAX").Format.Line.ForeColor.RGB = rgbToInt((255,0,0))
    ActiveChart.FullSeriesCollection("SPEC_MAX").Format.Line.DashStyle = 10   # 10 = msoLineSysDash, 11 = msoLineSysDot
    ActiveChart.FullSeriesCollection("SPEC_MAX").Format.Line.Weight = 3
    
    ActiveChart.FullSeriesCollection("SPEC_MIN").Format.Line.ForeColor.RGB = rgbToInt((0, 176, 240))
    ActiveChart.FullSeriesCollection("SPEC_MIN").Format.Line.DashStyle = 10   # 10 = msoLineSysDash, 11 = msoLineSysDot
    ActiveChart.FullSeriesCollection("SPEC_MIN").Format.Line.Weight = 3
    
    ActiveChart.FullSeriesCollection("SPEC_TYP").Format.Line.ForeColor.RGB = rgbToInt((0, 176, 80))
    ActiveChart.FullSeriesCollection("SPEC_TYP").Format.Line.DashStyle = 10   # 10 = msoLineSysDash, 11 = msoLineSysDot
    ActiveChart.FullSeriesCollection("SPEC_TYP").Format.Line.Weight = 3
            
    ActiveChart.FullSeriesCollection("SIM_MAX").Format.Line.ForeColor.RGB = rgbToInt((255, 0, 0))
    ActiveChart.FullSeriesCollection("SIM_MAX").Format.Line.DashStyle = 11   # 10 = msoLineSysDash, 11 = msoLineSysDot
    ActiveChart.FullSeriesCollection("SIM_MAX").Format.Line.Weight = 3
    
    ActiveChart.FullSeriesCollection("SIM_MIN").Format.Line.ForeColor.RGB = rgbToInt((0, 176, 240))
    ActiveChart.FullSeriesCollection("SIM_MIN").Format.Line.DashStyle = 11   # 10 = msoLineSysDash, 11 = msoLineSysDot
    ActiveChart.FullSeriesCollection("SIM_MIN").Format.Line.Weight = 3
    
    ActiveChart.FullSeriesCollection("SIM_TYP").Format.Line.ForeColor.RGB = rgbToInt((0, 176, 80))
    ActiveChart.FullSeriesCollection("SIM_TYP").Format.Line.DashStyle = 11   # 10 = msoLineSysDash, 11 = msoLineSysDot
    ActiveChart.FullSeriesCollection("SIM_TYP").Format.Line.Weight = 3

    ActiveChart.Axes(1, 1).HasTitle = True
    merged_label_string_x = ', '.join(label_x)
    ActiveChart.Axes(1, 1).AxisTitle.Text = 'Corner [' + merged_label_string_x +']'   # Add an x label
    
    ActiveChart.Axes(2, 1).HasTitle = True
    ActiveChart.Axes(2, 1).AxisTitle.Text = label_y                             # Add an y label
        


# clear pivot tables on Report tab
clear_pts(ws_pivot)

# create pt cache connection
pt_cache = wb.PivotCaches().Create(1, ws_data.Range("A1").CurrentRegion)       # https://docs.microsoft.com/en-us/office/vba/api/excel.xlpivottablesourcetype

# insert pivot table designer/editor
pt = pt_cache.CreatePivotTable(ws_pivot.Range("B3"), "Pivot_table")

ppt_slides_count = ppt.Slides.Count
initial_run = 1
for value in values:
    print('   Processing value: %s' %value)
    
    # xlApp.CalculateUntilAsyncQueriesDone()
    time.sleep(1)

    insert_pt_field_set1(pt, rows, columns, filters, value)
    
    # xlApp.CalculateUntilAsyncQueriesDone()
    time.sleep(1)
    
    if initial_run == 1:
        pivot_chart_create(ws_pivot)
    initial_run +=1   
    
    pivot_chart_adjust_and_copy(ws_pivot, rows, value)
    
    # xlApp.CalculateUntilAsyncQueriesDone()
    time.sleep(1)
    
    pptApp.ActiveWindow.View.GotoSlide(ppt_slides_count)                      
    ppt.Slides.Add(ppt_slides_count + 1, 16)                                       # Add new slide, often used layouts 16, 32, 29
    ppt_slides_count +=1
    pptApp.ActiveWindow.View.GotoSlide(ppt_slides_count)
    ppt.Slides.Item(ppt_slides_count).Shapes.Paste().Select()                      # Paste the chart to ppt
    pptApp.ActiveWindow.Selection.Cut()
    ppt.Slides.Item(ppt_slides_count).Shapes(2).Select()                           # Shape 2 means second placeholder on the slide layout
    pptApp.ActiveWindow.View.Paste()
    ppt.Slides.Item(ppt_slides_count).Shapes(2).LinkFormat.BreakLink()
    
    ppt.Slides(ppt_slides_count).Shapes.Placeholders.Item(1).TextFrame.TextRange.Text = value
    
    ppt.Save()

我尝试使用 xlApp.CalculateUntilAsyncQueriesDone() 命令而不是延迟,但它没有解决问题。谢谢你的帮助

python excel vba powerpoint pywin32
1个回答
0
投票

在提供的代码中,已经使用 xlApp.CalculateUntilAsyncQueriesDone() 进行异步计算处理,以等待所有数据透视表计算完成。但是,该错误可能是由于 Python 代码继续执行后异步查询仍在进行所致。 由于计算过程是异步的,因此您需要确保在将图表复制到 PowerPoint 幻灯片之前完成所有查询并更新结果。以下是如何实现此目标的示例:

# Create pivot chart in Excel'pivot_chart_create(ws_pivot)
# Wait for pivot table calculations to completewhile xlApp.CalculationState != 0:
    time.sleep(1)  # Wait for 1 second to check again

在此示例中,执行pivot_chart_create(ws_pivot)中的代码来创建数据透视图,然后使用while循环不断检查Excel的CalculationState。如果 CalculationState 不为 0(表示计算正在进行),则代码等待 1 秒,然后再次检查。计算完成后,代码将继续将图表复制到 PowerPoint 幻灯片。 通过在循环中不断检查 CalculationState,您可以确保在继续下一个任务之前所有数据透视表计算都已完成。这应该有助于避免 Excel 中的错误和崩溃。

© www.soinside.com 2019 - 2024. All rights reserved.