Пример #1
0
 def click_lesson(self, lesson_name):
     lesson_win = Desktop(backend="uia").window(
         **self.configs['lesson_win']['id'])
     lesson_win.wait('visible', timeout=30)
     lessons = self.get_lesson_list(lesson_win)
     for lesson in lessons.keys():
         #self.logger.debug("Lesson: %s." % lesson)
         if lesson_name == lesson:
             if len(lessons) > 1:  # 单个课程,不需点击
                 lessons[lesson_name].click()
             dialog_confirm = lesson_win.window(
                 **self.configs['lesson_win']['confirm']['id'])
             dialog_confirm.window(
                 **self.configs['lesson_win']['confirm']['ok']).click()
             lesson_win.wait_not('visible', timeout=60)
         elif lesson_name in lesson and '\r\n(上课中...)' in lesson:
             self.logger.debug("%s is working." % lesson_name)
             lesson_win.window(
                 **self.configs['lesson_win']['exit']).click()  # 关闭
         elif len(lessons) == 1:  # 单个课程,且课程名称不匹配情况
             dialog_confirm = lesson_win.window(
                 **self.configs['lesson_win']['confirm']['id'])
             dialog_confirm.window(
                 **self.configs['lesson_win']['confirm']['ng']).click()
             lesson_win.wait_not('visible', timeout=60)
         else:
             self.logger.debug("%s in config doesnot exists." % lesson_name)
Пример #2
0
 def start_from_tray(self, tray_icon):
     tray_icon.wrapper_object().click_input()
     tray_icon_menu = Desktop(backend="uia").window(
         **self.configs['TaskBar']['teacher_menu']['id'])
     tray_icon_menu.wait('visible', timeout=10)
     tray_icon_menu.window(**self.configs['TaskBar']['teacher_menu']
                           ['display_win']).wrapper_object().click_input()
     main_win = Desktop(backend="uia").window(
         **self.configs['teachermain']['main']['id'])
     main_win.exists(timeout=5)
Пример #3
0
class DesktopWindowSpecificationTests(unittest.TestCase):
    """Unit tests for Desktop object"""

    if UIA_support:

        def setUp(self):
            """Set some data and ensure the application is in the state we want"""
            Timings.Slow()
            self.app = Application().start('explorer.exe "' +
                                           mfc_samples_folder_32 + '"')
            self.desktop = Desktop(backend='uia')

        def tearDown(self):
            """Close the application after tests"""
            self.desktop.MFC_samplesDialog.CloseButton.click()
            self.desktop.MFC_samplesDialog.wait_not('visible')

        def test_folder_list(self):
            """Test that ListViewWrapper returns correct files list in explorer.exe"""
            files_list = self.desktop.MFC_samplesDialog.Shell_Folder_View.Items_View.wrapper_object(
            )
            self.assertEqual(
                [item.window_text() for item in files_list.get_items()], [
                    u'x64', u'BCDialogMenu.exe', u'CmnCtrl1.exe',
                    u'CmnCtrl2.exe', u'CmnCtrl3.exe', u'CtrlTest.exe',
                    u'mfc100u.dll', u'RebarTest.exe', u'RowList.exe',
                    u'TrayMenu.exe'
                ])
            self.assertEqual(
                files_list.item('RebarTest.exe').window_text(),
                'RebarTest.exe')

    else:  # Win32

        def setUp(self):
            """Set some data and ensure the application is in the state we want"""
            Timings.Defaults()
            self.app = Application(backend='win32').start(
                os.path.join(mfc_samples_folder, u"CmnCtrl3.exe"))
            self.desktop = Desktop()

        def tearDown(self):
            """Close the application after tests"""
            self.desktop.window(title='Common Controls Sample',
                                process=self.app.process).SendMessage(
                                    win32defines.WM_CLOSE)

        def test_simple_access_through_desktop(self):
            """Test that controls can be accessed by 4 levels of attributes"""
            dlg = self.desktop.window(title='Common Controls Sample',
                                      process=self.app.process)
            self.assertEqual(dlg.Pager.Toolbar.button_count(), 12)
Пример #4
0
def find_main_window(name, wait=True):
    desktop = Desktop()
    main_window = desktop.window(best_match=name)

    if wait:
        main_window.wait("visible")

    main_window.print_control_identifiers()

    return main_window
Пример #5
0
 def click_switch_local_mode(self):
     # 点击【课程控制】
     self.main_win[self.configs['teachermain']['toolbar']
                   ['BtnLesson']].click()
     # 点击【本地考试模式】
     self.click_menu_btn(
         self.configs['teachermain']['LessonMenu']['ExamMode'])
     lesson_win = Desktop(backend="uia").window(
         **self.configs['lesson_win']['id'])
     dialog_confirm = lesson_win.window(
         **self.configs['lesson_win']['confirm']['id'])
     dialog_confirm.window(
         **self.configs['lesson_win']['confirm']['ok']).click()
Пример #6
0
 def click_class_over(self):
     # 点击【课程控制】
     self.main_win[self.configs['teachermain']['toolbar']
                   ['BtnLesson']].click()
     # 点击【放学】
     self.click_menu_btn(
         self.configs['teachermain']['LessonMenu']['ClassOver'])
     lesson_win = Desktop(backend="uia").window(
         **self.configs['lesson_win']['id'])
     dialog_confirm = lesson_win.window(
         **self.configs['lesson_win']['confirm']['id'])
     dialog_confirm.window(
         **self.configs['lesson_win']['confirm']['ok']).click()
