试图在 xlwings 中捕获 MsgBox 文本并按下按钮
Trying to catch MsgBox text and press button in xlwings
所以我有一些代码使用 xlwings 在 Excel 文件 xlsm.
中写入数据
写完后,我按某个按钮计算。
有时,error/message 会在 Excel 中弹出,这很好,但我想将此消息捕获到 python,稍后再将其写入 log/print ]它。
此外,我需要与此消息进行交互,在这种情况下按消息框中的 "Ok"
附上消息框的图片
伙计们,我已经能够使用外部 python 库解决这个问题。
代码如下:
from pywinauto import application as autoWin
app = autoWin.Application()
con = app.connect(title = 'Configuration Error')
msgText = con.Dialog.Static2.texts()[0]
con.Dialog.Button.click()
con.Dialog.Button.click()
print(msgText)
基本上,它的作用是连接到应用程序并搜索标题。
在这种情况下 "Configuration Error"
需要双击才能按"Ok"关闭消息。
其次,它从消息中获取文本,并可以将其转发到我想要的任何地方。
不过要记住重要的部分,因为这应该是一个自动化任务,它应该 运行 并发,这意味着线程。
所以,下面是一个简单的线程 class:
class ButtonClicker(Thread):
def __init__(self):
Thread.__init__(self)
self._stop_event = Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
def run(self) -> None:
while True:
time.sleep(3)
try:
app = autoWin.Application()
con = app.connect(title='Configuration Error')
msg_data = con.Dialog.Static2.texts()[0]
while True:
con.Dialog.Button.click()
# con.Dialog.Button.click()
# print(msg_data)
return msg_data
except Exception as e:
print('Excel didnt stuck')
break
当然还有实际使用它:
event_handle = ButtonClicker()
event_handle.start()
需要一些操作才能在不同的 codes/scenarios 中工作,但至少我希望我将来能帮助别人,因为这似乎是一个很常见的问题。
@Danny 的解决方案,即 pywinauto
和 Thread
,在我的本地机器上完美运行,但当 Excel 为 [=21= 时似乎无法捕获消息框] 在服务器模式下,例如在我的例子中,自动化是在本地触发的,并由安装在服务器中的系统服务启动。
pywinauto.findwindows.ElementNotFoundError:
{'title': '<my-wanted-title>', 'backend': 'win32', 'visible_only': False}
终于用另一个python第三方库pywin32
解决了,所以这里提供一个备用方案。
'''
Keep finding message box with specified title and clicking button to close it,
until stopped by the main thread.
'''
import time
from threading import Thread, Event
import win32gui
import 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)
if __name__=='__main__':
t = ButtonClicker('Configuration Error', 3)
t.start()
time.sleep(10)
t.stop()
所以我有一些代码使用 xlwings 在 Excel 文件 xlsm.
中写入数据写完后,我按某个按钮计算。
有时,error/message 会在 Excel 中弹出,这很好,但我想将此消息捕获到 python,稍后再将其写入 log/print ]它。
此外,我需要与此消息进行交互,在这种情况下按消息框中的 "Ok"
附上消息框的图片
伙计们,我已经能够使用外部 python 库解决这个问题。
代码如下:
from pywinauto import application as autoWin
app = autoWin.Application()
con = app.connect(title = 'Configuration Error')
msgText = con.Dialog.Static2.texts()[0]
con.Dialog.Button.click()
con.Dialog.Button.click()
print(msgText)
基本上,它的作用是连接到应用程序并搜索标题。
在这种情况下 "Configuration Error"
需要双击才能按"Ok"关闭消息。
其次,它从消息中获取文本,并可以将其转发到我想要的任何地方。
不过要记住重要的部分,因为这应该是一个自动化任务,它应该 运行 并发,这意味着线程。
所以,下面是一个简单的线程 class:
class ButtonClicker(Thread):
def __init__(self):
Thread.__init__(self)
self._stop_event = Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
def run(self) -> None:
while True:
time.sleep(3)
try:
app = autoWin.Application()
con = app.connect(title='Configuration Error')
msg_data = con.Dialog.Static2.texts()[0]
while True:
con.Dialog.Button.click()
# con.Dialog.Button.click()
# print(msg_data)
return msg_data
except Exception as e:
print('Excel didnt stuck')
break
当然还有实际使用它:
event_handle = ButtonClicker()
event_handle.start()
需要一些操作才能在不同的 codes/scenarios 中工作,但至少我希望我将来能帮助别人,因为这似乎是一个很常见的问题。
@Danny 的解决方案,即 pywinauto
和 Thread
,在我的本地机器上完美运行,但当 Excel 为 [=21= 时似乎无法捕获消息框] 在服务器模式下,例如在我的例子中,自动化是在本地触发的,并由安装在服务器中的系统服务启动。
pywinauto.findwindows.ElementNotFoundError:
{'title': '<my-wanted-title>', 'backend': 'win32', 'visible_only': False}
终于用另一个python第三方库pywin32
解决了,所以这里提供一个备用方案。
'''
Keep finding message box with specified title and clicking button to close it,
until stopped by the main thread.
'''
import time
from threading import Thread, Event
import win32gui
import 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)
if __name__=='__main__':
t = ButtonClicker('Configuration Error', 3)
t.start()
time.sleep(10)
t.stop()