簡體   English   中英

我可以使用 xlwings 抑制來自 VBA 的消息框嗎?

[英]Can I suppress message box from VBA using xlwings?

我正在使用 xlwings(python 3.7)從 VBA 調用宏。 運行時,宏會填充一個消息框在此處輸入圖像描述

我想知道是否有辦法從xlwings端抑制它(例如根本不顯示消息框或自動單擊確定)(無法更改宏,鎖定)。 我當前的設置如下所示:

app = xw.apps.active    # open application instance
app.visible = False  # Excel application not visible
app.display_alerts = False   # supress alert messages
app.screen_updating = False  # supress screen updates

謝謝!

由於您無法更改宏,因此左側選項是自動單擊“確定”按鈕。 顯然,您不能在主進程中執行此操作,因為一旦出現消息框就會卡住。 因此,您需要創建一個子線程來同時執行此操作,從而使主進程從卡住中恢復。 總之,你需要兩件事:

  • 子線程,例如threading.Thread
  • 用於捕獲消息框的 GUI 自動化庫,例如pywin32pywinautoPyAutoGUI

當您使用xlwings時,應該已經將pywin32作為依賴項安裝。 因此,例如在這里使用它。

整個過程如下:

import xlwings as xw
from listener import MsgBoxListener

# start child thread
listener = MsgBoxListener('Message-box-title-in-your-case', 3)
listener.start()

# main process as you did before
app = xw.apps.active    # open application instance
app.visible = False  # Excel application not visible
app.display_alerts = False   # supress alert messages
app.screen_updating = False  # supress screen updates
...

# stop listener thread
listener.stop()

其中MsgBoxListener是捕獲和關閉消息框的子線程:

  • title是消息框的標題,隱藏在您的屏幕截圖中
  • interval是檢測是否存在消息框的頻率
# listener.py

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


class MsgBoxListener(Thread):

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

    def stop(self): self._stop_event.set()

    @property
    def is_running(self): return not self._stop_event.is_set()

    def run(self):
        while self.is_running:
            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)


if __name__=='__main__':
    t = MsgBoxListener('Microsoft Excel', 1)
    t.start()
    time.sleep(10)
    t.stop()

暫無
暫無

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

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