Пример #7
0
 def restart_lesson(self):
     # 点击【课程控制】
     self.main_win[self.configs['teachermain']['toolbar']
                   ['BtnLesson']].click()
     # 点击【重启】
     self.click_menu_btn(
         self.configs['teachermain']['LessonMenu']['Restart'])
     lesson_win = Desktop(backend="uia").window(
         **self.configs['lesson_win']['id'])
     dialog_confirm = lesson_win.window(
         **self.configs['lesson_win']['confirm']['id'])
     dialog_confirm.window(
         **self.configs['lesson_win']['confirm']['ok']).click()
Пример #8
0
class DesktopWindowSpecificationTests(unittest.TestCase):

    """Unit tests for Desktop object"""

    if UIA_support:
        def setUp(self):
            """Set some data and ensure the application is in the state we want"""
            Timings.Slow()
            self.app = Application().start('explorer.exe "' + mfc_samples_folder_32 + '"')
            self.desktop = Desktop(backend='uia')

        def tearDown(self):
            """Close the application after tests"""
            self.desktop.MFC_samplesDialog.CloseButton.click()
            self.desktop.MFC_samplesDialog.wait_not('visible')

        def test_folder_list(self):
            """Test that ListViewWrapper returns correct files list in explorer.exe"""
            files_list = self.desktop.MFC_samplesDialog.Shell_Folder_View.Items_View.wrapper_object()
            self.assertEqual([item.window_text() for item in files_list.get_items()],
                             [u'x64', u'BCDialogMenu.exe', u'CmnCtrl1.exe', u'CmnCtrl2.exe', u'CmnCtrl3.exe',
                              u'CtrlTest.exe', u'mfc100u.dll', u'RebarTest.exe', u'RowList.exe', u'TrayMenu.exe'])
            self.assertEqual(files_list.item('RebarTest.exe').window_text(), 'RebarTest.exe')

    else: # Win32
        def setUp(self):
            """Set some data and ensure the application is in the state we want"""
            Timings.Defaults()
            self.app = Application(backend='win32').start(os.path.join(mfc_samples_folder, u"CmnCtrl3.exe"))
            self.desktop = Desktop()

        def tearDown(self):
            """Close the application after tests"""
            self.desktop.window(title='Common Controls Sample', process=self.app.process).SendMessage(win32defines.WM_CLOSE)

        def test_simple_access_through_desktop(self):
            """Test that controls can be accessed by 4 levels of attributes"""
            dlg = self.desktop.window(title='Common Controls Sample', process=self.app.process)
            self.assertEqual(dlg.Pager.Toolbar.button_count(), 12)
Пример #9
0
 def stop_lesson(self):
     ''' 下课 '''
     # 点击【课程控制】
     self.main_win[self.configs['teachermain']['toolbar']
                   ['BtnLesson']].click()
     # 点击【下课】
     self.click_menu_btn(self.configs['teachermain']['LessonMenu']['Stop'])
     #
     lesson_win = Desktop(backend="uia").window(
         **self.configs['lesson_win']['id'])
     dialog_confirm = lesson_win.window(
         **self.configs['lesson_win']['confirm']['id'])
     dialog_confirm.window(
         **self.configs['lesson_win']['confirm']['ok']).click()
Пример #10
0
 def logon_process(self):
     ''' 登录处理 '''
     logon_win = Desktop(backend="uia").window(
         **self.configs['logon_win']['id'])
     if logon_win.exists(timeout=5):
         user = logon_win.window(**self.configs['logon_win']
                                 ['user']).wrapper_object().get_value()
         self.logger.debug("Logon User: %s" % user)
         if user != self.configs['teachermain']['login']['user']:
             logon_win.window(
                 **self.configs['logon_win']['user']).type_keys(
                     configs['teachermain']['login']['user'])
         logon_win.window(**self.configs['logon_win']['passwd']).type_keys(
             self.configs['teachermain']['login']['passwd'])
         logon_win.window(**self.configs['logon_win']['logon_btn']).click()
         reg_win = Desktop(backend="uia").window(
             **self.configs['teachermain']['main']['id'])
         reg_btn = reg_win.window(
             **self.configs['teachermain']['main']['try_btn'])
         if (reg_btn.exists(2)):
             self.logger.info('Current Version: Try, not registered.')
             reg_btn.click()
Пример #11
0
Popen('calc.exe', shell=True)
dlg = Desktop(backend="uia").Calculator
dlg.wait('visible')

##
#There are many possible criteria 
# for creating window specifications. 
# These are just a few examples.

# can be multi-level
app.window(title_re='.* - Notepad$').window(class_name='Edit')

# can combine criteria
dlg = Desktop(backend="uia").Calculator
dlg.window(auto_id='num8Button', control_type='Button')


# But fortunately pywinauto 
# uses “best match” algorithm to make a lookup 
# resistant to typos and small variations.
app.UntitledNotepad
# is equivalent to
app.window(best_match='UntitledNotepad')

# Unicode characters and special 
# symbols usage is possible through 
# an item access in a dictionary like manner.
app['Untitled - Notepad']
# is the same as
app.window(best_match='Untitled - Notepad')
Пример #12
0
 def get_trayicon(self):
     tray_shell = Desktop(backend="uia").window(
         **self.configs['TaskBar']['id'])
     tray_icon = tray_shell.window(
         **self.configs['TaskBar']['teacher_icon'])
     return tray_icon
Пример #13
0
        # fw.write(new_content_lines + '\n')
        fw.write((new_content_lines + '\n').encode('gbk'))

