Forum Discussion

RandyJ5150's avatar
RandyJ5150
Occasional Contributor
7 years ago

Accessing Sub Menu Items from Context Menu

This is my first question to the community.  I'm testing a WPF app with TC v12.60 and trying to access sub menu items from a context menu generated from a right-click on an object.

 

The context menus are as follows:

  • ContextMenu_Item1
  • ContextMenu_Item2
    • SubMenu1_Item1
      • SubMenu2_Item1
      • SubMenu2_Item2
    • SubMenu_Item2
  • etc.

The object that gets the right-click is in a ListView.  I generate the right click as follows:

Aliases.MyApp.HwndSource_mainWindow.mainWindow.tabControl1.listBoxDevices.ClickItemR(0)

 

I then access the contextmenu as follows:

contextmenu = Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot

 

I can navigate the submenus as follows:

 

# Hover mouse over a menu item at X,Y coordinate

contextmenu.HoverMouse(60, 100)
Delay(500)

 

#Submenu1
mouseX = Sys.Desktop.MouseX
mouseY = Sys.Desktop.MouseY
mouseX = mouseX + contextmenu.Width
submenu1 = Sys.ObjectFromPoint(mouseX, mouseY)
objectPoint = submenu1.ScreenToWindow(mouseX, mouseY)
submenu1.HoverMouse(objectPoint.X, objectPoint.Y)
Delay(500)

 

#Submenu2
mouseX = Sys.Desktop.MouseX
mouseY = Sys.Desktop.MouseY
mouseX = mouseX + submenu1.Width
submenu2 = Sys.ObjectFromPoint(mouseX, mouseY)
objectPoint = submenu2.ScreenToWindow(mouseX, mouseY)
Delay(500)


submenu2.Click(objectPoint.X, objectPoint.Y)

 

