Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.

Squish/Interacting with Menus: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
(add another option to activate an item)
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
[[Category:Tools::Squish]]
[[Category:Squish]]


= Interacting with menus and menu items =
= Interacting with menus and menu items =
Line 5: Line 5:
In [[:Category:Tools::Squish::Verifying_the_existence_of_a_menu_item | Verifying the existence of a menu item]], we saw how to access single menu items using Squish's real name approach. We can use this approach again, to implement support for dynamically interacting with menus and menu items. That is, we implement one single function for interacting with all menu items in the main window of the AUT, including menu items in sub-menus.
In [[:Category:Tools::Squish::Verifying_the_existence_of_a_menu_item | Verifying the existence of a menu item]], we saw how to access single menu items using Squish's real name approach. We can use this approach again, to implement support for dynamically interacting with menus and menu items. That is, we implement one single function for interacting with all menu items in the main window of the AUT, including menu items in sub-menus.


[[Image:http://www.kdab.com/~tobias/interacting-with-menus.png|Menu structure]]
[[File:Squish-interacting-with-menus.png|interaction with menus|Menu example]]


Consider the menu structure above - if we simply record interaction with File <s>&gt; New…, Edit</s>&gt; Find <s>&gt; Find…<br />and Edit</s>&gt; Find <s>&gt; Advanced</s>&gt; Find &amp; Replace…, we end up with code such as:<br /><code> # File <s>&gt; New…<br /> activateItem(waitForObjectItem(&quot;:MainWindow.menuBar_QMenuBar&amp;quot;, &quot;File&amp;quot;))<br /> activateItem(waitForObjectItem(&quot;:MainWindow.File_QMenu&amp;quot;, &quot;New…&quot;))
Consider the menu structure above - if we simply record interaction with File -> New…, Edit-> Find -> Find…
<br /> # Edit</s>&gt; Find <s>&gt; Find…<br /> activateItem(waitForObjectItem(&quot;:MainWindow.menuBar_QMenuBar&amp;quot;, &quot;Edit&amp;quot;))<br /> activateItem(waitForObjectItem(&quot;:MainWindow.Edit_QMenu&amp;quot;, &quot;Find&amp;quot;))<br /> activateItem(waitForObjectItem(&quot;:Edit.Find_QMenu&amp;quot;, &quot;Find…&quot;))
and Edit-> Find -> Advanced-> Find & Replace…, we end up with code such as:
<br /> # Edit</s>&gt; Find <s>&gt; Advanced</s>&gt; Find &amp; Replace…<br /> activateItem(waitForObjectItem(&quot;:MainWindow.menuBar_QMenuBar&amp;quot;, &quot;Edit&amp;quot;))<br /> activateItem(waitForObjectItem(&quot;:MainWindow.Edit_QMenu&amp;quot;, &quot;Find&amp;quot;))<br /> activateItem(waitForObjectItem(&quot;:Edit.Find_QMenu&amp;quot;, &quot;Advanced&amp;quot;))<br /> activateItem(waitForObjectItem(&quot;:Find.Advanced_QMenu&amp;quot;, &quot;Find &amp; Replace…&quot;))</code>
<code>
# File -> New…
activateItem(waitForObjectItem(":MainWindow.menuBar_QMenuBar", "File"))
activateItem(waitForObjectItem(":MainWindow.File_QMenu", "New…"))
 
# Edit-> Find -> Find…
activateItem(waitForObjectItem(":MainWindow.menuBar_QMenuBar", "Edit"))
activateItem(waitForObjectItem(":MainWindow.Edit_QMenu", "Find"))
activateItem(waitForObjectItem(":Edit.Find_QMenu", "Find…"))
 
# Edit-> Find -> Advanced-> Find & Replace…
activateItem(waitForObjectItem(":MainWindow.menuBar_QMenuBar", "Edit"))
activateItem(waitForObjectItem(":MainWindow.Edit_QMenu", "Find"))
activateItem(waitForObjectItem(":Edit.Find_QMenu", "Advanced"))
activateItem(waitForObjectItem(":Find.Advanced_QMenu", "Find & Replace…"))
</code>


This code requires the menu objects, including the sub-menus, to be added to the object map, which in turn requires us to always record when interacting with a menu or sub-menu that Squish does not yet know about. With the real name approach, we can get around this.
This code requires the menu objects, including the sub-menus, to be added to the object map, which in turn requires us to always record when interacting with a menu or sub-menu that Squish does not yet know about. With the real name approach, we can get around this.


Adding support for any level of menu depth can be done by implementing a function that takes an arbitrary number of arguments, such as below:<br /><code>def activateMenuItem(*menuPath):<br /> menu = &quot;:MainWindow.menuBar_QMenuBar&amp;quot;<br /> parent = &quot;{name='MainWindow' type='MainWindow' visible='1' windowTitle='MainWindow'}&quot;<br /> for item in menuPath[:–1]:<br /> activateItem(waitForObjectItem(menu, item))<br /> menu = &quot;{title='%s' type='QMenu' visible='1' window=s}&quot; (item, parent)<br /> parent = menu<br /> activateItem(waitForObjectItem(menu, menuPath[–1]))</code>
Adding support for any level of menu depth can be done by implementing a function that takes an arbitrary number of arguments, such as below:
<code>
def activateMenuItem(menu, *menuPath):
  for item in menuPath:
    activateItem(waitForObjectItem(menu, item))
    menu = {"title": item, "type": "QMenu", "visible": "1", "window": menu["window"]}
</code>


The code above only requires one object to be in the object map, and that is the menu bar. Of course, that can also be changed into a real name instead, if necessary.
The code above only requires one object to be in the object map, and that is the menu bar. Of course, that can also be changed into a real name instead, if necessary.


Usage would simply be:<br /><code> activateMenuItem(&quot;File&amp;quot;, &quot;New…&quot;)<br /> activateMenuItem(&quot;Edit&amp;quot;, &quot;Find&amp;quot;, &quot;Find…&quot;)<br /> activateMenuItem(&quot;Edit&amp;quot;, &quot;Find&amp;quot;, &quot;Advanced&amp;quot;, &quot;Find &amp; Replace…&quot;)</code>
Usage would simply be:
<code>
activateMenuItem(":MainWindow.menuBar_QMenuBar", "File", "New…")
activateMenuItem(":MainWindow.menuBar_QMenuBar", "Edit", "Find", "Find…")
activateMenuItem(":MainWindow.menuBar_QMenuBar", "Edit", "Find", "Advanced", "Find & Replace…")
</code>
 
If you want to use the object names instead the menu strings (e.g. due to translation of the strings) you can use the following function
<code>
def activateMenuItem(menu, *menuObjectPath):
  for item in menuObjectPath:
    children = object.children(waitForObject(menu))
    for child in children:
      if child.objectName == item:
        txt = child.title if hasattr(child, 'title') else child.text
        activateItem(waitForObjectItem(menu, txt))
        menu = {"title": item, "type": "QMenu", "visible": "1", "window": menu["window"]}
        break
 
def foo():
  # assume the object names of 'File' is 'menuFile' and 'New...' is 'actionNew'
  activateMenuItem(":MainWindow.menuBar_QMenuBar", "menuFile", "actionNew")
</code>

Latest revision as of 09:55, 11 August 2020


Interacting with menus and menu items

In Verifying the existence of a menu item, we saw how to access single menu items using Squish's real name approach. We can use this approach again, to implement support for dynamically interacting with menus and menu items. That is, we implement one single function for interacting with all menu items in the main window of the AUT, including menu items in sub-menus.

Menu example

Consider the menu structure above - if we simply record interaction with File -> New…, Edit-> Find -> Find… and Edit-> Find -> Advanced-> Find & Replace…, we end up with code such as:

# File -> New…
activateItem(waitForObjectItem(":MainWindow.menuBar_QMenuBar", "File"))
activateItem(waitForObjectItem(":MainWindow.File_QMenu", "New…"))

# Edit-> Find -> Find…
activateItem(waitForObjectItem(":MainWindow.menuBar_QMenuBar", "Edit"))
activateItem(waitForObjectItem(":MainWindow.Edit_QMenu", "Find"))
activateItem(waitForObjectItem(":Edit.Find_QMenu", "Find…"))

# Edit-> Find -> Advanced-> Find & Replace…
activateItem(waitForObjectItem(":MainWindow.menuBar_QMenuBar", "Edit"))
activateItem(waitForObjectItem(":MainWindow.Edit_QMenu", "Find"))
activateItem(waitForObjectItem(":Edit.Find_QMenu", "Advanced"))
activateItem(waitForObjectItem(":Find.Advanced_QMenu", "Find & Replace…"))

This code requires the menu objects, including the sub-menus, to be added to the object map, which in turn requires us to always record when interacting with a menu or sub-menu that Squish does not yet know about. With the real name approach, we can get around this.

Adding support for any level of menu depth can be done by implementing a function that takes an arbitrary number of arguments, such as below:

def activateMenuItem(menu, *menuPath):
  for item in menuPath:
    activateItem(waitForObjectItem(menu, item))
    menu = {"title": item, "type": "QMenu", "visible": "1", "window": menu["window"]}

The code above only requires one object to be in the object map, and that is the menu bar. Of course, that can also be changed into a real name instead, if necessary.

Usage would simply be:

activateMenuItem(":MainWindow.menuBar_QMenuBar", "File", "New…")
activateMenuItem(":MainWindow.menuBar_QMenuBar", "Edit", "Find", "Find…")
activateMenuItem(":MainWindow.menuBar_QMenuBar", "Edit", "Find", "Advanced", "Find & Replace…")

If you want to use the object names instead the menu strings (e.g. due to translation of the strings) you can use the following function

def activateMenuItem(menu, *menuObjectPath):
  for item in menuObjectPath:
    children = object.children(waitForObject(menu))
    for child in children:
      if child.objectName == item:
        txt = child.title if hasattr(child, 'title') else child.text
        activateItem(waitForObjectItem(menu, txt))
        menu = {"title": item, "type": "QMenu", "visible": "1", "window": menu["window"]}
        break

def foo():
  # assume the object names of 'File' is 'menuFile' and 'New...' is 'actionNew' 
  activateMenuItem(":MainWindow.menuBar_QMenuBar", "menuFile", "actionNew")