python - 我可以使用 xlwings 抑制来自 VBA 的消息框吗?
问题描述
我正在使用 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 自动化库,
pywin32
例如pywinauto
或PyAutoGUI
。
当您使用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()
推荐阅读
- c - 在设置二维数组的值时出现分段错误,即使循环计数器值在数组的 sizeof 内
- powershell - PowerShell 通过组策略
- java - 在一个事务中插入和更新时 Sql server 死锁
- php - Wordpress - 价格后的十进制,00
- dart - 禁用向下拖动以关闭 showModalBottomSheet
- sql-server - 如何在新的临时表(系统版本)上使用 SSDT 防止 SQL71609
- apache-spark - 如何将 sql 转换为 spark 数据集?
- python - 从单个数据帧创建多个 pyspark 数据帧
- ag-grid - 不保留 ag-grid v19 过滤器
- android - Spinner onItemSelected 仅返回数组的最后一项