尝试捕获MsgBox文本并在xlwings中按下按钮

时间:2019-06-10 16:40:35

标签: macros python-3.6 xlwings

所以我有一些使用xlwings在Excel文件xlsm中写入数据的代码。

写完之后,我按下某个按钮进行计算。

有时,Excel中会弹出错误/消息,这很好,但是我想将此消息捕获到python,然后将其写入日志/打印。

另外,我需要与此消息进行交互,在这种情况下,请在消息框中按“确定”

消息框image的附加图像

2 个答案:

答案 0 :(得分:2)

伙计们,我已经能够使用外部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)

基本上,它的作用是连接到应用程序,然后搜索标题。

在这种情况下为“配置错误”

需要双击才能按“确定”以关闭消息。

第二,它从消息中获取文本,并可以将其转发到我想要的任何地方。

要记住的重要部分,因为这应该是自动化任务,所以应该同时运行,这意味着线程化。

因此,下面是一个简单的Thread类:

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()

需要一些操纵才能在不同的代码/场景中工作,但至少我希望以后我会帮助其他人,因为这似乎是一个非常普遍的问题。

答案 1 :(得分:0)

@Danny 的解决方案,即 pywinautoThread,在我的本地机器上运行良好,但是当 Excel 在服务器模式下运行时,它似乎无法捕获消息框,例如就我而言,自动化是在本地触发的,并由安装在服务器中的系统服务启动。

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()