# GUI Application automation and testing library # Copyright (C) 2006-2018 Mark Mc Mahon and Contributors # https://github.com/pywinauto/pywinauto/graphs/contributors # http://pywinauto.readthedocs.io/en/latest/credits.html # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # * Neither the name of pywinauto nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """Wraps various standard windows controls""" from __future__ import unicode_literals import time import ctypes import win32gui import locale import six from . import hwndwrapper from .. import win32functions from .. import win32defines from .. import win32structures from ..timings import Timings from .. import deprecated #==================================================================== class ButtonWrapper(hwndwrapper.HwndWrapper): """Wrap a windows Button control""" friendlyclassname = "Button" windowclasses = [ "Button", ".*Button", r"WindowsForms\d*\.BUTTON\..*", ".*CheckBox", ] can_be_label = True #----------------------------------------------------------- def __init__(self, hwnd): """Initialize the control""" super(ButtonWrapper, self).__init__(hwnd) #self._set_if_needs_image() @property def _needs_image_prop(self): """_needs_image_prop=True if it is an image button""" # optimization call style once and work with that rather than # calling has_style a number of times style = self.style() if self.is_visible() and (style & win32defines.BS_BITMAP or style & win32defines.BS_ICON or style & win32defines.BS_OWNERDRAW): return True else: return False # Non PEP-8 alias _NeedsImageProp = deprecated(_needs_image_prop, deprecated_name='_NeedsImageProp') #----------------------------------------------------------- def friendly_class_name(self): """ Return the friendly class name of the button Windows controls with the class "Button" can look like different controls based on their style. They can look like the following controls: - Buttons, this method returns "Button" - CheckBoxes, this method returns "CheckBox" - RadioButtons, this method returns "RadioButton" - GroupBoxes, this method returns "GroupBox" """ # get the least significant BIT style_lsb = self.style() & 0xF f_class_name = 'Button' vb_buttons = { "ThunderOptionButton": "RadioButton", "ThunderCheckBox": "CheckBox", "ThunderCommandButton": "Button" } if self.class_name() in vb_buttons: f_class_name = vb_buttons[self.class_name()] if style_lsb in [win32defines.BS_3STATE, win32defines.BS_AUTO3STATE, win32defines.BS_AUTOCHECKBOX, win32defines.BS_CHECKBOX, ]: f_class_name = "CheckBox" elif style_lsb in [win32defines.BS_RADIOBUTTON, win32defines.BS_AUTORADIOBUTTON, ]: f_class_name = "RadioButton" elif style_lsb == win32defines.BS_GROUPBOX: f_class_name = "GroupBox" if self.style() & win32defines.BS_PUSHLIKE: f_class_name = "Button" return f_class_name #----------------------------------------------------------- def get_check_state(self): """ Return the check state of the checkbox The check state is represented by an integer 0 - unchecked 1 - checked 2 - indeterminate The following constants are defined in the win32defines module BST_UNCHECKED = 0 BST_CHECKED = 1 BST_INDETERMINATE = 2 """ self._ensure_enough_privileges('BM_GETCHECK') return self.send_message(win32defines.BM_GETCHECK) # Non PEP-8 alias GetCheckState = deprecated(get_check_state) __check_states = { win32defines.BST_UNCHECKED: False, win32defines.BST_CHECKED: True, win32defines.BST_INDETERMINATE: None, } #----------------------------------------------------------- def is_checked(self): """Return True if checked, False if not checked, None if indeterminate""" return self.__check_states[self.get_check_state()] #----------------------------------------------------------- def check(self): """Check a checkbox""" self._ensure_enough_privileges('BM_SETCHECK') self.send_message_timeout(win32defines.BM_SETCHECK, win32defines.BST_CHECKED) win32functions.WaitGuiThreadIdle(self.handle) time.sleep(Timings.after_buttoncheck_wait) # return this control so that actions can be chained. return self # Non PEP-8 alias Check = deprecated(check) #----------------------------------------------------------- def uncheck(self): """Uncheck a checkbox""" self._ensure_enough_privileges('BM_SETCHECK') self.send_message_timeout(win32defines.BM_SETCHECK, win32defines.BST_UNCHECKED) win32functions.WaitGuiThreadIdle(self.handle) time.sleep(Timings.after_buttoncheck_wait) # return this control so that actions can be chained. return self # Non PEP-8 alias UnCheck = deprecated(uncheck, deprecated_name='UnCheck') #----------------------------------------------------------- def set_check_indeterminate(self): """Set the checkbox to indeterminate""" self._ensure_enough_privileges('BM_SETCHECK') self.send_message_timeout(win32defines.BM_SETCHECK, win32defines.BST_INDETERMINATE) win32functions.WaitGuiThreadIdle(self.handle) time.sleep(Timings.after_buttoncheck_wait) # return this control so that actions can be chained. return self # Non PEP-8 alias SetCheckIndeterminate = deprecated(set_check_indeterminate) #----------------------------------------------------------- def is_dialog(self): """Buttons are never dialogs so return False""" return False #----------------------------------------------------------- def click(self, button="left", pressed="", coords=(0, 0), double=False, absolute=False): """Click the Button control""" #import win32functions #win32functions.WaitGuiThreadIdle(self) #self.notify_parent(win32defines.BN_CLICKED) hwndwrapper.HwndWrapper.click(self, button, pressed, coords, double, absolute) #win32functions.WaitGuiThreadIdle(self) time.sleep(Timings.after_button_click_wait) #----------------------------------------------------------- def check_by_click(self): """Check the CheckBox control by click() method""" if self.get_check_state() != win32defines.BST_CHECKED: self.click() # Non PEP-8 alias CheckByClick = deprecated(check_by_click) #----------------------------------------------------------- def uncheck_by_click(self): """Uncheck the CheckBox control by click() method""" if self.get_check_state() != win32defines.BST_UNCHECKED: self.click() # Non PEP-8 alias UncheckByClick = deprecated(uncheck_by_click) #----------------------------------------------------------- def check_by_click_input(self): """Check the CheckBox control by click_input() method""" if self.get_check_state() != win32defines.BST_CHECKED: self.click_input() # Non PEP-8 alias CheckByClickInput = deprecated(check_by_click_input) #----------------------------------------------------------- def uncheck_by_click_input(self): """Uncheck the CheckBox control by click_input() method""" if self.get_check_state() != win32defines.BST_UNCHECKED: self.click_input() # Non PEP-8 alias UncheckByClickInput = deprecated(uncheck_by_click_input) #==================================================================== def _get_multiple_text_items(wrapper, count_msg, item_len_msg, item_get_msg): """Helper function to get multiple text items from a control""" texts = [] # find out how many text items are in the combobox num_items = wrapper.send_message(count_msg) # get the text for each item in the combobox for i in range(0, num_items): text_len = wrapper.send_message (item_len_msg, i, 0) if six.PY3: text = ctypes.create_unicode_buffer(text_len + 1) else: text = ctypes.create_string_buffer(text_len + 1) wrapper.send_message(item_get_msg, i, ctypes.byref(text)) if six.PY3: texts.append(text.value.replace('\u200e', '')) else: texts.append(text.value.decode(locale.getpreferredencoding(), 'ignore').replace('?', '')) return texts #==================================================================== class ComboBoxWrapper(hwndwrapper.HwndWrapper): """Wrap a windows ComboBox control""" friendlyclassname = "ComboBox" windowclasses = [ "ComboBox", r"WindowsForms\d*\.COMBOBOX\..*", ".*ComboBox", ] has_title = False #----------------------------------------------------------- def __init__(self, hwnd): """Initialize the control""" super(ComboBoxWrapper, self).__init__(hwnd) @property def writable_props(self): """Extend default properties list.""" props = super(ComboBoxWrapper, self).writable_props props.extend(["selected_index", "dropped_rect", ]) return props #----------------------------------------------------------- def dropped_rect(self): """Get the dropped rectangle of the combobox""" dropped_rect = win32structures.RECT() self.send_message( win32defines.CB_GETDROPPEDCONTROLRECT, 0, ctypes.byref(dropped_rect)) # we need to offset the dropped rect from the control dropped_rect -= self.rectangle() return dropped_rect # Non PEP-8 alias DroppedRect = deprecated(dropped_rect) #----------------------------------------------------------- def item_count(self): """Return the number of items in the combobox""" self._ensure_enough_privileges('CB_GETCOUNT') return self.send_message(win32defines.CB_GETCOUNT) # Non PEP-8 alias ItemCount = deprecated(item_count) #----------------------------------------------------------- def selected_index(self): """Return the selected index""" self._ensure_enough_privileges('CB_GETCURSEL') return self.send_message(win32defines.CB_GETCURSEL) # Non PEP-8 alias SelectedIndex = deprecated(selected_index) #----------------------------------------------------------- def selected_text(self): """Return the selected text""" return self.item_texts()[self.selected_index()] # Non PEP-8 alias SelectedText = deprecated(selected_text) #----------------------------------------------------------- def _get_item_index(self, ident): """Get the index for the item with this 'ident'""" if isinstance(ident, six.integer_types): if ident >= self.item_count(): raise IndexError(('Combobox has {0} items, you requested ' + \ 'item {1} (0 based)').format(self.item_count(), ident)) # negative index if ident < 0: # convert it to a positive index ident = (self.item_count() + ident) elif isinstance(ident, six.string_types): # todo - implement fuzzy lookup for ComboBox items # todo - implement appdata lookup for combobox items ident = self.item_texts().index(ident) return ident #----------------------------------------------------------- def item_data(self, item): """Returns the item data associated with the item if any""" index = self._get_item_index(item) return self.send_message(win32defines.CB_GETITEMDATA, index) # Non PEP-8 alias ItemData = deprecated(item_data) #----------------------------------------------------------- def item_texts(self): """Return the text of the items of the combobox""" self._ensure_enough_privileges('CB_GETCOUNT') return _get_multiple_text_items( self, win32defines.CB_GETCOUNT, win32defines.CB_GETLBTEXTLEN, win32defines.CB_GETLBTEXT) # Non PEP-8 alias ItemTexts = deprecated(item_texts) #----------------------------------------------------------- def texts(self): """Return the text of the items in the combobox""" texts = [self.window_text()] texts.extend(self.item_texts()) return texts #----------------------------------------------------------- def get_properties(self): """Return the properties of the control as a dictionary""" props = hwndwrapper.HwndWrapper.get_properties(self) #props['item_data'] = [] #for i in range(self.item_count()): # props['item_data'].append(self.item_data(i)) return props #----------------------------------------------------------- def select(self, item): """Select the ComboBox item item can be either a 0 based index of the item to select or it can be the string that you want to select """ self.verify_actionable() index = self._get_item_index(item) # change the selected item self.send_message_timeout(win32defines.CB_SETCURSEL, index, timeout=0.05) # Notify the parent that we are finished selecting self.notify_parent(win32defines.CBN_SELENDOK) # Notify the parent that we have changed self.notify_parent(win32defines.CBN_SELCHANGE) # simple combo boxes don't have drop downs so they do not recieve # this notification if self.has_style(win32defines.CBS_DROPDOWN): # Notify the parent that the drop down has closed self.notify_parent(win32defines.CBN_CLOSEUP) win32functions.WaitGuiThreadIdle(self.handle) time.sleep(Timings.after_comboboxselect_wait) # return this control so that actions can be chained. return self # Non PEP-8 alias Select = deprecated(select) #----------------------------------------------------------- #def deselect(self, item): # Not implemented because it doesn't make sense for combo boxes. #TODO def edit_control(self): # return the edit control of the Combobox #TODO def list_control(self): # return the list control of the combobox #TODO def item_text(self, index): # get the test of item XX? #TODO def edit_text(self): # or should this be self.EditControl.text()? #==================================================================== class ListBoxWrapper(hwndwrapper.HwndWrapper): """Wrap a windows ListBox control""" friendlyclassname = "ListBox" windowclasses = [ "ListBox", r"WindowsForms\d*\.LISTBOX\..*", ".*ListBox", ] has_title = False #----------------------------------------------------------- def __init__(self, hwnd): """Initialize the control""" super(ListBoxWrapper, self).__init__(hwnd) @property def writable_props(self): """Extend default properties list.""" props = super(ListBoxWrapper, self).writable_props props.extend(["selected_indices"]) return props #----------------------------------------------------------- def is_single_selection(self): """Check whether the listbox has single selection mode.""" self._ensure_enough_privileges('LB_GETSELCOUNT') num_selected = self.send_message(win32defines.LB_GETSELCOUNT) # if we got LB_ERR then it is a single selection list box return (num_selected == win32defines.LB_ERR) # Non PEP-8 alias IsSingleSelection = deprecated(is_single_selection) #----------------------------------------------------------- def selected_indices(self): """The currently selected indices of the listbox""" self._ensure_enough_privileges('LB_GETSELCOUNT') num_selected = self.send_message(win32defines.LB_GETSELCOUNT) # if we got LB_ERR then it is a single selection list box if num_selected == win32defines.LB_ERR: items = tuple([self.send_message(win32defines.LB_GETCURSEL)]) # otherwise it is a multiselection list box else: items = (ctypes.c_int * num_selected)() self.send_message( win32defines.LB_GETSELITEMS, num_selected, ctypes.byref(items)) # Need to convert from Ctypes array to a python tuple items = tuple(items) return items # Non PEP-8 alias SelectedIndices = deprecated(selected_indices) #----------------------------------------------------------- def _get_item_index(self, ident): """Return the index of the item 'ident'""" if isinstance(ident, six.integer_types): if ident >= self.item_count(): raise IndexError(('ListBox has {0} items, you requested ' + \ 'item {1} (0 based)').format(self.item_count(), ident)) # negative index if ident < 0: ident = (self.item_count() + ident) elif isinstance(ident, six.string_types): # todo - implement fuzzy lookup for ComboBox items # todo - implement appdata lookup for combobox items ident = self.item_texts().index(ident) #-1 return ident #----------------------------------------------------------- def item_count(self): """Return the number of items in the ListBox""" self._ensure_enough_privileges('LB_GETCOUNT') return self.send_message(win32defines.LB_GETCOUNT) # Non PEP-8 alias ItemCount = deprecated(item_count) #----------------------------------------------------------- def item_data(self, i): """Return the item_data if any associted with the item""" index = self._get_item_index(i) return self.send_message(win32defines.LB_GETITEMDATA, index) # Non PEP-8 alias ItemData = deprecated(item_data) #----------------------------------------------------------- def item_texts(self): """Return the text of the items of the listbox""" self._ensure_enough_privileges('LB_GETCOUNT') return _get_multiple_text_items( self, win32defines.LB_GETCOUNT, win32defines.LB_GETTEXTLEN, win32defines.LB_GETTEXT) # Non PEP-8 alias ItemTexts = deprecated(item_texts) #----------------------------------------------------------- def item_rect(self, item): """Return the rect of the item""" index = self._get_item_index(item) rect = win32structures.RECT() res = self.send_message(win32defines.LB_GETITEMRECT, index, ctypes.byref(rect)) if res == win32defines.LB_ERR: raise RuntimeError("LB_GETITEMRECT failed") return rect # Non PEP-8 alias ItemRect = deprecated(item_rect) #----------------------------------------------------------- def texts(self): """Return the texts of the control""" texts = [self.window_text()] texts.extend(self.item_texts()) return texts # #----------------------------------------------------------- # def get_properties(self): # "Return the properties as a dictionary for the control" # props = hwndwrapper.HwndWrapper.get_properties(self) # # props['item_data'] = [] # for i in range(self.item_count()): # props['item_data'].append(self.item_data(i)) # # return props #----------------------------------------------------------- def select(self, item, select=True): """Select the ListBox item item can be either a 0 based index of the item to select or it can be the string that you want to select """ if self.is_single_selection() and isinstance(item, (list, tuple)) and len(item) > 1: raise Exception('Cannot set multiple selection for single-selection listbox!') if isinstance(item, (list, tuple)): for i in item: if i is not None: self.select(i, select) return self self.verify_actionable() # Make sure we have an index so if passed in a # string then find which item it is index = self._get_item_index(item) if self.is_single_selection(): # change the selected item self.send_message_timeout(win32defines.LB_SETCURSEL, index) else: if select: # add the item to selection self.send_message_timeout(win32defines.LB_SETSEL, win32defines.TRUE, index) else: # remove the item from selection self.send_message_timeout(win32defines.LB_SETSEL, win32defines.FALSE, index) # Notify the parent that we have changed self.notify_parent(win32defines.LBN_SELCHANGE) win32functions.WaitGuiThreadIdle(self.handle) time.sleep(Timings.after_listboxselect_wait) return self # Non PEP-8 alias Select = deprecated(select) #----------------------------------------------------------- def set_item_focus(self, item): """Set the ListBox focus to the item at index""" index = self._get_item_index(item) # if it is a multiple selection dialog if self.has_style(win32defines.LBS_EXTENDEDSEL) or \ self.has_style(win32defines.LBS_MULTIPLESEL): self.send_message_timeout(win32defines.LB_SETCARETINDEX, index) else: self.send_message_timeout(win32defines.LB_SETCURSEL, index) win32functions.WaitGuiThreadIdle(self.handle) time.sleep(Timings.after_listboxfocuschange_wait) # return this control so that actions can be chained. return self # Non PEP-8 alias SetItemFocus = deprecated(set_item_focus) #----------------------------------------------------------- def get_item_focus(self): """Retrun the index of current selection in a ListBox""" # if it is a multiple selection dialog if self.has_style(win32defines.LBS_EXTENDEDSEL) or \ self.has_style(win32defines.LBS_MULTIPLESEL): return self.send_message(win32defines.LB_GETCARETINDEX) else: return self.send_message(win32defines.LB_GETCURSEL) # Non PEP-8 alias GetItemFocus = deprecated(get_item_focus) #==================================================================== class EditWrapper(hwndwrapper.HwndWrapper): """Wrap a windows Edit control""" friendlyclassname = "Edit" windowclasses = [ "Edit", ".*Edit", "TMemo", r"WindowsForms\d*\.EDIT\..*", "ThunderTextBox", "ThunderRT6TextBox", ] has_title = False #----------------------------------------------------------- def __init__(self, hwnd): """Initialize the control""" super(EditWrapper, self).__init__(hwnd) @property def writable_props(self): """Extend default properties list.""" props = super(EditWrapper, self).writable_props props.extend(['selection_indices']) return props #----------------------------------------------------------- def line_count(self): """Return how many lines there are in the Edit""" self._ensure_enough_privileges('EM_GETLINECOUNT') return self.send_message(win32defines.EM_GETLINECOUNT) # Non PEP-8 alias LineCount = deprecated(line_count) #----------------------------------------------------------- def line_length(self, line_index): """Return how many characters there are in the line""" self._ensure_enough_privileges('EM_LINEINDEX') # need to first get a character index of that line char_index = self.send_message(win32defines.EM_LINEINDEX, line_index) # now get the length of text on that line return self.send_message ( win32defines.EM_LINELENGTH, char_index, 0) # Non PEP-8 alias LineLength = deprecated(line_length) #----------------------------------------------------------- def get_line(self, line_index): """Return the line specified""" text_len = self.line_length(line_index) # create a buffer and set the length at the start of the buffer text = ctypes.create_unicode_buffer(text_len+3) text[0] = six.unichr(text_len) # retrieve the line itself win32functions.SendMessage(self, win32defines.EM_GETLINE, line_index, ctypes.byref(text)) return text.value # Non PEP-8 alias GetLine = deprecated(get_line) #----------------------------------------------------------- def texts(self): """Get the text of the edit control""" texts = [self.window_text(), ] for i in range(self.line_count()): texts.append(self.get_line(i)) return texts #----------------------------------------------------------- def text_block(self): """Get the text of the edit control""" length = self.send_message(win32defines.WM_GETTEXTLENGTH) text = ctypes.create_unicode_buffer(length + 1) win32functions.SendMessage(self, win32defines.WM_GETTEXT, length + 1, ctypes.byref(text)) return text.value # Non PEP-8 alias TextBlock = deprecated(text_block) #----------------------------------------------------------- def selection_indices(self): """The start and end indices of the current selection""" self._ensure_enough_privileges('EM_GETSEL') start = ctypes.c_int() end = ctypes.c_int() self.send_message( win32defines.EM_GETSEL, ctypes.byref(start), ctypes.byref(end)) return (start.value, end.value) # Non PEP-8 alias SelectionIndices = deprecated(selection_indices) #----------------------------------------------------------- def set_window_text(self, text, append = False): """Override set_window_text for edit controls because it should not be used for Edit controls. Edit Controls should either use set_edit_text() or type_keys() to modify the contents of the edit control.""" hwndwrapper.HwndWrapper.set_window_text(self, text, append) raise UserWarning( "set_window_text() should probably not be called for Edit Controls") #----------------------------------------------------------- def set_edit_text(self, text, pos_start = None, pos_end = None): """Set the text of the edit control""" self._ensure_enough_privileges('EM_REPLACESEL') self.verify_actionable() # allow one or both of pos_start and pos_end to be None if pos_start is not None or pos_end is not None: # if only one has been specified - then set the other # to the current selection start or end start, end = self.selection_indices() if pos_start is None: pos_start = start if pos_end is None and not isinstance(start, six.string_types): pos_end = end # set the selection if either start or end has # been specified self.select(pos_start, pos_end) else: self.select() if isinstance(text, six.text_type): if six.PY3: aligned_text = text else: aligned_text = text.encode(locale.getpreferredencoding()) elif isinstance(text, six.binary_type): if six.PY3: aligned_text = text.decode(locale.getpreferredencoding()) else: aligned_text = text else: # convert a non-string input if six.PY3: aligned_text = six.text_type(text) else: aligned_text = six.binary_type(text) if isinstance(aligned_text, six.text_type): buffer = ctypes.create_unicode_buffer(aligned_text, size=len(aligned_text) + 1) else: buffer = ctypes.create_string_buffer(aligned_text, size=len(aligned_text) + 1) # replace the selection with self.send_message(win32defines.EM_REPLACESEL, True, ctypes.byref(buffer)) #win32functions.WaitGuiThreadIdle(self) #time.sleep(Timings.after_editsetedittext_wait) if isinstance(aligned_text, six.text_type): self.actions.log('Set text to the edit box: ' + aligned_text) else: self.actions.log(b'Set text to the edit box: ' + aligned_text) # return this control so that actions can be chained. return self # set SetText as an alias to set_edit_text set_text = set_edit_text # Non PEP-8 alias SetText = deprecated(set_text) # Non PEP-8 alias SetEditText = deprecated(set_edit_text) #----------------------------------------------------------- def select(self, start = 0, end = None): """Set the edit selection of the edit control""" self._ensure_enough_privileges('EM_SETSEL') self.verify_actionable() win32functions.SetFocus(self) # if we have been asked to select a string if isinstance(start, six.text_type): string_to_select = start start = self.text_block().index(string_to_select) if end is None: end = start + len(string_to_select) elif isinstance(start, six.binary_type): string_to_select = start.decode(locale.getpreferredencoding()) start = self.text_block().index(string_to_select) if end is None: end = start + len(string_to_select) if end is None: end = -1 self.send_message(win32defines.EM_SETSEL, start, end) # give the control a chance to catch up before continuing win32functions.WaitGuiThreadIdle(self.handle) time.sleep(Timings.after_editselect_wait) # return this control so that actions can be chained. return self # Non PEP-8 alias Select = deprecated(select) #==================================================================== class StaticWrapper(hwndwrapper.HwndWrapper): """Wrap a windows Static control""" friendlyclassname = "Static" windowclasses = [ "Static", r"WindowsForms\d*\.STATIC\..*", "TPanel", ".*StaticText"] can_be_label = True def __init__(self, hwnd): """Initialize the control""" super(StaticWrapper, self).__init__(hwnd) @property def _needs_image_prop(self): """_needs_image_prop=True if it is an image static""" # if the control is visible - and it shows an image if self.is_visible() and (self.has_style(win32defines.SS_ICON) or self.has_style(win32defines.SS_BITMAP) or self.has_style(win32defines.SS_CENTERIMAGE) or self.has_style(win32defines.SS_OWNERDRAW)): return True else: return False # Non PEP-8 alias _NeedsImageProp = deprecated(_needs_image_prop, deprecated_name='_NeedsImageProp') #==================================================================== class PopupMenuWrapper(hwndwrapper.HwndWrapper): """Wrap a Popup Menu""" friendlyclassname = "PopupMenu" windowclasses = ["#32768", ] has_title = False #----------------------------------------------------------- def is_dialog(self): """Return whether it is a dialog""" return True #----------------------------------------------------------- def _menu_handle(self): """Get the menu handle for the popup menu""" hMenu = win32gui.SendMessage(self.handle, win32defines.MN_GETHMENU) if not hMenu: raise ctypes.WinError() return (hMenu, False) # (hMenu, is_main_menu)