I have existing PySide6 code.
My class PyProto inherits QTreeView and implements currentChanged().
I am doing automated testing and I need to move the focus to any item in the QTreeView.
When I put a breakpoint on PyProto.currentChanged() and click a new item in the tree view, the breakpoint is hit and the call stack only contains two items: app.exec() and currentChanged().
QUESTIONS
How do I simulate the selection of a new item in the tree view in a way that is transparent to the rest of the app?
Is it enough to call PyProto.currentChanged() from my test code?
How do I obtain a list of the current items in the tree view so that I can call currentChanged()?
Link:
PySide6.QtWidgets.QAbstractItemView.currentChanged(current, previous)
PARAMETERS current – PySide6.QtCore.QModelIndex
previous – PySide6.QtCore.QModelIndex
This slot is called when a new item becomes the current item. The
previous current item is specified by the previous index, and the new
item by the current index.
Related
I have a QTreeWidget with the following shape:
Root
- Item1
-- Sub11
--- Sub111
-- Sub12
--- Sub121
...
When double clicking on any item from the QTreeWidget the selection expands by default (or collapsed if it was already expanded). I created a simple function tree_get_details(self, item, column) to print item and column of the double clicked item and connected it with itemDoubleClicked. This works nicely so far. However how can I make this function available only at bottom layer of the tree (ie for subXXX rows). Hence for Root, Item1, Item2, Sub11, Sub12 just the default behaviour for the double clicked event and for Sub111, Sub121 printing item and column?
Somehow I need to test in my function tree_get_details if the "item" passed in argument is at the bottom layer. I know of the topLevelItem method but can't find the corresponding bottom one (if it exists...). My tree has 4-level hierarchy.
It depends on what exactly you mean with "bottom item".
The usual name for a "bottom item" in a tree is "leaf item".
It is defined as an item without children.
That's something you can check with the QTreeWidgetItem::childCount method (it's a leaf if and only if it returns 0).
If for whatever reason, you want to detect items in the third sub-level, you can count the number of parent items recursively.
That's slightly more complicated and probably not what you want.
I'm trying to write a general test script to find errors in new software builds. My idea is to iterate through the controls in the window and interact with each one, logging any errors that are caused and restarting the software if it crashes.
I'm looking for a way to dynamically find control identifiers, a bit like print_control_identifiers() but with the output being a list or similar structure which I can iterate through.
On a GitHub question about control identifiers this was mentioned:
it's possible to walk the hierarchy by using .children() (immediate children only) and .descendants() (the whole subtree as a plain list)
I assumed I could just iterate through my Application object's descendants() list and call a relavant interaction method for each, however I can't work out how to get this list. I assumed I could do something like this, but I haven't had any success:
def test(application):
for child in application.descendants():
#interact with child control
software = Application(backend='uia').start(cmd_line=FILE_PATH)
test(software)
AttributeError: Neither GUI element (wrapper) nor wrapper method 'descendants' were found (typo?)
EDIT
I resorted to looking through the code and found the print_control_identifiers method:
class Application(object):
def print_control_identifiers(self, depth=None, filename=None):
"""
Prints the 'identifiers'
Prints identifiers for the control and for its descendants to
a depth of **depth** (the whole subtree if **None**).
.. note:: The identifiers printed by this method have been made
unique. So if you have 2 edit boxes, they won't both have "Edit"
listed in their identifiers. In fact the first one can be
referred to as "Edit", "Edit0", "Edit1" and the 2nd should be
referred to as "Edit2".
"""
if depth is None:
depth = sys.maxsize
# Wrap this control
this_ctrl = self.__resolve_control(self.criteria)[-1]
# Create a list of this control and all its descendants
all_ctrls = [this_ctrl, ] + this_ctrl.descendants()
# Create a list of all visible text controls
txt_ctrls = [ctrl for ctrl in all_ctrls if ctrl.can_be_label and ctrl.is_visible() and ctrl.window_text()]
# Build a dictionary of disambiguated list of control names
name_ctrl_id_map = findbestmatch.UniqueDict()
for index, ctrl in enumerate(all_ctrls):
ctrl_names = findbestmatch.get_control_names(ctrl, all_ctrls, txt_ctrls)
for name in ctrl_names:
name_ctrl_id_map[name] = index
# Swap it around so that we are mapped off the control indices
ctrl_id_name_map = {}
for name, index in name_ctrl_id_map.items():
ctrl_id_name_map.setdefault(index, []).append(name)
This shows that .descendants() isn't a method of the Application class, but belongs to the control. I was wrong there it seems. Is it possible to create my own version of print_control-identifiers() which returns a list of control objects that can be iterated through?
Correct method to list top-level windows is application.windows(). Then you can call .descendants() for every listed window. In the most cases application has only one top-level window. Particularly for backend="uia" even new dialogs are children of the main window (for backend="win32" every dialog is a top-level window).
I have a QTreeWidget structure like this:
root
|
groups
|
tables
I am trying to do something when there is a "doubleClick" but ONLY in the the childs called "tables".
The only good result that I have been able to get is:
self.ui.treeWidget.itemDoubleClicked.connect(self.treeWidgetItemAction)
The problem now is that ALL the elements in the QTreeWidget are responding to the "doubleClick". I do not want that, but I do not know how to reference only the children in the final branch of the tree.
Any help??
Thanks.
Just make your treeWidgetItemAction method check whether the doubleCliked item is one that should react on doubleClicks, and only do what you want to do in that case.
To know where an item is a leaf, you could check it's childCount method. If it doesn't have any children, it's a leaf.
Every Item of Tkinter Canvas widget has a unique item id. I can delete the item by using
canvas.delete(itemId)
Now how do I get back the item on the Canvas assuming I have kept the itemId intact?
canvas.add(itemId) # something like this but add is not a canvas method
I read that it can be done in Tcl/Tk but did not find any equivalent reference for tkinter.
The Canvas widget has no add method, but the different create_ methods. If you have already deleted an item and you want to "restore" it, you should get the options of the item before that and then create a new one with the values you have retrieved.
When you delete it, it's gone. You can't get it back. The item id is just an identifier, not an actual object.
when i added an item in a qlistwiget and reaches the bottom. A scroll bar appears, how can i ensurevisible an item that was newly added from the qlistwidget? Or how can i get the focus to the last index?
QListWidget inherits from QAbstractItemView, which has the methods you are looking for:
You can use QAbstractItemView.scrollTo(ModelIndex index), using the index of your newly added item.
Alternatively, since your item is always appended to the end of the list, just call QAbstractItemView.scrollToBottom().
After creating the new QListWidgetItem, pass it to QListWidget.scrollToItem to ensure that it becomes visible.
Note that scrollToItem also has a scroll hint parameter that allows fine-tuning of how the item is re-positioned in the list widget.