Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

Accessing ListBoxWrapper class methods

Help
2007-05-11
2013-05-28
  • Hello,
    I am unable to access the ListBoxWrapper methods. I am working with a Visual Basic application.  The following code connects to the application and creates a dialog without problem, then attempts to create a ListBoxWrapper instance but instead creates a HwndWrapper object without the listbox methods.

    from pywinauto import application
    from pywinauto import handleprops
    from pywinauto import controls

    app_tagbt = application.Application()
    app_tagbt.start_(r'<path>\MakeTagbt.exe') # replace <path> with actual path
    dlg_tagbt = app_tagbt.ThunderRT6FormDC

    dlg_tagbt.PrintControlIdentifiers()
    # shows listbox I want to control
    # ThunderRT6FileListBox - ''   (L37, T303, R214, B361)
    #    '3' 'ThunderRT6FileListBox2'

    allwins = app_tagbt.windows_()
    for i in allwins:
        if handleprops.classname(i)=='ThunderRT6FormDC':
            child_nums = [g for g in handleprops.children(i)]
    for j in child_nums:
        if handleprops.controlid(k)==3: # know this is correct from dlg_tagbt.PrintControlIdentifiers()
            cntrl_lbw = controls.win32_controls.ListBoxWrapper(j)

    I suspect that I am supplying an incorrect hwnd even though I get no error and if I try cntrl_lbw.Click() it clicks in the correct window.  Could this be a limitation of the Visual Basic application.  Am I going at this completely wrong?
    Thanks,

    Mike

     
    • Mark Mc Mahon
      Mark Mc Mahon
      2007-05-12

      Hi,

      I meant to answer this earlier in the week - sorry for the delay.

      The reason that it is returning a HwndWrapper is because pywinauto doesn't know that class type - it has to be added to pywinauto for it to be recognized.

      At line 368 of pywinauto/controls/win32_controls.py there is the following data

          windowclasses = [
              "ListBox",
              r"WindowsForms\d*\.LISTBOX\..*",
              "TListBox",]

      You need to add "ThunderRT6FileListBox " as that is the class that VB uses for ListBoxes, e.g.
          windowclasses = [
              "ListBox",
              r"WindowsForms\d*\.LISTBOX\..*",
              "ThunderRT6FileListBox",
              "TListBox",]

      I just did a quick check with Texts() on a very simple listbox in VB (6) and it worked - but then the class names that I saw were "ThunderListBox" and "ThunderFileListBox" - so I cannot be sure that "ThunderRT6FileListBox" will act the same.

      The easiest way to know if you are working with the right control is to use DrawOutline e.g.

      Control.Listbox.DrawOutline()

      # if you have multiple list boxes then you may need
      Control.ListBox2.DrawOutline()

      # if the listbox has a label - then the following may/should work (but probably not in VB - as pywinauto (nor similar tools) cannot see labels :-(
      Control.FileListBox.DrawOutline()

      If it does work - let me know with a reminder to add "ThunderRT6FileListBox" to the list of classes of the official pywinauto. Note the same goes for most other VB controls.

      Hope this helps
        Mark

       
    • Hello Mark,

      I tried adding "ThunderRT6FileListBox","ThunderFileListBox", "ThunderRT6ListBox" and "ThunderRT6DirListBox" to windowclasses like you suggested. Unfortunately it didn't work. In poking around somewhere I noticed that the friendlyclassname of my control was also "ThunderRT6ListBox" so I'm curious if that value would need to be modified as well?

      Since I couldn't access the ListBoxWrapper methods directly I looked at the way you were using SendMessage() inside the methods. Based on this I learned enough to manipulate the VB application controls. And the DrawOutline() method was very useful!

      I ran into a couple of issues that I would like to hear your opinion on.
      The first relates to identifying which process/window is currently running in the application. The VB app. I was trying to control required selection of inputs from 2 different listboxes at which point a plot would be drawn on the main application window. I needed to wait until the plot was drawn before clicking on a commandbutton. I tried using WaitGuiThreadIdle() with different controls/windows
      as the input and got nothing. Would this be a proper application of this method?
      I was eventually able to use timings.WaitUntil() to watch for the focus changing.

      The second issue I had was maintaining focus on the application. I used SetFocus()
      copiously but would still commonly get errors (window not enabled etc.) if I tried working outside the running script. This isn't a huge deal but it would be nice to
      be able to run the script and use my machine for other tasks at the same time. Is
      this unrealistic?

      Thanks very much for your help,
      Mike

       
      • Mark Mc Mahon
        Mark Mc Mahon
        2007-05-18

        Hi Mike,

        hmm - the friendlyclassname should be ListBox if the class names matches. One problem that I discovered when I was doing this myself to answer your earlier post was that I forgot the comma's at the end of the line - resulting in one entry like "ListBoxThunderFileListBox" - so that is something to double check.

        WaitGuiThreadIdle() is not something to be relied on by it's own (or maybe I am using it wrong!). Are all the control active all the time - or they become inactive when the plotting is is on-going? I think the WaitUntil() that you ended up using is probably the best method.

        There are certain operations that will work without the application being automated having focus - but I did not try very hard to ensure that a script would run successfully while you work with other things (this is an extremely hard requirement - and sometimes I just HAVE to resort to simulating key/mouse presses to the active application. (In fact I don't think there is really any way in Windows to send key presses - except to the active window!.

        Thanks
          Mark