Added unit tests, changed from properties to methods
added more granularity to many controls
This commit is contained in:
parent
f44d83ab67
commit
c9e84c7567
@ -112,6 +112,7 @@ class HwndWrapper(object):
|
||||
friendlyclassname = ''
|
||||
handle = None
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def __init__(self, hwnd):
|
||||
"Initialize the control"
|
||||
# handle if hwnd is actually a HwndWrapper
|
||||
@ -120,12 +121,6 @@ class HwndWrapper(object):
|
||||
except AttributeError:
|
||||
self.handle = hwnd
|
||||
|
||||
if not self.friendlyclassname:
|
||||
self.FriendlyClassName = handleprops.classname(hwnd)
|
||||
else:
|
||||
self.FriendlyClassName = self.friendlyclassname
|
||||
|
||||
|
||||
# verify that we have been passed in a valid windows handle
|
||||
if not win32functions.IsWindow(hwnd):
|
||||
raise InvalidWindowHandle(hwnd)
|
||||
@ -137,128 +132,149 @@ class HwndWrapper(object):
|
||||
# when asked for properties
|
||||
self._NeedsImageProp = False
|
||||
|
||||
# set the friendly class name to default to
|
||||
# the class name
|
||||
self._extra_clientrects = []
|
||||
self._extra_props = {}
|
||||
|
||||
self._extra_props['MenuItems'] = self.MenuItems
|
||||
|
||||
# if it is a main window
|
||||
#if self.IsDialog:
|
||||
# self.FriendlyClassName = "Dialog"
|
||||
|
||||
# default to not having a reference control added
|
||||
self.ref = None
|
||||
|
||||
|
||||
#FriendlyClassName = property(
|
||||
# handleprops.friendlyclassname,
|
||||
# doc = "FriendlyClassName of the window ")
|
||||
#-----------------------------------------------------------
|
||||
def FriendlyClassName(self):
|
||||
"Return the friendly class name for the control"
|
||||
if not self.friendlyclassname:
|
||||
return handleprops.classname(self)
|
||||
else:
|
||||
return self.friendlyclassname
|
||||
|
||||
#-----------------------------------------------------------
|
||||
#def _get_classname(self):
|
||||
# try:
|
||||
# return self._class_name
|
||||
# except AttributeError:
|
||||
# return handleprops.classname(self)
|
||||
def Class(self):
|
||||
"Class Name of the window"
|
||||
return handleprops.classname(self)
|
||||
|
||||
Class = property (handleprops.classname,
|
||||
doc = "Class Name of the window")
|
||||
#-----------------------------------------------------------
|
||||
def Text(self):
|
||||
"Main text of the control"
|
||||
return handleprops.text(self)
|
||||
|
||||
Text = property (handleprops.text,
|
||||
doc = "Main text of the control")
|
||||
Style = property (handleprops.style,
|
||||
doc = "Style of window")
|
||||
ExStyle = property (handleprops.exstyle,
|
||||
doc = "Extended Style of window")
|
||||
ControlID = property (handleprops.controlid,
|
||||
doc = "The ID of the window")
|
||||
UserData = property (handleprops.userdata,
|
||||
doc = "Extra data associted with the window")
|
||||
ContextHelpID = property (handleprops.contexthelpid,
|
||||
doc = "The Context Help ID of the window")
|
||||
IsVisible = property (handleprops.isvisible,
|
||||
doc = "Whether the window is visible or not")
|
||||
IsUnicode = property (handleprops.isunicode,
|
||||
doc = "Whether the window is unicode or not")
|
||||
IsEnabled = property (handleprops.isenabled,
|
||||
doc = "Whether the window is enabled or not")
|
||||
#-----------------------------------------------------------
|
||||
def Style(self):
|
||||
"Style of window"
|
||||
return handleprops.style(self)
|
||||
|
||||
Rectangle = property (handleprops.rectangle,
|
||||
doc = "Rectangle of window")
|
||||
ClientRect = property (handleprops.clientrect,
|
||||
doc = "Client rectangle of window")
|
||||
#-----------------------------------------------------------
|
||||
def ExStyle(self):
|
||||
"Extended Style of window"
|
||||
return handleprops.exstyle(self)
|
||||
|
||||
Font = property (handleprops.font, doc = "The font of the window")
|
||||
#-----------------------------------------------------------
|
||||
def ControlID(self):
|
||||
"The ID of the window"
|
||||
return handleprops.controlid(self)
|
||||
|
||||
ProcessID = property (handleprops.processid,
|
||||
doc = "ID of process that controls this window")
|
||||
#-----------------------------------------------------------
|
||||
def UserData(self):
|
||||
"Extra data associted with the window"
|
||||
return handleprops.userdata(self)
|
||||
|
||||
HasStyle = handleprops.has_style
|
||||
HasExStyle = handleprops.has_exstyle
|
||||
#-----------------------------------------------------------
|
||||
def ContextHelpID(self):
|
||||
"The Context Help ID of the window"
|
||||
return handleprops.contexthelpid(self)
|
||||
|
||||
IsDialog = property(handleprops.is_toplevel_window,
|
||||
doc = handleprops.is_toplevel_window.__doc__)
|
||||
#-----------------------------------------------------------
|
||||
def IsVisible(self):
|
||||
"Whether the window is visible or not"
|
||||
return handleprops.isvisible(self)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def IsUnicode(self):
|
||||
"Whether the window is unicode or not"
|
||||
return handleprops.isunicode(self)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def IsEnabled(self):
|
||||
"Whether the window is enabled or not"
|
||||
return handleprops.isenabled(self)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def Rectangle(self):
|
||||
"Rectangle of window"
|
||||
return handleprops.rectangle(self)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def ClientRect(self):
|
||||
"Client rectangle of window"
|
||||
return handleprops.clientrect(self)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def Font(self):
|
||||
"The font of the window"
|
||||
return handleprops.font(self)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def ProcessID(self):
|
||||
"ID of process that controls this window"
|
||||
return handleprops.processid(self)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def HasStyle(self, style):
|
||||
"Retrun true if the control has the specified sytle"
|
||||
return handleprops.has_style(self, style)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def HasExStyle(self, exstyle):
|
||||
"Retrun true if the control has the specified extended sytle"
|
||||
return handleprops.has_exstyle(self, exstyle)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def IsDialog(self):
|
||||
"Retrun true if the control is a top level window"
|
||||
return handleprops.is_toplevel_window(self)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# define the Menu Property
|
||||
def _get_menuitems(self):
|
||||
def MenuItems(self):
|
||||
"Return the menu items for the dialog"
|
||||
if self.IsDialog:
|
||||
return _GetMenuItems(win32functions.GetMenu(self))
|
||||
if self.IsDialog():
|
||||
menu_handle = win32functions.GetMenu(self)
|
||||
self.SendMessage(win32defines.WM_INITMENU, menu_handle)
|
||||
return _GetMenuItems(menu_handle, self)
|
||||
else:
|
||||
return []
|
||||
MenuItems = property (_get_menuitems,
|
||||
doc = "Return the menu items for the dialog")
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _get_parent(self):
|
||||
def Parent(self):
|
||||
"Return the parent of this control"
|
||||
parent_hwnd = handleprops.parent(self)
|
||||
|
||||
|
||||
if parent_hwnd:
|
||||
return WrapHandle(parent_hwnd)
|
||||
else:
|
||||
return None
|
||||
Parent = property (_get_parent,
|
||||
doc = "Parent window of window")
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _get_texts(self):
|
||||
def Texts(self):
|
||||
"Return the text for each item of this control"
|
||||
texts = [self.Text, ]
|
||||
texts = [self.Text(), ]
|
||||
return texts
|
||||
Texts = property (_get_texts, doc = "All text items of the control")
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# TODO: Make _extra_clientrects a property/method of the class
|
||||
# rather then a property that is set at initialization
|
||||
def _get_clientrects(self):
|
||||
def ClientRects(self):
|
||||
"Return the client rect for each item in this control"
|
||||
|
||||
clientrects = [self.ClientRect, ]
|
||||
clientrects.extend(self._extra_clientrects)
|
||||
return clientrects
|
||||
ClientRects = property (
|
||||
_get_clientrects, doc = "All client rectanbgles of the control")
|
||||
return [self.ClientRect(), ]
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _get_fonts(self):
|
||||
def Fonts(self):
|
||||
"Return the font for each item in this control"
|
||||
return [self.Font, ]
|
||||
Fonts = property (_get_fonts, doc = "All fonts of the control")
|
||||
return [self.Font(), ]
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _get_children(self):
|
||||
def Children(self):
|
||||
"Return the children of this control"
|
||||
|
||||
# this will be filled in the callback function
|
||||
child_windows = handleprops.children(self)
|
||||
return [WrapHandle(hwnd) for hwnd in child_windows]
|
||||
|
||||
Children = property (_get_children, doc = "The list of children")
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def IsChild(self, parent):
|
||||
@ -281,11 +297,12 @@ class HwndWrapper(object):
|
||||
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def SendMessageTimeout(self, message, wparam = 0 , lparam = 0, timeout = .4):
|
||||
"Send a message to the control and wait for it to return or for timout to finish"
|
||||
def SendMessageTimeout(
|
||||
self, message, wparam = 0 , lparam = 0, timeout = .4):
|
||||
"Send a message to the control and wait for it to return or to timeout"
|
||||
|
||||
result = ctypes.c_long()
|
||||
ret = win32functions.SendMessageTimeout(self, message, wparam, lparam,
|
||||
win32functions.SendMessageTimeout(self, message, wparam, lparam,
|
||||
win32defines.SMTO_NORMAL, int(timeout * 1000), ctypes.byref(result))
|
||||
|
||||
return result.value
|
||||
@ -316,40 +333,40 @@ class HwndWrapper(object):
|
||||
def NotifyParent(self, message):
|
||||
"Send the notification message to parent of this control"
|
||||
|
||||
return self.Parent.PostMessage(
|
||||
return self.Parent().PostMessage(
|
||||
win32defines.WM_COMMAND,
|
||||
win32functions.MakeLong(self.ControlID, message),
|
||||
win32functions.MakeLong(self.ControlID(), message),
|
||||
self)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def GetProperties(self):
|
||||
"Return the properties of the control as a dictionary"
|
||||
props = self._extra_props
|
||||
props = {}
|
||||
|
||||
# get the className
|
||||
props['Class'] = self.Class
|
||||
props['Class'] = self.Class()
|
||||
|
||||
# set up the friendlyclass defaulting
|
||||
# to the class Name
|
||||
props['FriendlyClassName'] = self.FriendlyClassName
|
||||
props['FriendlyClassName'] = self.FriendlyClassName()
|
||||
|
||||
props['Texts'] = self.Texts
|
||||
props['Style'] = self.Style
|
||||
props['ExStyle'] = self.ExStyle
|
||||
props['ControlID'] = self.ControlID
|
||||
props['UserData'] = self.UserData
|
||||
props['ContextHelpID'] = self.ContextHelpID
|
||||
props['Texts'] = self.Texts()
|
||||
props['Style'] = self.Style()
|
||||
props['ExStyle'] = self.ExStyle()
|
||||
props['ControlID'] = self.ControlID()
|
||||
props['UserData'] = self.UserData()
|
||||
props['ContextHelpID'] = self.ContextHelpID()
|
||||
|
||||
props['Fonts'] = self.Fonts
|
||||
props['ClientRects'] = self.ClientRects
|
||||
props['Fonts'] = self.Fonts()
|
||||
props['ClientRects'] = self.ClientRects()
|
||||
|
||||
props['Rectangle'] = self.Rectangle
|
||||
props['Rectangle'] = self.Rectangle()
|
||||
|
||||
props['IsVisible'] = self.IsVisible
|
||||
props['IsUnicode'] = self.IsUnicode
|
||||
props['IsEnabled'] = self.IsEnabled
|
||||
props['IsVisible'] = self.IsVisible()
|
||||
props['IsUnicode'] = self.IsUnicode()
|
||||
props['IsEnabled'] = self.IsEnabled()
|
||||
|
||||
#props['MenuItems'] = []
|
||||
props['MenuItems'] = self.MenuItems()
|
||||
|
||||
#if self.IsVisible and self._NeedsImageProp:
|
||||
# print "\t", self.Class
|
||||
@ -361,15 +378,15 @@ class HwndWrapper(object):
|
||||
#-----------------------------------------------------------
|
||||
def CaptureAsImage(self):
|
||||
"Return a PIL image of the dialog"
|
||||
if not (self.Rectangle.width() and self.Rectangle.height()):
|
||||
if not (self.Rectangle().width() and self.Rectangle().height()):
|
||||
return None
|
||||
|
||||
# get the control rectangle in a way that PIL likes it
|
||||
box = (
|
||||
self.Rectangle.left,
|
||||
self.Rectangle.top,
|
||||
self.Rectangle.right,
|
||||
self.Rectangle.bottom)
|
||||
self.Rectangle().left,
|
||||
self.Rectangle().top,
|
||||
self.Rectangle().right,
|
||||
self.Rectangle().bottom)
|
||||
|
||||
# grab the image and get raw data as a string
|
||||
# wrapped in try because PIL is optional
|
||||
@ -404,11 +421,11 @@ class HwndWrapper(object):
|
||||
# check first if it's parent is enabled
|
||||
# (as long as it is not a dialog!)
|
||||
if not self.friendlyclassname == "Dialog":
|
||||
if not self.Parent.IsEnabled:
|
||||
if not self.Parent().IsEnabled():
|
||||
raise ControlNotEnabled()
|
||||
|
||||
# then check if the control itself is enabled
|
||||
if not self.IsEnabled:
|
||||
if not self.IsEnabled():
|
||||
raise ControlNotEnabled()
|
||||
|
||||
#-----------------------------------------------------------
|
||||
@ -418,11 +435,11 @@ class HwndWrapper(object):
|
||||
# check first if it's parent is visible
|
||||
# (as long as it is not a dialog!)
|
||||
if not self.friendlyclassname == "Dialog":
|
||||
if not self.Parent.IsVisible:
|
||||
if not self.Parent().IsVisible():
|
||||
raise ControlNotVisible()
|
||||
|
||||
# then check if the control itself is Visible
|
||||
if not self.IsVisible:
|
||||
if not self.IsVisible():
|
||||
raise ControlNotVisible()
|
||||
|
||||
|
||||
@ -444,8 +461,12 @@ class HwndWrapper(object):
|
||||
_perform_click(self, button, pressed, coords, double)
|
||||
|
||||
waited = 0
|
||||
# verify that we have been passed in a valid windows handle
|
||||
while win32functions.IsWindow(self.handle) and waited < 1.5:
|
||||
# Keep waiting until both this control and it's parent
|
||||
# are no longer valid controls
|
||||
while (win32functions.IsWindow(self) or \
|
||||
win32functions.IsWindow(self.Parent())) and \
|
||||
waited < 1.5:
|
||||
|
||||
time.sleep(.1)
|
||||
waited += .1
|
||||
|
||||
@ -516,7 +537,7 @@ class HwndWrapper(object):
|
||||
self.VerifyActionable()
|
||||
|
||||
if append:
|
||||
text = self.Text + text
|
||||
text = self.Text() + text
|
||||
|
||||
text = ctypes.c_wchar_p(unicode(text))
|
||||
self.PostMessage(win32defines.WM_SETTEXT, 0, text)
|
||||
@ -539,7 +560,7 @@ class HwndWrapper(object):
|
||||
|
||||
# attach the Python process with the process that self is in
|
||||
win32functions.AttachThreadInput(
|
||||
win32functions.GetCurrentThreadId(), self.ProcessID, 1)
|
||||
win32functions.GetCurrentThreadId(), self.ProcessID(), 1)
|
||||
|
||||
# make sure that the control is in the foreground
|
||||
win32functions.SetForegroundWindow(self)
|
||||
@ -554,7 +575,7 @@ class HwndWrapper(object):
|
||||
|
||||
# detach the python process from the window's process
|
||||
win32functions.AttachThreadInput(
|
||||
win32functions.GetCurrentThreadId(), self.ProcessID, 0)
|
||||
win32functions.GetCurrentThreadId(), self.ProcessID(), 0)
|
||||
|
||||
win32functions.WaitGuiThreadIdle(self)
|
||||
return self
|
||||
@ -600,7 +621,7 @@ class HwndWrapper(object):
|
||||
"Draw an outline around the window"
|
||||
|
||||
# don't draw if dialog is not visible
|
||||
if not self.IsVisible:
|
||||
if not self.IsVisible():
|
||||
return
|
||||
|
||||
colours = {
|
||||
@ -614,7 +635,7 @@ class HwndWrapper(object):
|
||||
colour = colours[colour]
|
||||
|
||||
if not rect:
|
||||
rect = self.Rectangle
|
||||
rect = self.Rectangle()
|
||||
|
||||
# create the pen(outline)
|
||||
pen_handle = win32functions.CreatePen(
|
||||
@ -655,7 +676,7 @@ class HwndWrapper(object):
|
||||
# if the menu items haven't been passed in then
|
||||
# get them from the window
|
||||
if not items:
|
||||
items = self.MenuItems
|
||||
items = self.MenuItems()
|
||||
|
||||
# get the text names from the menu items
|
||||
item_texts = [item['Text'] for item in items]
|
||||
@ -757,10 +778,10 @@ def _perform_click(
|
||||
|
||||
# send each message
|
||||
for msg in msgs:
|
||||
ret = ctrl.SendMessageTimeout(msg, flags, click_point)
|
||||
ctrl.SendMessageTimeout(msg, flags, click_point)
|
||||
|
||||
# wait until the thread can accept another message
|
||||
ret = win32functions.WaitGuiThreadIdle(ctrl)
|
||||
win32functions.WaitGuiThreadIdle(ctrl)
|
||||
|
||||
# wait a certain(short) time after the click
|
||||
time.sleep(delay_after_click)
|
||||
@ -792,15 +813,15 @@ def _calc_flags_and_coords(pressed, coords):
|
||||
|
||||
# should really be in win32defines - I don't know why it isnt!
|
||||
#====================================================================
|
||||
def _GetMenuItems(menuHandle):
|
||||
def _GetMenuItems(menu_handle, ctrl):
|
||||
"Get the menu items as a list of dictionaries"
|
||||
# If it doesn't have a real menu just return
|
||||
if not win32functions.IsMenu(menuHandle):
|
||||
if not win32functions.IsMenu(menu_handle):
|
||||
return []
|
||||
|
||||
items = []
|
||||
|
||||
item_count = win32functions.GetMenuItemCount(menuHandle)
|
||||
item_count = win32functions.GetMenuItemCount(menu_handle)
|
||||
|
||||
# for each menu item
|
||||
for i in range(0, item_count):
|
||||
@ -822,7 +843,7 @@ def _GetMenuItems(menuHandle):
|
||||
|
||||
|
||||
ret = win32functions.GetMenuItemInfo (
|
||||
menuHandle, i, True, ctypes.byref(menu_info))
|
||||
menu_handle, i, True, ctypes.byref(menu_info))
|
||||
if not ret:
|
||||
raise ctypes.WinError()
|
||||
|
||||
@ -834,21 +855,28 @@ def _GetMenuItems(menuHandle):
|
||||
# if there is text
|
||||
if menu_info.cch:
|
||||
# allocate a buffer
|
||||
bufferSize = menu_info.cch+1
|
||||
text = (ctypes.c_wchar * bufferSize)()
|
||||
buffer_size = menu_info.cch+1
|
||||
text = ctypes.create_unicode_buffer(buffer_size)
|
||||
|
||||
# update the structure and get the text info
|
||||
menu_info.dwTypeData = ctypes.addressof(text)
|
||||
menu_info.cch = bufferSize
|
||||
menu_info.cch = buffer_size
|
||||
win32functions.GetMenuItemInfo (
|
||||
menuHandle, i, True, ctypes.byref(menu_info))
|
||||
menu_handle, i, True, ctypes.byref(menu_info))
|
||||
item_prop['Text'] = text.value
|
||||
else:
|
||||
item_prop['Text'] = ""
|
||||
|
||||
# if it's a sub menu then get it's items
|
||||
if menu_info.hSubMenu:
|
||||
sub_menu_items = _GetMenuItems(menu_info.hSubMenu)#, indent)
|
||||
# make sure that the app updates the menu if it need to
|
||||
ctrl.SendMessage(
|
||||
win32defines.WM_INITMENUPOPUP, menu_info.hSubMenu, i)
|
||||
|
||||
# get the sub menu items
|
||||
sub_menu_items = _GetMenuItems(menu_info.hSubMenu, ctrl)#, indent)
|
||||
|
||||
# append them
|
||||
item_prop['MenuItems'] = sub_menu_items
|
||||
|
||||
items.append(item_prop)
|
||||
@ -869,12 +897,12 @@ def GetDialogPropsFromHandle(hwnd):
|
||||
# controls on the dialog
|
||||
try:
|
||||
controls = [hwnd, ]
|
||||
controls.extend(hwnd.Children)
|
||||
controls.extend(hwnd.Children())
|
||||
except AttributeError:
|
||||
controls = [WrapHandle(hwnd), ]
|
||||
|
||||
# add all the children of the dialog
|
||||
controls.extend(controls[0].Children)
|
||||
controls.extend(controls[0].Children())
|
||||
|
||||
props = []
|
||||
|
||||
@ -888,7 +916,7 @@ def GetDialogPropsFromHandle(hwnd):
|
||||
ctrl_props.handle = ctrl.handle
|
||||
|
||||
# offset the rectangle from the dialog rectangle
|
||||
ctrl_props['Rectangle'] -= controls[0].Rectangle
|
||||
ctrl_props['Rectangle'] -= controls[0].Rectangle()
|
||||
|
||||
props.append(ctrl_props)
|
||||
|
||||
|
@ -28,7 +28,7 @@ from wraphandle import WrapHandle
|
||||
|
||||
#====================================================================
|
||||
def _unittests():
|
||||
|
||||
"Run some tests on the controls"
|
||||
from pywinauto import win32functions
|
||||
|
||||
"do some basic testing"
|
||||
@ -36,7 +36,6 @@ def _unittests():
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print "blah"
|
||||
handle = win32functions.GetDesktopWindow()
|
||||
else:
|
||||
try:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -48,16 +48,10 @@ class ButtonWrapper(HwndWrapper.HwndWrapper):
|
||||
|
||||
self._set_if_needs_image()
|
||||
|
||||
# default to Button for FriendlyClassName
|
||||
# might be changed later
|
||||
#self.FriendlyClassName = "Button"
|
||||
self.FriendlyClassName = self._friendly_class_name()
|
||||
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _set_if_needs_image(self):
|
||||
"Set the _NeedsImageProp attribute if it is an image button"
|
||||
if self.IsVisible and (\
|
||||
if self.IsVisible() and (\
|
||||
self.HasStyle(win32defines.BS_BITMAP) or \
|
||||
self.HasStyle(win32defines.BS_ICON) or \
|
||||
self.HasStyle(win32defines.BS_OWNERDRAW)):
|
||||
@ -65,27 +59,27 @@ class ButtonWrapper(HwndWrapper.HwndWrapper):
|
||||
self._NeedsImageProp = True
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _friendly_class_name(self):
|
||||
def FriendlyClassName(self):
|
||||
|
||||
# get the least significant bit
|
||||
StyleLSB = self.Style & 0xF
|
||||
style_lsb = self.Style() & 0xF
|
||||
|
||||
f_class_name = 'Button'
|
||||
|
||||
if StyleLSB == win32defines.BS_3STATE or \
|
||||
StyleLSB == win32defines.BS_AUTO3STATE or \
|
||||
StyleLSB == win32defines.BS_AUTOCHECKBOX or \
|
||||
StyleLSB == win32defines.BS_CHECKBOX:
|
||||
if style_lsb == win32defines.BS_3STATE or \
|
||||
style_lsb == win32defines.BS_AUTO3STATE or \
|
||||
style_lsb == win32defines.BS_AUTOCHECKBOX or \
|
||||
style_lsb == win32defines.BS_CHECKBOX:
|
||||
f_class_name = "CheckBox"
|
||||
|
||||
elif StyleLSB == win32defines.BS_RADIOBUTTON or \
|
||||
StyleLSB == win32defines.BS_AUTORADIOBUTTON:
|
||||
elif style_lsb == win32defines.BS_RADIOBUTTON or \
|
||||
style_lsb == win32defines.BS_AUTORADIOBUTTON:
|
||||
f_class_name = "RadioButton"
|
||||
|
||||
elif StyleLSB == win32defines.BS_GROUPBOX:
|
||||
elif style_lsb == win32defines.BS_GROUPBOX:
|
||||
f_class_name = "GroupBox"
|
||||
|
||||
if self.Style & win32defines.BS_PUSHLIKE:
|
||||
if self.Style() & win32defines.BS_PUSHLIKE:
|
||||
f_class_name = "Button"
|
||||
|
||||
return f_class_name
|
||||
@ -179,7 +173,7 @@ class ComboBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
return self.SendMessage(win32defines.CB_GETCURSEL)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _get_droppedrect(self):
|
||||
def DroppedRect(self):
|
||||
"Get the dropped rectangle of the combobox"
|
||||
droppedRect = win32structures.RECT()
|
||||
|
||||
@ -189,11 +183,9 @@ class ComboBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
ctypes.byref(droppedRect))
|
||||
|
||||
# we need to offset the dropped rect from the control
|
||||
droppedRect -= self.Rectangle
|
||||
droppedRect -= self.Rectangle()
|
||||
|
||||
return droppedRect
|
||||
DroppedRect = property(_get_droppedrect, doc =
|
||||
"The dropped rectangle of the combobox")
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def ItemCount(self):
|
||||
@ -215,13 +207,12 @@ class ComboBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
win32defines.CB_GETLBTEXT)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _get_texts(self):
|
||||
texts = [self.Text]
|
||||
def Texts(self):
|
||||
"Return the text of the items in the listbox"
|
||||
texts = [self.Text()]
|
||||
texts.extend(self.ItemTexts())
|
||||
return texts
|
||||
|
||||
Texts = property(_get_texts, doc = "get the texts of the listbox")
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def GetProperties(self):
|
||||
"Return the properties of the control as a dictionary"
|
||||
@ -230,7 +221,7 @@ class ComboBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
# get selected item
|
||||
props['SelectedItem'] = self.SelectedIndex()
|
||||
|
||||
props['DroppedRect'] = self.DroppedRect
|
||||
props['DroppedRect'] = self.DroppedRect()
|
||||
|
||||
props['ItemData'] = []
|
||||
for i in range(self.ItemCount()):
|
||||
@ -252,7 +243,7 @@ class ComboBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
if isinstance(item, (int, long)):
|
||||
index = item
|
||||
else:
|
||||
index = self.Texts.index(item) -1
|
||||
index = self.Texts().index(item) -1
|
||||
|
||||
# change the selected item
|
||||
self.SendMessageTimeout(win32defines.CB_SETCURSEL, index)
|
||||
@ -263,7 +254,8 @@ class ComboBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
# return this control so that actions can be chained.
|
||||
return self
|
||||
|
||||
|
||||
#def IsSelected(self, item):
|
||||
# pass
|
||||
|
||||
#====================================================================
|
||||
class ListBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
@ -308,7 +300,7 @@ class ListBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def ItemTexts(self):
|
||||
"Return the text items of the control"
|
||||
"Return the text of the items of the listbox"
|
||||
return _get_multiple_text_items(
|
||||
self,
|
||||
win32defines.LB_GETCOUNT,
|
||||
@ -316,13 +308,12 @@ class ListBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
win32defines.LB_GETTEXT)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _get_texts(self):
|
||||
texts = [self.Text]
|
||||
texts.extend(self.ItemTexts)
|
||||
def Texts(self):
|
||||
"Return the texts of the control"
|
||||
texts = [self.Text()]
|
||||
texts.extend(self.ItemTexts())
|
||||
return texts
|
||||
|
||||
Texts = property(_get_texts, doc = "get the texts of the listbox")
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def GetProperties(self):
|
||||
"Return the properties as a dictionary for the control"
|
||||
@ -352,10 +343,10 @@ class ListBoxWrapper(HwndWrapper.HwndWrapper):
|
||||
if isinstance(item, (int, long)):
|
||||
index = item
|
||||
else:
|
||||
index = self.Texts.index(item)
|
||||
index = self.Texts().index(item) - 1
|
||||
|
||||
# change the selected item
|
||||
self.SendMessageTimeout(win32defines.LB_SETCURSEL, index, 0)
|
||||
self.SendMessageTimeout(win32defines.LB_SETCURSEL, index)
|
||||
|
||||
# Notify the parent that we have changed
|
||||
self.NotifyParent(win32defines.LBN_SELCHANGE)
|
||||
@ -403,43 +394,64 @@ class EditWrapper(HwndWrapper.HwndWrapper):
|
||||
"Initialize the control"
|
||||
super(EditWrapper, self).__init__(hwnd)
|
||||
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def LineCount(self):
|
||||
"Return how many lines there are in the Edit"
|
||||
return self.SendMessage(win32defines.EM_GETLINECOUNT)
|
||||
|
||||
def _get_texts(self):
|
||||
#-----------------------------------------------------------
|
||||
def LineLength(self, line_index):
|
||||
"Return how many characters there are in the line"
|
||||
|
||||
# need to first get a character index of that line
|
||||
char_index = self.SendMessage(win32defines.EM_LINEINDEX, line_index)
|
||||
|
||||
# now get the length of text on that line
|
||||
return self.SendMessage (
|
||||
win32defines.EM_LINELENGTH, char_index, 0)
|
||||
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def GetLine(self, line_index):
|
||||
"Return the line specified"
|
||||
|
||||
text_len = self.LineLength(line_index)
|
||||
# create a buffer and set the length at the start of the buffer
|
||||
text = ctypes.create_unicode_buffer(text_len+1)
|
||||
text[0] = unichr(text_len)
|
||||
|
||||
# retrieve the line itself
|
||||
self.SendMessage (win32defines.EM_GETLINE, line_index, ctypes.byref(text))
|
||||
|
||||
return text.value
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def Texts(self):
|
||||
"Get the text of the edit control"
|
||||
|
||||
texts = [self.Text,]
|
||||
texts = [self.Text(),]
|
||||
|
||||
for i in range(0, self.LineCount()):
|
||||
textLen = self.SendMessage (win32defines.EM_LINELENGTH, i, 0)
|
||||
|
||||
text = ctypes.create_unicode_buffer(textLen+1)
|
||||
|
||||
# set the length - which is required
|
||||
text[0] = unichr(textLen)
|
||||
|
||||
self.SendMessage (win32defines.EM_GETLINE, i, ctypes.byref(text))
|
||||
|
||||
texts.append(text.value)
|
||||
texts.append(self.GetLine(i))
|
||||
|
||||
return texts
|
||||
|
||||
Texts = property(_get_texts, _get_texts.__doc__)
|
||||
#-----------------------------------------------------------
|
||||
def TextBlock(self):
|
||||
"Get the text of the edit control"
|
||||
|
||||
return "\n".join(self.Texts()[1:])
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def _get_selectionindices(self):
|
||||
"Return the indices of the selection"
|
||||
def SelectionIndices(self):
|
||||
"The start and end indices of the current selection"
|
||||
start = ctypes.c_int()
|
||||
end = ctypes.c_int()
|
||||
self.SendMessage(
|
||||
win32defines.EM_GETSEL, ctypes.byref(start), ctypes.byref(end))
|
||||
|
||||
return (start.value, end.value)
|
||||
SelectionIndices = property(
|
||||
_get_selectionindices,
|
||||
doc = "The start and end indices of the current selection")
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def GetProperties(self):
|
||||
@ -490,7 +502,7 @@ class EditWrapper(HwndWrapper.HwndWrapper):
|
||||
if isinstance(start, basestring):
|
||||
string_to_select = start
|
||||
#
|
||||
start = self.texts[1].index(string_to_select)
|
||||
start = self.Texts()[1].index(string_to_select)
|
||||
|
||||
if end is None:
|
||||
end = start + len(string_to_select)
|
||||
@ -517,7 +529,7 @@ class StaticWrapper(HwndWrapper.HwndWrapper):
|
||||
super(StaticWrapper, self).__init__(hwnd)
|
||||
|
||||
# if the control is visible - and it shows an image
|
||||
if self.IsVisible and (
|
||||
if self.IsVisible() and (
|
||||
self.HasStyle(win32defines.SS_ICON) or \
|
||||
self.HasStyle(win32defines.SS_BITMAP) or \
|
||||
self.HasStyle(win32defines.SS_CENTERIMAGE) or \
|
||||
@ -527,6 +539,7 @@ class StaticWrapper(HwndWrapper.HwndWrapper):
|
||||
|
||||
|
||||
|
||||
#====================================================================
|
||||
# the main reason for this is just to make sure that
|
||||
# a Dialog is a known class - and we don't need to take
|
||||
# an image of it (as an unknown control class)
|
||||
@ -542,8 +555,96 @@ class DialogWrapper(HwndWrapper.HwndWrapper):
|
||||
|
||||
# get all teh controls
|
||||
controls = [self]
|
||||
controls.extend(self.Children)
|
||||
controls.extend(self.Children())
|
||||
|
||||
return tests.run_tests(controls, tests_to_run)
|
||||
|
||||
#-----------------------------------------------------------
|
||||
def WriteToXML(self, filename):
|
||||
"Write the dialog an XML file (requires elementtree)"
|
||||
controls = [self]
|
||||
controls.extend(self.Children())
|
||||
props = [ctrl.GetProperties() for ctrl in controls]
|
||||
|
||||
from pywinauto import XMLHelpers
|
||||
XMLHelpers.WriteDialogToFile(filename, props)
|
||||
|
||||
|
||||
|
||||
|
||||
import unittest
|
||||
class EditTestCases(unittest.TestCase):
|
||||
"Unit tests for the TreeViewWrapper class"
|
||||
|
||||
def setUp(self):
|
||||
"""Start the application set some data and ensure the application
|
||||
is in the state we want it."""
|
||||
|
||||
# start the application
|
||||
from pywinauto.application import Application
|
||||
app = Application()
|
||||
|
||||
import os.path
|
||||
path = os.path.split(__file__)[0]
|
||||
|
||||
test_file = os.path.join(path, "test.txt")
|
||||
|
||||
self.test_data = open(test_file, "r").read()
|
||||
# remove the BOM if it exists
|
||||
self.test_data = self.test_data.replace("\xef\xbb\xbf", "")
|
||||
self.test_data = self.test_data.decode('utf-8')
|
||||
|
||||
app.start_("Notepad.exe " + test_file)
|
||||
|
||||
self.app = app
|
||||
self.dlg = app.UntitledNotepad
|
||||
self.ctrl = self.dlg.Edit.ctrl_()
|
||||
|
||||
#self.dlg.MenuSelect("Styles")
|
||||
|
||||
# select show selection always, and show checkboxes
|
||||
#app.ControlStyles.ListBox1.TypeKeys("{HOME}{SPACE}" + "{DOWN}"* 12 + "{SPACE}")
|
||||
#self.app.ControlStyles.ApplyStylesSetWindowLong.Click()
|
||||
#self.app.ControlStyles.SendMessage(win32defines.WM_CLOSE)
|
||||
|
||||
def tearDown(self):
|
||||
"Close the application after tests"
|
||||
# close the application
|
||||
self.dlg.MenuSelect("File->Exit")
|
||||
|
||||
|
||||
if self.app.Notepad.No.Exists():
|
||||
self.app.Notepad.No.Click()
|
||||
|
||||
def testTypeKeys(self):
|
||||
self.ctrl.SetText("Here is\r\nsome text")
|
||||
self.assertEquals("\n".join(self.ctrl.Texts()[1:]), "Here is\nsome text")
|
||||
|
||||
def testSetText(self):
|
||||
# typekeys types at the current caret position (start when opening a new file)
|
||||
added_text = "Here is some more Text"
|
||||
self.ctrl.TypeKeys(added_text, with_spaces = True)
|
||||
expected_text = added_text + self.test_data
|
||||
|
||||
self.assertEquals(self.ctrl.TextBlock(), expected_text)
|
||||
|
||||
def testSelect(self):
|
||||
self.ctrl.Select(10, 50)
|
||||
|
||||
self.assertEquals((10, 50), self.ctrl.SelectionIndices())
|
||||
|
||||
def testLineCount(self):
|
||||
self.assertEquals(self.ctrl.LineCount(), self.test_data.count("\n")+1)
|
||||
|
||||
def testGetLine(self):
|
||||
for i, line in enumerate(self.test_data.split("\n")):
|
||||
self.assertEquals(self.ctrl.GetLine(i), line)
|
||||
|
||||
def testTextBlock(self):
|
||||
self.assertEquals(self.ctrl.TextBlock(), self.test_data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
#_unittests()
|
||||
|
||||
unittest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user