def __init__(self, root, locator): '''constructor :param root: parent control or window :param locator: control locator ''' self._root = root self._locator = locator self._driver = root.get_driver() self._proxy = LazyInit(self, "_proxy", self._init_proxy)
def __init__(self, root=None, locator=None): '''构造函数 :type root: UIA.Control or None :param root: 开始查找的UIA控件或包含UIA的win32control.Window; :type locator: str or qt4c.qpath.QPath(后面支持) :param locator: UIA控件的name属性 or qpath(后面支持) :attention: 参数root和locator不能同时为None ''' control.Control.__init__(self) if locator is None and root is None: raise RuntimeError("传入参数locator和root不能同时为None!") self._root = root self._locator = locator self._uiaobj = LazyInit(self, '_uiaobj', self._init_uiaobj)
def __init__(self, root, locator, **ext): '''构造函数 :param root: 父对象(多态:最顶层是App实例对象) :type root: App | Element :param locator: 定位描述(多态:可以直接是element的id),如果为None则指向_root对象 :type locator: QPath | str(QPath) | int已定位到的element的ID ''' ControlContainer.__init__(self) if ext: self.user_name = ext['id'] self._app = None self._root = root self._locator = locator # -*- -*- -*- if not isinstance(self._root, (App, Element)): raise Exception('element.root is invalid') if self._locator is not None and not isinstance( self._locator, (QPath, basestring, int)): raise Exception('element.locator is invalid') # -*- -*- -*- root = self._root while True: if isinstance(root, App): self._app = root break root = root._root if not isinstance(self._app, App): raise Exception('element.app is invalid') # -*- -*- -*- self._check_locator(self._locator) # -*- -*- -*- self._element = LazyInit(self, '_element', self._init_element)
def __init__(self, app): self._app = app self._driver = app.get_driver() self._locators = {} self._proxy = LazyInit(self, "_proxy", self._init_proxy)
class Window(object): '''Window ''' timeout = 4 interval = 0.5 NAME = None def __init__(self, app): self._app = app self._driver = app.get_driver() self._locators = {} self._proxy = LazyInit(self, "_proxy", self._init_proxy) def _init_proxy(self): t0 = time.time() while time.time() - t0 < self.timeout: if self.NAME is None: raise ValueError("NAME of class \"%s\" is not set" % type(self)) control_id = self._driver.get_window_by_name(self.NAME) if control_id: return ControlProxy(self._driver, control_id) time.sleep(self.interval) raise ControlNotFoundError("window with name \"%s\" not found" % self.NAME) def __getitem__(self, key): if not self._locators.has_key(key): raise RuntimeError("child control of name \"%s\" is not defined" % key) params = self._locators.get(key) if isinstance(params, basestring): params = {"root": self, "type": Control, "locator": params} else: params["root"] = params.get("root", self) params["type"] = params.get("type", Control) root = params["root"] if isinstance(root, basestring) and re.match('^@', root): root_key = re.sub('^@', '', root) params["root"] = self.controls[root_key] ctrl_class = params.pop("type") return ctrl_class(**params) @property def id(self): '''control id ''' return self._proxy.id @property def app(self): '''belonging app ''' return self._app @property def title(self): '''window title ''' return self._proxy.get_attr("title") @property def controls(self): '''children control retriever ''' return self def get_driver(self): '''get test driver ''' return self._driver def update_locator(self, locators): '''update UI locator(UI map) ''' self._locators.update(locators) def exist(self): '''window existence ''' if self.NAME is None: raise ValueError("NAME of class \"%s\" is not set" % type(self)) control_id = self._driver.get_window_by_name(self.NAME) if control_id: return True else: return False def wait_for_exist(self, timeout, interval): '''wait for control existence ''' Timeout(timeout, interval).retry(self.exist, (), None, lambda x: x == True) def wait_for_value(self, timeout, interval, attrname, attrval): '''wait for control attribute value ''' Timeout(timeout, interval).retry(lambda: getattr(self, attrname), (), None, lambda x: x == attrval)
class Control(object): '''Control ''' def __init__(self, root, locator): '''constructor :param root: parent control or window :param locator: control locator ''' self._root = root self._locator = locator self._driver = root.get_driver() self._proxy = LazyInit(self, "_proxy", self._init_proxy) def _init_proxy(self): if isinstance(self._locator, basestring): control_ids = self._driver.find_controls_by_name( self._root.id, self._locator) elif isinstance(self._locator, int): control_ids = [self._locator] elif isinstance(self._locator, QPath): control_ids = self._driver.find_controls(self._root.id, self._locator.dumps()[0]) else: raise TypeError() if control_ids: if len(control_ids) == 1: return ControlProxy(self._driver, control_ids[0]) else: raise ControlAmbiguousError() else: raise ControlNotFoundError() @property def id(self): '''control id ''' return self._proxy.id @property def name(self): return self._proxy.get_attr("name") def get_driver(self): '''get test driver ''' return self._driver def exist(self): '''control existence ''' if not self._root.exist(): return False if isinstance(self._locator, basestring): control_ids = self._driver.find_controls_by_name( self._root.id, self._locator) elif isinstance(self._locator, QPath): control_ids = self._driver.find_controls(self._root.id, self._locator.dumps()) else: raise TypeError() if control_ids: return True else: return False def wait_for_exist(self, timeout, interval): '''wait for control existence ''' Timeout(timeout, interval).retry(self.exist, (), None, lambda x: x == True) def wait_for_value(self, timeout, interval, attrname, attrval): '''wait for control attribute value ''' Timeout(timeout, interval).retry(lambda: getattr(self, attrname), (), None, lambda x: x == attrval)
class Control(control.Control): ''' UIA方式访问控件基类 ''' def __init__(self, root=None, locator=None): '''构造函数 :type root: UIA.Control or None :param root: 开始查找的UIA控件或包含UIA的win32control.Window; :type locator: str or qt4c.qpath.QPath(后面支持) :param locator: UIA控件的name属性 or qpath(后面支持) :attention: 参数root和locator不能同时为None ''' control.Control.__init__(self) if locator is None and root is None: raise RuntimeError("传入参数locator和root不能同时为None!") self._root = root self._locator = locator self._uiaobj = LazyInit(self, '_uiaobj', self._init_uiaobj) def _init_uiaobj(self): '''初始化uia对象 ''' if self._root is None: self._root = Control(root=UIAutomationClient.GetRootElement()) self._root.empty_invoke() if isinstance(self._root, wincontrols.Control): pid = self._root.ProcessId if not pid or not self._root.Valid: raise ControlExpiredError("父控件/父窗口已经失效,查找中止!") if self._locator is None: cnd = UIAutomationClient.CreatePropertyCondition( IUIAutomation.UIA_NativeWindowHandlePropertyId, self._root.HWnd) self._root = find_UIAElm(cnd) if self._locator is None: if isinstance(self._root, Control): self._root.empty_invoke() elm = self._root._uiaobj elif isinstance(self._root, IUIAutomation.IUIAutomationElement): elm = self._root else: raise TypeError( "root应为uiacontrols.Control类型或者UIA element,实际类型为:%s" % type(self._root)) else: if isinstance(self._locator, six.string_types): if isinstance(self._root, Control): args = (self._root, self._locator) try: from qt4c.qpath import _find_by_name foundctrl = self._timeout.retry( _find_by_name, args, (ControlNotFoundError)) foundctrl.empty_invoke() elm = foundctrl._uiaobj except TimeoutError: raise ControlNotFoundError("找不到name为 (%s)的UIA子控件!" % self._locator) else: raise TypeError("root应为uiacontrols.Control类型,实际类型为:%s" % type(self._root)) else: try: kwargs = {'root': self._root} foundctrls = self._timeout.retry(self._locator.search, kwargs, (), lambda x: len(x) > 0) except TimeoutError as erro: raise ControlNotFoundError( "<%s>中的%s查找超时:%s" % (self._root, self._locator.getErrorPath(), erro)) nctrl = len(foundctrls) if (nctrl > 1): raise ControlAmbiguousError("<%s>找到%d个控件" % (self._locator, nctrl)) foundctrls[0].empty_invoke() elm = foundctrls[0]._uiaobj return elm def empty_invoke(self): '''无意义调用,用于主动初始化对象 ''' self._uiaobj.CurrentName def SetFocus(self): self._uiaobj.SetFocus() #这个接口没有作用 @property def Valid(self): """是否是有效控件 """ return self.Enabled @property def Width(self): """控件宽度 """ rect = self._getrect() return rect['Width'] @property def Height(self): """控件高度 """ rect = self._getrect() return rect['Height'] @property def BoundingRect(self): """返回控件 """ rect = self._getrect() return Rectangle((int(rect['Left']), int(rect['Top']), int(rect['Left'] + rect['Width']), int(rect['Top'] + rect['Height']))) def _getrect(self): rect = {'Left': 0, 'Top': 0, 'Width': 0, 'Height': 0} (rect['Left'], rect['Top'], rect['Width'], rect['Height']) = self._uiaobj.GetCurrentPropertyValue( IUIAutomation.UIA_BoundingRectanglePropertyId) return rect def click(self, mouseFlag=MouseFlag.LeftButton, clickType=MouseClickType.SingleClick, xOffset=None, yOffset=None): """点击控件 :type mouseFlag:qt4c.mouse.MouseFlag :param mouseFlag: 鼠标按钮类型 :type clickType:qt4c.mouse.MouseClickType :param clickType:点击动作类型 :type xOffset:int :param 横向偏移量 :type yOffset:int :param 纵向偏移量 """ Timeout(5, 0.5).waitObjectProperty(self, 'Enabled', True) x, y = self._getClickXY(xOffset, yOffset) Mouse.click(int(x), int(y), mouseFlag, clickType) @property def ProcessId(self): pid = self._uiaobj.GetCurrentPropertyValue( IUIAutomation.UIA_ProcessIdPropertyId) return pid @property def ControlType(self): """返回UIA控件的类型 """ typeint = self._uiaobj.GetCurrentPropertyValue( IUIAutomation.UIA_ControlTypePropertyId) return UIAControlType[typeint] @property def Enabled(self): """此控件是否可用 """ return self._uiaobj.GetCurrentPropertyValue( IUIAutomation.UIA_IsEnabledPropertyId) @property def Children(self): """返回子控件列表 :rtype ListType """ self.empty_invoke() children = [] child = RawWalker.GetFirstChildElement(self._uiaobj) while (child != None): try: child.CurrentName #测试uiaelm对象是否有效 children.append(Control(root=child)) child = RawWalker.GetNextSiblingElement(child) except ValueError: child = None return children @property def Parent(self): self.empty_invoke() parent = RawWalker.GetParentElement(self._uiaobj) try: parent.CurrentName #测试uia elm对象是否有效 except ValueError: parent = None else: return Control(root=parent) @property def Name(self): """返回control的name属性 """ return self._uiaobj.CurrentName @property def Type(self): """返回控件类型 """ return self._uiaobj.CurrentLocalizedControlType @property def Value(self): """返回控件value属性(通常是文本信息) """ return self._uiaobj.GetCurrentPropertyValue( IUIAutomation.UIA_LegacyIAccessibleValuePropertyId) def equal(self, other): if not isinstance(other, Control): return False if self.ProcessId != other.ProcessId: return False return self._uiaobj == other._uiaobj def exist(self): """判断控件是否存在 """ try: self._init_uiaobj() except Exception as e: print("判断UIA控件存在失败,UIA elm实例化异常:%s" % e) return False return True def wait_for_exist(self, timeout, interval): """等待控件存在 """ Timeout(timeout, interval).retry(self.exist, (), (), lambda x: x == True) @property def Hwnd(self): """返回控件句柄 """ return self.hwnd @property def HWnd(self): """兼容其他类型控件 """ return self.hwnd @property def hwnd(self): return self._uiaobj.CurrentNativeWindowHandle @property def HasKeyboardFocus(self): """返回是否被选为键盘输入 """ return self._uiaobj.CurrentHasKeyboardFocus @property def ClassName(self): """返回ClassName """ return self._uiaobj.CurrentClassName