This all works to click the menus, but I really want to access the menus by name instead of X,Y coordinates.  What is the best way to access the menu items by Header name or even by WPF Object name?

 

 

 

  • shankar_r's avatar
    shankar_r
    Community Hero

    TestComplete provides access to popup menu objects. 

     

    Have you tried below,

    1. Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot.Click("<ITem name or Index>")
    2. Aliases.MyApp.HwndSource_mainWindow.mainWindow.tabControl1.listBoxDevices.Items(0).Popup.Clcik("<ITem name or Index>")
    3. If you are not able to find a solution with above two steps then try to record the action and see how TestComplete clicks. You will find a idea here.

    Still you are not able to resolve prove some snapshots of Object properties etc.

    • RandyJ5150's avatar
      RandyJ5150
      Occasional Contributor

      The recorded action converted to the following steps:

      Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot.Click(58, 105)
      Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot.Click(68, 11)
      Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot.Click(64, 15)

       

      The image snapshots for each step above showed the correct submenu, but when run, all of the clicks occured in the first-level menu, not the submenus.  Additionally, these are still based on relative X,Y coordinates of the object.  I would like to access the menu items by name, header, or possibly even a tag in the WPF object.

       

      The TC Click Action accepts X,Y coordinates, so name or index will not work as parameters there.

       

      Others report success using FindChild, but I have not been able to get FindChild to return the menu item object.

       

      The object returned by Point and Fix object:
      Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot.WPFObject("Decorator", "", 1).WPFObject("NonLogicalAdornerDecorator", "", 1)

       

      I'm thinking I need to poke around this object somehow.

       

      • RandyJ5150's avatar
        RandyJ5150
        Occasional Contributor

        Poking around the Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot.WPFObject("Decorator", "", 1).WPFObject("NonLogicalAdornerDecorator", "", 1) object has been enlightening, but I cannot figure out how to access the menu items by name.  I know this has been solved because I see other solutions.  Can someone help me understand what I'm working with?

         

        While poking around, I did write the following snippet and received the following results.  Am I barking up the right tree or pursuing a futile course of action?  Can someone explain what these object are?

         

         

        Script:

        # Attempting to figure out how to access context menu items by names, so far unsuccessful
        arrayproperties=["ClrClassName"]
        arrayvalues=["*"]
        something = Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot.FindAll(arrayproperties, arrayvalues, 100, True)
        for x in range(len(something)):
          Log.Message("something[" + str(x) + "]" + something[x].ClrClassName + ", " + something[x].Name)
          somethingelse = something[x].FindAll(arrayproperties, arrayvalues, 100, True)
          for y in range(len(somethingelse)):
            Log.Message("somethingelse[" + str(y) + "]" + somethingelse[y].ClrClassName + ", " + somethingelse[y].Name)

         

        Output:

        something[0]PopupRoot, WPFObject("PopupRoot", "", 1)
        somethingelse[0]PopupRoot, WPFObject("PopupRoot", "", 1)
        somethingelse[1]Decorator, WPFObject("Decorator", "", 1)
        somethingelse[2]NonLogicalAdornerDecorator, WPFObject("NonLogicalAdornerDecorator", "", 1)
        somethingelse[3]AdornerLayer, WPFObject("AdornerLayer", "", 2)
        somethingelse[4]AdornerLayer, WPFObject("AdornerLayer", "", 1)
        something[1]Decorator, WPFObject("Decorator", "", 1)
        somethingelse[0]Decorator, WPFObject("Decorator", "", 1)
        somethingelse[1]NonLogicalAdornerDecorator, WPFObject("NonLogicalAdornerDecorator", "", 1)
        somethingelse[2]AdornerLayer, WPFObject("AdornerLayer", "", 2)
        somethingelse[3]AdornerLayer, WPFObject("AdornerLayer", "", 1)
        something[2]NonLogicalAdornerDecorator, WPFObject("NonLogicalAdornerDecorator", "", 1)
        somethingelse[0]NonLogicalAdornerDecorator, WPFObject("NonLogicalAdornerDecorator", "", 1)
        somethingelse[1]AdornerLayer, WPFObject("AdornerLayer", "", 2)
        somethingelse[2]AdornerLayer, WPFObject("AdornerLayer", "", 1)
        something[3]AdornerLayer, WPFObject("AdornerLayer", "", 2)
        somethingelse[0]AdornerLayer, WPFObject("AdornerLayer", "", 2)
        something[4]AdornerLayer, WPFObject("AdornerLayer", "", 1)
        somethingelse[0]AdornerLayer, WPFObject("AdornerLayer", "", 1)

         

  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor

    While I don't recommend keeping unedited Mappings and code from a recording for your final test, have you tried recording interacting with the context menu?  What happens when you use Object Spy?  

    • RandyJ5150's avatar
      RandyJ5150
      Occasional Contributor

      When we recorded keyword tests, the recording would save the wrong objects from name-mapping. It was over a year-ago and my memory is a little vague, but the results were not what we expected, and we had trouble discerning what we needed.

       

      Here's a Test Visualizer image of the context menu's.  I believe this was produced with the code below.

       

      Three level context menu accessed by right-clicking on an object

       

      Sample Code:

      This is the code where we left-off.  Maybe it will give you some ideas.

      The code:

      #. Set the scroll position
      #. right-click an item in a listbox to cause the 1st level context menu to popup
      #. Call FindAll on PopupRoot and call FindAll of the result to log the results for viewing/debugging (trying to find accessible objects)
      #. Hover the mouse over 1st level menu (looks like the coordinates are hard-coded)
      #. Determine positionally (x,y) where level 2 submenu is
      #. Hover the mouse over the level 2 submenu to cause the 3rd level menu to popup
      #. Determine the position of an item in the 3rd level menu by adding the width of the 2nd level menu
      #. Click on the determined position

       

      Hopefully this will help you find a path forward.  I'm sure we will need to revisit this in the future.  We desperately need a solution.  We use context menu's in many places.

       

      # Script is not complete.
      # TODO: need to figure out way to access multi-level context menu items
      
      import ScriptGetMCU
      
      def SystemDiagramOnline1():
          Aliases.CrewWare.HwndSource_mainWindow.mainWindow.tabControl1.scrollViewer1.VScroll.Pos = 0
          Aliases.CrewWare.HwndSource_mainWindow.mainWindow.tabControl1.scrollViewer1.HScroll.Pos = 0
      
          x = ScriptGetMCU.GetMCUIndex()
          Aliases.CrewWare.HwndSource_mainWindow.mainWindow.tabControl1.listBoxDevices.ClickItemR(x)
      
          # Attempting to figure out how to access context menu items by names, so far unsuccessful
          arrayproperties=["ClrClassName"]
          arrayvalues=["*"]
          something = Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot.FindAll(arrayproperties, arrayvalues, 100, True)
          for x in range(len(something)):
            Log.Message("something[" + str(x) + "]" + something[x].ClrClassName + ", " + something[x].Name)
            somethingelse = something[x].FindAll(arrayproperties, arrayvalues, 100, True)
            for y in range(len(somethingelse)):
              Log.Message("somethingelse[" + str(y) + "]" + somethingelse[y].ClrClassName + ", " + somethingelse[y].Name)
      
          contextmenu = Aliases.CrewWare.HwndSource_PopupRoot.PopupRoot
          contextmenu.HoverMouse(60, 100)
          Delay(500)
          
          #Submenu1
          mouseX = Sys.Desktop.MouseX
          mouseY = Sys.Desktop.MouseY
          mouseX = mouseX + contextmenu.Width
          submenu1 = Sys.ObjectFromPoint(mouseX, mouseY)
          objectPoint = submenu1.ScreenToWindow(mouseX, mouseY)
          submenu1.HoverMouse(objectPoint.X, objectPoint.Y)
          Delay(500)
      
          #Submenu2    
          mouseX = Sys.Desktop.MouseX
          mouseY = Sys.Desktop.MouseY
          mouseX = mouseX + submenu1.Width
          submenu2 = Sys.ObjectFromPoint(mouseX, mouseY)
          objectPoint = submenu2.ScreenToWindow(mouseX, mouseY)
          Delay(500)
          submenu2.Click(objectPoint.X, objectPoint.Y)

       

      • brohrbacher's avatar
        brohrbacher
        Occasional Contributor

        RandyJ5150 

         

        Thanks for the information. We also use a lot of context menus in our software. My current workaround is to use the X,Y coordinates within the context menu. Not ideal but it will work for the time being.

         

        I reached out to support to see if there is something I am missing and/or not understanding. It could be an issue with TestComplete dealing with complex context menus.  I ran their notepad example https://support.smartbear.com/testcomplete/docs/app-objects/specific-tasks/standard/menu/displaying-context.html and that seemed to work just fine. I tried replicating what they did within our software but I had no luck. Even had one of the developers take a look and they were stumped and just suggested I use the X,Y coordinates.

         

        I will keep you updated if I hear anything. 

    • brohrbacher's avatar
      brohrbacher
      Occasional Contributor

      tristaanogre 

       

      Object spy sees it as a context menu which is a good sign. However, my problem is that I have items like "Add..., Remove..., Properties..., etc.) which TestComplete recognizes (they get highlighted in the menu) but the actual Click that I want doesn't occur. In other words, TestComplete is highlighting (hovering over) the items in the list and not actually clicking on them.  I even tried using integers like 0,1,2,3 (which is something I don't want to do for obvious reasons) but that method didn't work.

       

      It recognizes that it's a popup context menu and works when I use X,Y coordinates within the context menu and a click occurs. 

       

      I have tried various methods from the documentation and other support cases but can't seem to get anywhere and this issue seems to fall in line with mine.