PywinAuto and the disappearing control Identifier - python

I'm using pywinauto (the latest from the new github) to automate logging in to another program. The "Sign in" window has a bunch of buttons, and two fields, one for user name and one for password.
My problem is that the user name and password 'edit' control identifiers have the same Access name: ['1', '0', 'Edit']. There is no "Edit2".
When I use
sign_in.print_control_identifiers()
It still only shows the one edit property. How do I access this other edit control?
update with pictures with the demo company file:
Here is the LOGIN window: http://imgur.com/VwS9w0b
Here is the mouse hovering over password: http://imgur.com/6HWQVlZ
Password field clicked, its called edit1 as well! http://imgur.com/GUnTVrK
Swapy output : http://imgur.com/LJB99y1
A solution I found was to simulate a "tab" key
sign_on.TypeKeys("{TAB}")
But this is not a great solution because if another window were to take focus at the time of the TAB then the script would sent the tab to that window.

I'm not sure which version of Pywinauto you are using. There is a revived one on GitHub (https://github.com/pywinauto/pywinauto). You can access controls as elements of a dictionary:
sign_in['0']
sign_in['1']
Highlighting a GUI element can also help to understand what element you refer to:
sign_in['0'].DrawOutline() # green by default
sign_in['1'].DrawOutline('red') # acceptable keywords: 'red','blue','green'
sign_in['Edit'].DrawOutline(0xff0000) # blue
Update the answer with an example of walking through all control's children and highlight them. This way you can see if you have access to the "password" field.
import time
def drawContours(ctl):
for c in ctl.Children():
drawContours(c)
time.sleep(1)
c.DrawOutline()
ctl.DrawOutline()
drawCountours(sign_in)

Edit0 and Edit1 refers to the same first edit box. It's expected behavior (by design). Edit2 refers to the second edit box, Edit3 to the third one etc. If you get print_control_identifiers() output, you usually see something like that ("Find" dialog in Notepad, for example):
Edit - '' (L152, T160, R323, B180)
'Edit' 'Edit0' 'Edit1' 'Fi&nd what:Edit' ()
Edit - '' (L152, T188, R323, B208)
'Edit2' 'Re&place with:Edit' ()
So possible names for best_match search algorithm are listed for each control. These names are trying to be unique (not overlapping with other controls), but one control has several best names. It's normal situation. sign_in['Edit2'] is probably what you need.
If you disagree with such approach, you may raise design discussion here: https://github.com/pywinauto/pywinauto/issues

Related

How to specify input language for Entry or any other input field?