fw.close()
"""
# 清空 record_txt_file文件内容
fw_record = codecs.open(record_txt_file, "a", 'gbk')
fw_record.seek(0)
fw_record.truncate()
# 自动化测试【一位整数乘法】(10个数字两两相乘,共10*10=100种情况)

for i in range(1, 10):
    for j in range(1, 10):
        real_value = i * j
        # dlg_spec.window(title=str(i), control_type="Button").draw_outline(colour="red", thickness=3)
        dlg_spec.window(title=str(i), control_type="Button").click()
        # dlg_spec.window(title="加", control_type="Button").draw_outline(colour="red", thickness=3)
        dlg_spec.window(title="乘", control_type="Button").click()
        # dlg_spec.window(title=str(j), control_type="Button").draw_outline(colour="red", thickness=3)
        dlg_spec.window(title=str(j), control_type="Button").click()
        # dlg_spec.window(title="等于", control_type="Button").draw_outline(colour="red", thickness=3)
        dlg_spec.window(title="等于", control_type="Button").click()

        # 选中结果框
        # dlg_spec.window(title="结果").draw_outline(colour="red", thickness=3)
        # 复制内容
        send_keys("^c")
        # 打开剪贴板
        wc.OpenClipboard()
        # 获取剪贴板内容
        copy_text = wc.GetClipboardData(win32con.CF_TEXT)
Пример #14
0
dlg['登录Edit'].type_keys('a044')
dlg.type_keys('{TAB 1}')
dlg.type_keys('20140960')
dlg['确定'].click()
newdlg = Desktop(
    backend='win32'
)['qadui: CCJX Domain CCJX [RMB] > CCJX 捷和电机(江西)有限公司 (1) - QAD Enterprise Applications']
newdlg.wait('visible', timeout=5)
newdlg['Edit'].type_keys('13.7')
sleep(0.5)
newdlg['Edit'].type_keys('{ENTER 1}')
newdlg2 = Desktop(
    backend='win32'
)['qadui: CCJX Domain CCJX [RMB] > CCJX 捷和电机(江西)有限公司 (2) - QAD Enterprise Applications']
sleep(2)
ui = newdlg2.window(title='物料用途表查询',
                    class_name='WindowsForms10.Window.8.app.0.83a9e6_r15_ad1')
newdlg2.wait('visible', timeout=10)
newdlg2.maximize()
ui.type_keys(var)
ui.type_keys('{ENTER 2}')
sleep(2)
newdlg2.click(button='left',
              pressed='',
              coords=(500, 500),
              double=False,
              absolute=False)
newdlg2.type_keys('^a')
newdlg2.type_keys('^c')
qad3 = Desktop(
    backend='win32'
)['qadui: CCJX Domain CCJX [RMB] > CCJX 捷和电机(江西)有限公司 (3) - QAD Enterprise Applications']
Пример #15
0
    def loginView(self):
        try:
            connected_nordlocker.connect(title='NordLocker')
        except findwindows.WindowAmbiguousError:
            wins = findwindows.find_elements(active_only=True, title="NordLocker")
            connected_nordlocker.connect(handle=wins[0].handle)
        except findwindows.ElementNotFoundError:
            wait_until(30, 0.5, lambda: len(findwindows.find_elements(active_only=True, title="NordLocker")) > 0)
            wins = findwindows.find_elements(active_only=True, title="NordLocker")
            connected_nordlocker.connect(handle=wins[0].handle)

def timeoutError():
    main_screen = connected_nordlocker.window(title='NordLocker')
    try:
        actionable_window = main_screen.wait("exists enabled visible ready", timeout=20)
    except TimeoutError as e:
        print("Baigesi sesijos laikas")

        print(f"NordLocker app identifier: {main_screen}")

desktop = Desktop(backend="uia")
login_screen = desktop.window(title="NordLocker", control_type="Window")
drop_down = login_screen.child_window(auto_id="HeaderDropDown", control_type="ToolBar")
drop_down.print_control_identifiers()
drop_down.click_input()

login_button = login_screen.child_window(title="Log in", control_type="Button")
login_button.click_input()

time.sleep(5)
Пример #16
0
def Install():
    Popen(r'D:\Client\DuoLaBao\Setup-DLB-1.4.12.1.exe', shell=True)
    time.sleep(1)
    dlg = Desktop(backend="win32").window(title=u"安装 - 哆啦宝")

    # 界面一 您将把哆啦宝安装在哪里?
    # 界面一 您将把哆啦宝安装在哪里?
    time.sleep(1)
    # 获取路径输入框
    dlg.window(class_name="TEdit")
    edit = dlg['TEdit']
    # 输入路径
    edit.set_text(r'D:\Program Files\DuoLaBao')
    # 发送快捷键 下一步
    dlg.type_keys("%N")

    # 文件夹已经存在
    # 文件夹已经存在
    time.sleep(2)
    exeits = Desktop(backend="win32").window(title=u"文件夹已经存在")
    #判断窗体是否存在
    if exeits.exists():
        exeits.type_keys("%Y")

    # 界面二 您想选择哪个附加任务?
    # 界面二 您想选择哪个附加任务?
    # 发送快捷键 下一步
    time.sleep(2)
    dlg.type_keys("%N")

    # 界面三 安装程序开始在您的电脑中安装哆啦宝.
    # 界面三 安装程序开始在您的电脑中安装哆啦宝.
    time.sleep(2)
    dlg.type_keys("%I")

    #界面四 哆啦宝安装完成F
    #界面四 哆啦宝安装完成F
    time.sleep(2)
    dlgss = Desktop(backend="win32").window(title=u"安装 - 哆啦宝")
    dlgss.type_keys("%F")

    # 界面五 初始化激活提示
    # 界面五 初始化激活提示
    time.sleep(3)
    dlgcc = Desktop(backend="uia").window(title=u"初始化激活提示")
    # 获取窗体坐标
    idc = FromPostion.GetZuoBiao(dlgcc)
    # print idc
    # 获取屏幕大小
    screenWidth, screenHeight = pyautogui.size()
    # 获取当前鼠标位置
    currentMouseX, currentMouseY = pyautogui.position()

    # 激活对话框窗体操作
    # 激活对话框窗体操作
    def TuiChu():
        time.sleep(1)
        # 移动鼠标到指定位置
        pyautogui.moveTo(idc[0] + 130, idc[1] + 150)
        # 鼠标点击事件
        pyautogui.click()
        return

    TuiChu()
    return
Пример #17
0
# coding=utf-8
from subprocess import Popen
from pywinauto import Desktop
from pc_test_tool import *

Popen(r"D:\Program Files\DuoLaBao\bin\BasePay.exe", shell=True)
window = Desktop(backend="uia").window(title=u'哆啦宝')
# window.print_ctrl_ids()
# window.print_control_identifiers()
# a=window.criteria
window.child_window(auto_id="devSetTable").print_ctrl_ids()

b = window.window()
# 设备类型选择按钮
click_action(window, left=410, top=10)
# 意锐小盒-基础版
click_action(window, left=380, top=40)

# 设备类型选择按钮
click_action(window, left=410, top=10)
# 意锐小盒-基础版
click_action(window, left=380, top=60)

# pyautogui.press('shift')

# 设备类型选择按钮
click_action(window, left=410, top=10)
# 意锐小盒-基础版
click_action(window, left=380, top=80)
Пример #18
0
class TeachingMain(object):
    def __init__(self, configs):
        self.configs = configs
        self.logger = logging.getLogger(self.__class__.__qualname__)
        self.logger.setLevel(logging.DEBUG)
        self.main_win = Desktop(backend="uia").window(
            **self.configs['teachermain']['main']['id'])  # 主窗口

    def capture_dropdown_menu(self):
        '''
        截图:工具栏中各按钮点击后弹出的下拉菜单
        :return:
        '''
        pop_win = self.main_win.window(**self.configs['teachermain']['menu'])
        self.main_win.wait('visible', timeout=5, retry_interval=1)
        # 截图
        self.logger.debug("Capture the dropdown menu.")
        menu_img = pop_win.capture_as_image()  # PIL Image
        # 转换成OpenCV图片
        self.logger.debug("Convert PIL image to OpenCV format.")
        cv_img = cv.cvtColor(np.array(menu_img), cv.COLOR_RGB2BGR)
        return cv_img, pop_win

    def enter_monitor_pane(self):
        '''进入监视视图'''
        self.main_win.window(**self.configs['teachermain']['left_sider']
                             ['monitor_view']).click()
        monitor_pane = self.main_win.window(
            **self.configs['teachermain']['monitor_pane']['id'])
        monitor_pane.wait('visible', timeout=30)
        return monitor_pane

    def capture_monitor_pane(self):
        '''
        截图:客户端桌面的屏幕显示区域
        :return:
        '''
        client_pane = self.main_win.window(
            **self.configs['teachermain']['monitor_pane']['id'])
        if not client_pane.exists():
            client_pane = self.enter_monitor_pane()
        monitor_region = client_pane.window(
            **self.configs['teachermain']['monitor_pane']
            ['monitors']).capture_as_image()
        # PIL图片转OpenCV图片
        img_clients = cv.cvtColor(np.array(monitor_region), cv.COLOR_RGB2BGR)
        return img_clients

    def get_total_clients(self):
        '''
        检测界面中所有的客户端数,包括未上线的
        :return:
        '''
        img = self.capture_monitor_pane()
        lower_color = np.array([100, 43, 46])  # 蓝色
        upper_color = np.array([124, 255, 255])
        hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
        mask_color = cv.inRange(hsv, lower_color, upper_color)
        kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
        wait_contours = cv.dilate(mask_color, kernel, iterations=2)
        cnts = cv.findContours(wait_contours, cv.RETR_EXTERNAL,
                               cv.CHAIN_APPROX_SIMPLE)
        count = len(cnts[1])
        return count

    def get_offline_clients(self):
        '''
        通过阈值,统计未上线数量
        :param img: 客户端显示区域的截图
        :return:
        '''
        img = self.capture_monitor_pane()
        gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
        th = cv.threshold(gray, 1, 255, cv.THRESH_BINARY_INV)[1]
        if self.logger.getEffectiveLevel() == logging.DEBUG:
            img_name = '%s.png' % strftime('%Y%m%d%H%M', localtime(time()))
            full_path = os.path.join(configs['log']['full_path'], img_name)
            cv.imwrite(full_path, th)
        cnts = cv.findContours(th, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
        count = len(cnts[1])
        self.logger.debug("Calc number of offline clients: %s" % count)
        return count

    def preprocess_ip_image(self):
        '''
        IP识别前的图像预处理
        :param img:
        :return:
        '''
        img = self.capture_monitor_pane()
        if self.logger.getEffectiveLevel() == logging.DEBUG:
            full_path = os.path.join(configs['log']['full_path'],
                                     'capture.png')
            cv.imwrite(full_path, img)
        # 去除背景
        img_no_background = cv.threshold(img, 200, 255, cv.THRESH_BINARY)[1]
        # Otsu's二值化
        gray = cv.cvtColor(img_no_background, cv.COLOR_BGR2GRAY)
        ost = cv.threshold(gray, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)[1]
        # laplacian算子
        gray_lap = cv.Laplacian(ost, -1, ksize=3)
        # 寻找轮廓
        cnts = cv.findContours(gray_lap, cv.RETR_EXTERNAL,
                               cv.CHAIN_APPROX_SIMPLE)
        # 将桌面显示区域,以及小点,用白色填充
        for i in range(len(cnts[1])):
            x, y, w, h = cv.boundingRect(cnts[1][i])
            if h > 50:
                gray_lap[y:(y + h), x:(x + w + 10)] = 0
            elif h < 5:
                gray_lap[y:(y + h), x:(x + w)] = 0

        pro_img = cv.threshold(gray_lap, 127, 255, cv.THRESH_BINARY_INV)[1]
        return pro_img

    def string_to_ip(self, text, ip_pattern):
        '''将OCR识别出的字符串,分拆成IP列表'''
        pre_text = ''.join(ip_pattern.split('.')[:3])
        pre_ip = '.'.join(ip_pattern.split('.')[:3])
        ips = text.replace(' ', '').split('\n\n')
        clients = []
        for x in ips:
            self.logger.debug('String: %s' % x)
            digits = ''.join(list(filter(str.isdigit,
                                         x))).replace(pre_text,
                                                      ' ').strip().split(' ')
            ip_array = []
            for client in digits:
                ipaddr = pre_ip + '.' + client
                ip_array.append(ipaddr)
            clients.append(ip_array)
        return clients

    def get_client_ips(self, ip_pattern=configs['tc']['pattern']):
        '''
        检测客户端IP地址
        :param ip_pattern:
        :return: 各行IP组成的列表
        '''
        ip_img = self.preprocess_ip_image()
        if self.logger.getEffectiveLevel() == logging.DEBUG:
            full_path = os.path.join(configs['log']['full_path'], 'pre_ip.png')
            cv.imwrite(full_path, ip_img)
        # OCR识别数字,需采用tesseract 4.0
        ip_str = ocr.image_to_string(ip_img)
        self.logger.debug("IP String: %s" % ip_str)
        # 处理IP字符串
        ip_list = self.string_to_ip(ip_str, ip_pattern)
        self.logger.debug("IP of clients: %s" % ip_list)
        return ip_list

    def get_menu_items(self, cv_img):
        '''识别图片中的菜单项数量'''
        self.logger.debug("Image Process: dilation.")
        lower_color = np.array([100, 43, 46])  # 蓝色
        upper_color = np.array([124, 255, 255])
        hsv = cv.cvtColor(cv_img, cv.COLOR_BGR2HSV)
        mask_color = cv.inRange(hsv, lower_color, upper_color)
        kernel = cv.getStructuringElement(cv.MORPH_RECT, (6, 6))
        img_dilate = cv.dilate(mask_color, kernel, iterations=2)
        if self.logger.getEffectiveLevel() == logging.DEBUG:
            full_path = os.path.join(configs['log']['full_path'], 'menu.png')
            cv.imwrite(full_path, img_dilate)
        self.logger.debug("Get the contours of menu image.")
        cnts = cv.findContours(img_dilate, cv.RETR_EXTERNAL,
                               cv.CHAIN_APPROX_SIMPLE)
        count = len(cnts[1])
        self.logger.debug("Total Menu items: %s" % count)
        return count

    def click_menu_btn(self, item_id, fixed=0):
        '''点击下拉菜单项'''
        cv_img, pop_win = self.capture_dropdown_menu()
        rect = pop_win.rectangle()
        items_num = self.get_menu_items(
            cv_img) - fixed  # 修正【放学】按钮中逗号导致的轮廓增加1的问题
        if item_id > items_num:
            self.logger.error("Index out of range.")
        else:
            mouse_x = int(rect.width() / 2)
            mouse_y = int(rect.height() * (item_id * 2 - 1) / (items_num * 2))
            pop_win.click_input(coords=(mouse_x, mouse_y))  # 点击操作
            self.logger.debug("Coordinates: %s, %s" % (mouse_x, mouse_y))

    def click_launch_app(self):
        '''
        点击【运行应用程序】
        :return:
        '''
        # 点击【远程命令】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnRemoteCommand']].click()
        # 点击
        self.click_menu_btn(
            self.configs['teachermain']['RemoteCommandMenu']['StartApp'])

    def click_launch_webpage(self):
        '''
        点击【打开网页】
        :return:
        '''
        # 点击【远程命令】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnRemoteCommand']].click()
        # 点击
        self.click_menu_btn(
            self.configs['teachermain']['RemoteCommandMenu']['OpenWeb'])

    def get_data_grid_list(self, grid):
        data_list = grid.children()
        items = {}
        for app in data_list:
            if app.friendly_class_name() == 'ListItem':
                items[app.window_text()] = app
        return items

    def add_app(self, runapp_win):
        runapp_win.window(
            **self.configs['teachermain']['run_app']['add_btn']).click()
        add_win = runapp_win.window(
            **self.configs['teachermain']['run_app']['add_pane']['id'])
        add_win.window(
            **self.configs['teachermain']['run_app']['add_pane']
            ['name']).type_keys(
                self.configs['teachermain']['remote_app']['app_name'])
        add_win.window(
            **self.configs['teachermain']['run_app']['add_pane']
            ['excute_path']).type_keys(
                self.configs['teachermain']['remote_app']['app_path'])
        add_win.window(
            **self.configs['teachermain']['run_app']['add_pane']
            ['parameter']).type_keys(
                self.configs['teachermain']['remote_app']['app_arg'])
        add_win.window(**self.configs['teachermain']['run_app']['add_pane']
                       ['window_mode']).click()
        add_win.window(**self.configs['teachermain']['remote_app']
                       ['app_mode']).wrapper_object().click_input()
        add_win.window(**self.configs['teachermain']['run_app']['add_pane']
                       ['ok']).click()
        add_win.wait_not('visible', timeout=10)

    def add_web_page(self, webpage_win):
        webpage_win.window(
            **self.configs['teachermain']['open_webpage']['add_btn']).click()
        add_win = webpage_win.window(
            **self.configs['teachermain']['open_webpage']['add_pane']['id'])
        add_win.window(
            **self.configs['teachermain']['open_webpage']['add_pane']
            ['name']).type_keys(
                self.configs['teachermain']['remote_page']['page_name'])
        add_win.window(
            **self.configs['teachermain']['open_webpage']['add_pane']
            ['page_url']).type_keys(
                self.configs['teachermain']['remote_page']['page_url'])
        add_win.window(**self.configs['teachermain']['open_webpage']
                       ['add_pane']['ok']).click()
        add_win.wait_not('visible', timeout=10)

    def click_remote_run(self, pop_win, item_name, type=0):
        '''
        远程应用中弹出框的操作流程
        :param pop_win:
        :param item_name:
        :param type: 0 运行应用程序,1 打开网页
        :return:
        '''
        # app_name=self.configs['teachermain']['remote_app']['app_name']
        pop_win.wait('visible', timeout=10)
        grid = pop_win.window(
            **self.configs['teachermain']['pop_win']['data_grid'])
        data_list = self.get_data_grid_list(grid)
        if item_name not in data_list.keys():
            if type == 0:
                self.add_app(pop_win)
            if type == 1:
                self.add_web_page(pop_win)
            data_list = self.get_data_grid_list(grid)
        data_list[item_name].click_input()  # 选中
        pop_win.window(**self.configs['teachermain']['pop_win']
                       ['remote_btn']).click()  # 点击【远程执行】
        pop_win.window(
            **self.configs['teachermain']['pop_win']['exit']).click()

    def click_remote_app_run(self, app_name):
        runapp_win = self.main_win.window(
            **self.configs['teachermain']['run_app']['id'])
        runapp_win.wait('visible', timeout=10)
        self.click_remote_run(runapp_win, app_name, 0)

    def click_remote_open_webpage(self, page_name):
        open_webpage_win = self.main_win.window(
            **self.configs['teachermain']['open_webpage']['id'])
        open_webpage_win.wait('visible', timeout=10)
        self.click_remote_run(open_webpage_win, page_name, 1)

    def click_lesson(self, lesson_name):
        lesson_win = Desktop(backend="uia").window(
            **self.configs['lesson_win']['id'])
        lesson_win.wait('visible', timeout=30)
        lessons = self.get_lesson_list(lesson_win)
        for lesson in lessons.keys():
            #self.logger.debug("Lesson: %s." % lesson)
            if lesson_name == lesson:
                if len(lessons) > 1:  # 单个课程,不需点击
                    lessons[lesson_name].click()
                dialog_confirm = lesson_win.window(
                    **self.configs['lesson_win']['confirm']['id'])
                dialog_confirm.window(
                    **self.configs['lesson_win']['confirm']['ok']).click()
                lesson_win.wait_not('visible', timeout=60)
            elif lesson_name in lesson and '\r\n(上课中...)' in lesson:
                self.logger.debug("%s is working." % lesson_name)
                lesson_win.window(
                    **self.configs['lesson_win']['exit']).click()  # 关闭
            elif len(lessons) == 1:  # 单个课程,且课程名称不匹配情况
                dialog_confirm = lesson_win.window(
                    **self.configs['lesson_win']['confirm']['id'])
                dialog_confirm.window(
                    **self.configs['lesson_win']['confirm']['ng']).click()
                lesson_win.wait_not('visible', timeout=60)
            else:
                self.logger.debug("%s in config doesnot exists." % lesson_name)

    def get_lesson_list(self, lesson_win):
        '''课程选择窗口 \r\n(上课中...) '''
        lesson_list = lesson_win.window(
            **self.configs['lesson_win']['pane']['id']).children()
        lessons = {}
        for lesson in lesson_list:
            if lesson.class_name() == 'Button':
                lessons[lesson.window_text()] = lesson
        return lessons

    def start_lesson(self, lesson_name):
        ''' 上课 '''
        # 点击【课程控制】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnLesson']].click()
        # 点击【上课】
        self.click_menu_btn(self.configs['teachermain']['LessonMenu']['Start'])
        # 点击相应课程
        self.click_lesson(lesson_name)
        lesson_win = Desktop(backend="uia").window(
            **self.configs['lesson_win']['id'])
        lesson_win.wait_not('visible', timeout=60)

    def stop_lesson(self):
        ''' 下课 '''
        # 点击【课程控制】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnLesson']].click()
        # 点击【下课】
        self.click_menu_btn(self.configs['teachermain']['LessonMenu']['Stop'])
        #
        lesson_win = Desktop(backend="uia").window(
            **self.configs['lesson_win']['id'])
        dialog_confirm = lesson_win.window(
            **self.configs['lesson_win']['confirm']['id'])
        dialog_confirm.window(
            **self.configs['lesson_win']['confirm']['ok']).click()
        #sleep(60)
        #lesson_win.wait_not('visible', timeout=60)

    def restart_lesson(self):
        # 点击【课程控制】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnLesson']].click()
        # 点击【重启】
        self.click_menu_btn(
            self.configs['teachermain']['LessonMenu']['Restart'])
        lesson_win = Desktop(backend="uia").window(
            **self.configs['lesson_win']['id'])
        dialog_confirm = lesson_win.window(
            **self.configs['lesson_win']['confirm']['id'])
        dialog_confirm.window(
            **self.configs['lesson_win']['confirm']['ok']).click()
        #lesson_win.wait_not('visible', timeout=60)

    def click_class_over(self):
        # 点击【课程控制】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnLesson']].click()
        # 点击【放学】
        self.click_menu_btn(
            self.configs['teachermain']['LessonMenu']['ClassOver'])
        lesson_win = Desktop(backend="uia").window(
            **self.configs['lesson_win']['id'])
        dialog_confirm = lesson_win.window(
            **self.configs['lesson_win']['confirm']['id'])
        dialog_confirm.window(
            **self.configs['lesson_win']['confirm']['ok']).click()
        #lesson_win.wait_not('visible', timeout=60)

    def click_switch_local_mode(self):
        # 点击【课程控制】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnLesson']].click()
        # 点击【本地考试模式】
        self.click_menu_btn(
            self.configs['teachermain']['LessonMenu']['ExamMode'])
        lesson_win = Desktop(backend="uia").window(
            **self.configs['lesson_win']['id'])
        dialog_confirm = lesson_win.window(
            **self.configs['lesson_win']['confirm']['id'])
        dialog_confirm.window(
            **self.configs['lesson_win']['confirm']['ok']).click()
        #lesson_win.wait_not('visible', timeout=60)

    def click_tc_power_btn(self, btn):
        ''' 点击电源管理下的菜单按钮 '''
        # 点击【电源控制】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnPower']].click()
        #
        cv_img, pop_win = self.capture_dropdown_menu()
        self.click_menu_btn(btn)

    def click_clients_poweroff(self):
        ''' 关机终端 '''
        self.click_tc_power_btn(
            self.configs['teachermain']['PowerMenu']['Poweroff'])

    def click_clients_wakeup(self):
        ''' 唤醒终端 '''
        self.click_tc_power_btn(
            self.configs['teachermain']['PowerMenu']['Wakeup'])

    def click_clients_restart(self):
        ''' 重启终端 '''
        self.click_tc_power_btn(
            self.configs['teachermain']['PowerMenu']['Restart'])

    def click_host_wakeup(self):
        ''' 唤醒主机 '''
        self.click_tc_power_btn(
            self.configs['teachermain']['PowerMenu']['Wakeup_host'])

    def click_black_screen(self):
        ''' 点击【黑屏安静】
        :return:
        '''
        self.main_win[self.configs['teachermain']['RightSider']['toolbox']
                      ['BtnBlackScreen']].click()

    def click_cancel_black_screen(self):
        ''' 点击【取消黑屏安静】
        :return:
        '''
        self.main_win[self.configs['teachermain']['RightSider']['toolbox']
                      ['BtnCancelBlack']].click()

    def get_logon_time(self, timeout, offline=0):
        '''
        所有桌面全登录的时间计时
        :param timeout:
        :return:
        '''
        start_time = time()
        while True:
            end_time = time()
            total_time = end_time - start_time
            if self.get_offline_clients() == offline:
                break
            elif timeout > total_time:
                continue
            else:
                total_time = None
                self.logger.warning("timeout!")
                break
        return total_time

    def img_template_match(self, src, tpl):
        template = cv.imread(tpl, 0)
        w, h = template.shape[:2]

        img = cv.threshold(src, 200, 255, cv.THRESH_BINARY)[1]
        kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
        wait_contours = cv.dilate(img, kernel, iterations=1)
        gray = cv.cvtColor(wait_contours, cv.COLOR_BGR2GRAY)
        bin = cv.threshold(gray, 127, 255, cv.THRESH_BINARY)[1]
        gray_lap = cv.Laplacian(bin, -1, ksize=3)
        # cv.imshow('test1', gray_lap)
        cnts = cv.findContours(gray_lap, cv.RETR_EXTERNAL,
                               cv.CHAIN_APPROX_SIMPLE)
        copy = src.copy()
        num = 0
        for i in range(len(cnts[1])):
            x, y, w, h = cv.boundingRect(cnts[1][i])
            if h > 30:
                crop = copy[y:(y + h), x:(x + w)]
                crop_gray = cv.cvtColor(crop, cv.COLOR_BGR2GRAY)
                res = cv.matchTemplate(crop_gray, template,
                                       cv.TM_CCOEFF_NORMED)
                threshold = 0.8  # 匹配程度大于%80的坐标y,x

                # 3.这边是Python/Numpy的知识,后面解释
                loc = np.where(res >= threshold)
                for pt in zip(*loc[::-1]):  # *号表示可选参数
                    # right_bottom = (pt[0] + w, pt[1] + h)
                    # cv.rectangle(img_rgb, pt, right_bottom, (0, 0, 255), 2)
                    num += 1
                    break
                    # cv.imshow(r'test', crop)
        return num

    def get_quiet_num(self):
        '''
        检测黑屏安静图标的数量
        :return:
        '''
        origin = self.capture_monitor_pane()
        template = os.path.join(configs['img']['full_path'],
                                configs['img']['quiet'])
        num = self.img_template_match(origin, template)
        return num

    def get_remote_app_start_num(self):
        '''
        检测远程程序启动的数量,应用与素材必须一一匹配
        :return:
        '''
        origin = self.capture_monitor_pane()
        template = os.path.join(configs['img']['full_path'],
                                configs['img']['app'])
        num = self.img_template_match(origin, template)
        return num

    def get_remote_page_start_num(self):
        '''
        检测远程网页打开的数量,页面与素材必须一一匹配
        :return:
        '''
        origin = self.capture_monitor_pane()
        template = os.path.join(configs['img']['full_path'],
                                configs['img']['app'])
        num = self.img_template_match(origin, template)
        return num

    def click_enter_portal(self):
        '''
        点击【云校园】
        :return:
        '''
        # 点击【云校园】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnPortabl']].click()
        IvyCloud_win = Desktop(backend="uia").window(
            **self.configs['portal']['id'])
        IvyCloud_win.wait('visible', timeout=30)

    def click_enter_workspace(self):
        '''
        点击【作业空间】
        :return:
        '''
        # 点击【作业空间】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnWorkspace']].click()
        Workspace_win = Desktop(backend="uia").window(
            **self.configs['workspace']['id'])
        Workspace_win.wait('visible', timeout=30)

    def click_forbidden_net(self):
        '''
        点击【禁网】
        :return:
        '''
        # 点击【禁网】
        self.main_win[self.configs['teachermain']['toolbar']
                      ['BtnForbiddenNet']].click()

    def enter_policy_pane(self):
        '''进入策略视图'''
        self.main_win.window(**self.configs['teachermain']['left_sider']
                             ['policy_view']).click()
        policy_pane = self.main_win.window(
            **self.configs['teachermain']['policy_pane']['id'])
        policy_pane.wait('visible', timeout=30)
        return policy_pane

    def add_policy_item(self, policy_win, black=True):
        '''策略添加窗口中添加策略'''
        # 进入添加窗口
        policy_win.window(**self.configs['teachermain']['policy_pane']
                          ['advance_win']['tab']['add_btn']).click()
        add_win = policy_win.window(
            **self.configs['teachermain']['policy_pane']['advance_win']
            ['add_win']['id'])
        add_win.wait('visible', timeout=30)
        # 添加策略
        if black:
            add_win.window(**self.configs['teachermain']['policy_pane']
                           ['advance_win']['add_win']['url']).type_keys(
                               configs['teachermain']['policy_black']['url'])
            add_win.window(
                **self.configs['teachermain']['policy_pane']['advance_win']
                ['add_win']['description']).type_keys(
                    configs['teachermain']['policy_black']['description'])
        else:
            add_win.window(**self.configs['teachermain']['policy_pane']
                           ['advance_win']['add_win']['url']).type_keys(
                               configs['teachermain']['policy_white']['url'])
            add_win.window(
                **self.configs['teachermain']['policy_pane']['advance_win']
                ['add_win']['description']).type_keys(
                    configs['teachermain']['policy_white']['description'])
        add_win.window(**self.configs['teachermain']['policy_pane']
                       ['advance_win']['add_win']['ok']).click()

    def add_white_black_policy(self, black=True):
        '''添加黑白名单策略'''
        # 进入策略视图
        policy_pane = self.enter_policy_pane()
        policy_pane.window(**self.configs['teachermain']['policy_pane']
                           ['toolbar']['advance_btn']).click()
        # 网页限制窗口
        policy_win = self.main_win.window(
            **self.configs['teachermain']['policy_pane']['advance_win']['id'])
        policy_win.wait('visible', timeout=30)
        # 判断黑白名单
        if black:
            policy_win.window(
                **self.configs['teachermain']['policy_pane']['advance_win']
                ['black_tab']).wrapper_object().click_input()
        # 添加策略
        self.add_policy_item(policy_win, black)
        # 保存策略
        policy_win.window(**self.configs['teachermain']['policy_pane']
                          ['advance_win']['btn_dialog']['ok_btn']).click()

    def apply_whitelist_policy(self):
        '''应用白名单'''
        policy_pane = self.enter_policy_pane()
        policy_pane.window(**self.configs['teachermain']['policy_pane']
                           ['toolbar']['whitelist_btn']).click()

    def apply_blacklist_policy(self):
        '''应用黑名单'''
        policy_pane = self.enter_policy_pane()
        policy_pane.window(**self.configs['teachermain']['policy_pane']
                           ['toolbar']['blacklist_btn']).click()

    def apply_allopen_policy(self):
        '''应用全部开放'''
        policy_pane = self.enter_policy_pane()
        policy_pane.window(**self.configs['teachermain']['policy_pane']
                           ['toolbar']['allopen_btn']).click()

    def get_clients_policy(self):
        policy_pane = self.enter_policy_pane()
        clients_pane = policy_pane.window(
            **self.configs['teachermain']['policy_pane']['clients_grid'])
        items = self.get_data_grid_list(clients_pane)
        return items

    def is_all_policy(self, policy_name):
        '''所有客户端策略是否相同'''
        items = self.get_clients_policy()
        policy_num = sum([policy_name in x.texts() for x in items.values()])
        return policy_num == len(items)

    def is_all_blacklist(self):
        return self.is_all_policy(self.configs['teachermain']['policy_pane']
                                  ['policy_status']['blacklist'])

    def is_all_whitelist(self):
        return self.is_all_policy(self.configs['teachermain']['policy_pane']
                                  ['policy_status']['whitelist'])

    def is_all_allopen(self):
        return self.is_all_policy(self.configs['teachermain']['policy_pane']
                                  ['policy_status']['allopen'])