簡體   English   中英

在 Microsoft Excel 中處理 VBA 彈出消息框

[英]Handling VBA popup message boxes in Microsoft Excel

我需要用 Python 自動化 Excel 文件,問題是 Excel 中有宏,單擊宏按鈕時會彈出一個彈出窗口:

宏截圖

彈出消息框本身有一個按鈕,我必須單擊它才能繼續。 我已經嘗試過使用 Python 中的 Win32com 和 Win32 API 庫,但在文檔中找不到任何解決方案。

我的代碼如下:

    ms_excel_app = win32.gencache.EnsureDispatch('Excel.Application')
    ms_excel_app.Visible = True
    ms_excel_app.DisplayAlerts = False

    template_file = r"C:\Templates_for_test\macro_test.xlsm"


    ms_excel_file =ms_excel_app.Workbooks.Open(template_file)
    ms_excel_file.DisplayAlerts = False
    excel_sheet = ms_excel_file.ActiveSheet
    # Opening a template file
    ms_excel_file = ms_excel_app.Workbooks.Open(template_file)

    spread_sheet = ms_excel_file.ActiveSheet

    # Click on 'Current date and time' macro button
    ms_excel_app.Application.Run("Sheet1.CommandButton1_Click")
    # TODO  verify verify timestamp and click ok- popup appears verify date and time format : dd/mm/yyyy hh:mm:ss
    timestamp_message = time.strftime("%d/%m/%Y %H:%M:%S")

我想要做的是識別屏幕截圖中的彈出窗口,然后單擊“確定”按鈕

有點晚了,因為我遇到了同樣的情況,所以只發布一個解決方案。

消息框使 Excel 應用程序卡住並相應地阻止您的主進程。 所以,一個通用的解決方案:

  • 啟動一個子線程來收聽消息框 -> 一旦找到就關閉它
  • 使用 Excel 文件完成主要工作
  • 一切完成后停止子線程

當您使用pywin32 ,它還可用於捕獲和關閉消息框。 一個Thread類來完成這項工作:

# ButtonClicker.py

import time
from threading import Thread, Event
import win32gui, win32con


class ButtonClicker(Thread):

    def __init__(self, title:str, interval:int):
        Thread.__init__(self)
        self._title = title 
        self._interval = interval 
        self._stop_event = Event()   

    def stop(self):
        '''Stop thread.'''
        self._stop_event.set()

    @property
    def stopped(self):
        return self._stop_event.is_set()

    def run(self):
        while not self.stopped:
            try:
                time.sleep(self._interval)
                self._close_msgbox()
            except Exception as e:
                print(e, flush=True)

    def _close_msgbox(self):
        # find the top window by title
        hwnd = win32gui.FindWindow(None, self._title)
        if not hwnd: return

        # find child button
        h_btn = win32gui.FindWindowEx(hwnd, None,'Button', None)
        if not h_btn: return

        # show text
        text = win32gui.GetWindowText(h_btn)
        print(text)

        # click button        
        win32gui.PostMessage(h_btn, win32con.WM_LBUTTONDOWN, None, None)
        time.sleep(0.2)
        win32gui.PostMessage(h_btn, win32con.WM_LBUTTONUP, None, None)
        time.sleep(0.2)

最后,您的代碼可能如下所示:

from ButtonClicker import ButtonClicker


# 1. start a child thread
# ButtonClicker instance tries to catch window with specified `title` at a user defined frequency. 
# In your case, the default title for Excel message box is `Microsoft Excel`.
listener = ButtonClicker("Microsoft Excel", 3)
listener.start()


# 2. do your work with Excel file as before
# though it might be blocked by message box, the concurrent child thread will close it

ms_excel_app = win32.gencache.EnsureDispatch('Excel.Application')
ms_excel_app.Visible = True
ms_excel_app.DisplayAlerts = False

template_file = r"C:\Templates_for_test\macro_test.xlsm"
...

# 3. close the child thread finally
listener.stop()

暫無
暫無

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

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