In short, i try to type letters (in input components like "Entry", "Text") that are allowed by Windows language-keyboard (i'm using "Latvan(QWERTY)" keyboard) and i can't write long letters like 'ā', 'č', 'ģ' and others.
For example, when i try to write 'ā', the result is 'â'.
The interesting part - when i focus on specific GUI input fiend and change Windows keyboard-language (with "Alt+Shift" shortcut or manually) twice (for example, from "Latvan(QWERTY)" to "Russian" and back to "Latvan(QWERTY)") - then i can write all letters i needed.
What i want is to set all input fields keyboard-language so i could write all letters i want without doing things mentioned above every time i launch my GUI program.
If you need more info or there is already place where this question is answered, please leave a comment and i will act accordingly.
Edit 1:
I am using PyCharm to write my Python Tkinter code. I tried to assign necessary keyboard to my program's generated GUI form according to this guide but it didn't work (i guess that because i used it on temporary created GUI forms).
I was able to solve my problem by using pynput.
Here is simplified version of my final code:
from tkinter import *
from pynput.keyboard import Key, Controller
def change_keyboard_lang(event):
keyboard = Controller()
for i in range(2):
keyboard.press(Key.alt)
keyboard.press(Key.shift_l)
keyboard.release(Key.shift_l)
keyboard.release(Key.alt)
root = Tk()
word_input = Entry(root)
word_input.focus_set()
word_input.bind("<FocusIn>", change_keyboard_lang)
word_input.pack()
root.mainloop()
In short, if cursor is focused on Entry field "word_input", system calls function "change_keyboard_lang" that changes input language from original to other and back to original - and now i can write necessary letters.
It's not the best solution since i need to bind event to every input field in my GUI form but it gets the job done. If you have a better solution please post it here.

How do I update the data associated with a QListWidgetItem from the QListWidget in PyQt?

I have a QListWidget that has 10 QListWidgetItems. When each of those QListWidgetItems is created I do something like this:
item = QtGui.QListWidgetItem("Text to Show")
item.setData(36, "A specific value that is used later")
self.ui.my_list.addItem(item)
Now, later in the application, after a user clicks a button, I want to update the text "A specific value that is used later", for the item that is selected. I have attempted to do this
ndx = self.ui.my_list.currentRow()
self.ui.my_list.item(ndx).setData(36, "Updated!")
The problem is, this doesn't work. It doesn't throw any errors, but the data is just gone. In my button press signal I have this code to see the value before and after the reassignment:
ndx = self.ui.my_list.currentRow()
print "Before:", self.ui.my_list.item(ndx).data(36).toPyObject()
self.ui.my_list.item(ndx).setData(36, "Updated!")
print "After:", self.ui.my_list.item(ndx).data(36).toPyObject()
This outputs:
Before: A specific value that is used later
After:
How can I properly change the data so that it is saved back to the QListWidgetItem?
You may want to check that the role value your using is a valid user role, otherwise it may be altered internally. I write in c++, but I use the QListWidget and QListWidgetItem(s) frequently, and this was a problem I encountered early on. I imagen that the functionality is similar regardless of the language. According to the documentation here, the first user role that can be used is 0x0010. So to tie it to your example, you might try the following:
item.setData(0x0010, "A specific value that is used later")
For additional item roles you would use 0x0011, 0x0012, 0x0013, etc.

Naming a file the content of a Text Entry Widget

I am trying to create a program in tkinter that allows people to rename a log file to whatever is typed into a text entry box. However this is not going to plan.
EDITED Thanks to Bryan Oakley.
I have slaved the rename function to a button however my new issue is that the values for contents are a weird set of numbers. These appear to be randomly generated every time I run the rename function.
These numbers look like
44499952get
44452520get
46401376get
46400496get
44688048get
44697440get
Can anyone please help or explain what these numbers mean?
Look at this code:
newname_ent = Entry(self,width = 50,)
contents = newname_ent.get()
It seems highly unlikely that the user will be able to type in something in the millisecond or so between creating the widget and getting the value.
You need to create a button or set an event binding that will call a function after the user has the chance to enter some information. That function is where you will put the code to do the rename.

How to get a value from QSpinBox, how to disable NextButton in QWizard

Python 3.3, PyQt 4.8.4. My knowledge of PyQt and Python (and English, I think;)) isn't good, so there are many questions in my studies. I made a draft in Qt Designer, still I can't understand how to make it work properly. I have wizard, on the first page - 2 QSpinBoxes, second - generated quantity of spinboxes, equals to the entered values in boxes on the first page. Tried to search about signals and slots, but still can't understand.
How to get this value inside my program, to use it for generation of spinboxes on the 2nd page?
Of course, I need to keep other pages out of reach while this first value isn't correct. I think that can be realized by keeping NextButton unavailable, but how - I don't know. Need kind of help!)
My code itself
http://pastebin.com/UxvzFvJR
Launcher was made separately http://pastebin.com/2sYtyg9z
1: Move your spinboxes generate code(line list_x = [] to f += 1) to page2's initializePage. Dirty but works:
class Ui_Wizard(object):
def addSpins(self):
list_x = []
...
...
self.wizardPage2.initializePage = self.addSpins
2: Register them as mandatory field:
self.wizardPage1.registerField("cols*", self.spinBox_col)

PyGtk - Activating a combo box

If I have a combo box in pyGTK and would like to set a list of strings and then on clicking on one activate a command how would I do it?
At the moment I have:
self.combo_key = gtk.Combo()
self.combo_key.set_popdown_strings(self.keys)
self.combo_key.entry.set_text(db.keys()[0])
self.combo_key.entry.connect("activate", self.key_sel)
But "activate" only calls after selection, and then by pressing enter. I'm also getting a deprecation warning for gtk.Combo() but cannot find any help on using gtk.ComboBoxEntry()
Any help guys?
Try using a gtk.ComboBox instead of gtk.Combo, since the latter is deprecated in favor of the former. To initialise, you can you code like:
liststore = gtk.ListStore(gobject.TYPE_STRING)
for key in self.keys:
liststore.append((key,))
combobox = gtk.ComboBox(liststore)
cell = gtk.CellRendererText()
combobox.pack_start(cell, True)
combobox.add_attribute(cell, 'text', 0)
Now you connect to the changed signal of the combobox and use its get_active() method to ask for the item that was selected.
As you might guess from this explanation, the ComboBox isn't exactly made for this purpose. You probably want to use gtk.Menu.

Categories

Resources