How to use a for loop to iterate over dynamically named variables (var1, var2, ...) - pyqt5

I am trying to make a GUI using PyQt5.
I have a couple of buttons say 4 which call the same function. A click on a button calls the same function to plot the data associated with each button.
radiobutton1.clicked.connect(self.fun)
radiobutton2.clicked.connect(self.fun)
radiobutton3.clicked.connect(self.fun)
radiobutton4.clicked.connect(self.fun)
Since each line of code is the same except the name of the button, is there a way instead of writing almost the same code four times, I use a for loop to generate the code?

You should initialize them in a loop, then append all of the objects to a list. Then, in this case, all you'd have to do is iterate over the list and call the .clicked.connect() method on each object.
radio_buttons = list()
for i in range(1, 5):
temp_radio_button = QRadioButton("Radio Button")
radio_buttons.append(temp_radio_button)
....
for radio_button in radio_buttons:
radio_button.clicked.connect(self.fun)

I know it does not apply to this case, but for those who use QtDesigner and need to access the widgets later, this can be an option:
def get_all_objects(self,label,window,widget_class):
for widget in filter(lambda entry: match(label,entry.objectName()),window.findChildren(widget_class)):
yield widget
for widget in self.get_all_objects('radiobutton',MainWindow,QtWidgets.QRadioButton):
widget.clicked.connect(self.fun)
Note:MainWindow can be replaced by a page on a StackedWidget if all your target widgets are in the same page.

Related

Click on first element contained in a div

I have a div that contains a set of dynamic elements. I want to click on the first search result.
I want to click on the first element contains in
I tried using creating a custom xPath like so but it didn't work. Any ideas here?
//div[1][contains(text(), 'listing')]
First of all It would've helped if you had provided more information.
best will be using pseudo-child like div.firstChild or if the elements are generated dynamically you can add a class and use document.querySelectorAll(".class") which will give you an array of elements that had the class.
You can use array[0] to use click on the first element.
For anyone coming across this thread here is the solution
const listings = await page.$x('//*[contains(#id,"listing_")]')

PyQt 5 Hiding and showing widgets an dealing with List Widgets

I am pretty new to Python and very new to PyQt. Just trying to find a solution on how to hide widgets that do not need to be shown until a button is clicked. Also can't figure out the syntax with items in a list widget. If x is clicked in a list widget it will execute y.
If you want to trigger a slot when clicking items in QListWidget,
you can use itemClicked signal to accomplish it,
Hear is an example,
class YourListWidget(QListWidget):
def __init__(self, parent=None):
super(YourListWidget, self).__init__(parent)
self.itemClicked.connect(self.do_something)
def do_something(self, item):
# item is the item you clicked, it is a QListWidgetItem object
# you can see its name by calling text() method of QListWidgetItem,
# or do anything you want in this slot.
print(item.text())

How should a test be written for a delegate for editing?

I have a tree view for which some fields need to use a custom delegate for editing. The delegate presents a QListView for value selection. It seems like the QAbstractItemView.edit() method should be used to initiate the edit from the test but I can't figure out how to get access to the created editor (a QListView) so I can select the proper element for the test.
This is part of a test I had working with a QComboBox delegate before switching to the QListVew, but it seems too manual.
for index, enumerator in enumerate(group.children):
editor = delegate.createEditor(
parent=viewport,
option=None,
index=target_index,
)
editor.setCurrentIndex(index)
delegate.setModelData(editor, model, target_index)
assert enumerator.uuid == item.enumeration_uuid
https://github.com/altendky/st/commit/643c5c30f87fc3bfd8b422687e81f740ec36ef44#diff-06bc81dbbd9f7a12878169d5238e1572R846
Here is what I came up with.
https://github.com/altendky/st/blob/089432162b9e8ca67eafdfcc2a4ecc34e8f0e96e/epyqlib/tests/test_attrsmodel.py#L848
for row, enumerator in enumerate(group.children):
assert view.edit(
target_index,
PyQt5.QtWidgets.QAbstractItemView.AllEditTriggers,
None,
)
editor, = view.findChildren(PyQt5.QtWidgets.QListView)
index = editor.model().index(row, 0, editor.rootIndex())
editor.setCurrentIndex(index)
editor.clicked.emit(index)
# this is fun. if you get weird issues try doing this more times
for _ in range(3):
application.processEvents()
assert enumerator.uuid == item.enumeration_uuid
Do note that I connect the editor's clicked signal to post an enter-key event since the view's are hardcoded to catch an enter event and finish editing.

What's the proper way to access a previous page's elements using Protractor?

I have a test where I click through list of links on a page. If I open the links in new pages, I can iterate through the list using browser.switchTo().window and the original window's handle, clicking on each one.
But if I open a link in the same page (_self) and I navigate back to the original list of links using browser.navigate().back(), I get the following error when it iterates to click the next link:
StaleElementReferenceError: stale element reference: element is not attached to the page document
What's the proper way to access elements on a prior page once you've navigated away?
When you request a object from Selenium, Selenium IDs that object with a internal Unique ID. See the below command
>>> driver.find_element_by_tag_name("a")
<selenium.webdriver.firefox.webelement.FirefoxWebElement
(session="93fc2bec-c9f8-0c46-aec3-1939af00c917",
element="5173f7fb-63ca-e447-b176-4a226d956834")>
As you can see the element has a unique uuid. Selenium maintains these list internally, so when you take an action like click, it fetches the element from its cached and takes action on it.
Once the page is refreshed or a new page is loaded, this cache is no longer valid. But the object you created in your language binding still is. If I try and execute some action on its
>>> elem.is_displayed()
selenium.common.exceptions.StaleElementReferenceException:
Message: The element reference of [object Null] null
stale: either the element is no longer attached to the DOM or the page has been refreshed
So in short there is no way to use the same object. Which means you need to alter your approach. Consider the below code
for elem in driver.find_elements_by_tag_name("a"):
elem.click()
driver.back()
Above code will fail on the second attempt of elem.click(). So the fix is to make sure not to re-use a collection object. Instead use a number based loop. I can write the above code in many different ways. Consider few approaches below
Approach 1
elems = driver.find_elements_by_tag_name("a")
count = len(elems)
for i in range(0, count):
elems[i].click()
driver.back()
elems = driver.find_elements_by_tag_name("a")
This is not a very great approach as I am getting a collection of objects and only using one of them. A page which would have 500+ odd links will make this code quite slow
Approach 2
elems = driver.find_elements_by_tag_name("a")
count = len(elems)
for i in range(1, count + 1):
elem = driver.find_element_by_xpath("(//a)[{}]".format(i))
driver.back()
This is better than approach 1 as I am getting all objects just one. Latter I am getting one and using one
Approach 3
elems = driver.find_elements_by_tag_name("a")
links = []
for elem in elems:
links.append(elem.get_attribute("href"))
for link in links:
driver.get(link)
# do some action
This approach will only work when links are href based. So it is that based on the situation I would choose or alter my approach

QTP - Checking dynamic pages

I'm trying to check if a value is contained in the innertext of a webelement but I'm having a little problem: frames seem to change at every refresh of the pages.
These are the steps I've recorded:
Browser("SystemPage").Page("SystemP").Frame("dme2_header").Image("Gestione Anagrafiche").Click<br>
Browser("SystemPage").Page("SystemP").Frame("dme2_appl").WebEdit("pdrBean.pdrPod").Set parameter("POD")<br>
Browser("SystemPage").Page("SystemP").Frame("dme2_appl").WebButton("Cerca").Click
Browser("SystemPage").Page("SystemP").Frame("dme2_appl_2").Image("show_files").Click
Browser("SystemPage").Page("SystemP").Frame("dme2_appl_6").Image("Lente").Click
cctype = Browser("SystemPage").Page("SystemP").Frame("dme2_appl_7").WebElement("arrow_down").GetROProperty("innertext")<br>
DataAct = Browser("SystemPage").Page("SystemP").Frame("dme2_appl_7").WebElement("arrow_down_2").GetROProperty("innertext")<br>
Browser("SystemPage").Page("SystemP").Frame("dme2_header").Image("Gestione Anagrafiche").Click
The frames "dme2_appl6" and "dme2_appl7" changes at every refresh of the two pages.
The question is simple: how can I rewrite these two actions to make them universal?
I've tried to do something like:
Set objFrame = Frame("title:=dme2_appl_.")
and then
Browser("SystemPage").Page("SystemP").objFrame.Image("Lente").Click
But QTP gives me an error in return: "property or method not supported by the object"
Please try using the below code
Browser("SystemPage").Page("SystemP").Image("Lente").Click
Avoid using the "Frame" and if you really want to use it, put regex for name property of Frame.
Go to Object Properties--> Click on the Frame object --> Mandatory Properties--> Change name property as
like iFrame_213123123 to i.*
Hope this will solve your problem.
I don't think you can use a frame object that way. When you write Page().Frame() UFT sets the frame's parent in different way than if you first create the Frame.
Think of Frame() as a function that behaves differently when called on a Page or as a free function.
Try:
Browser("SystemPage").Page("SystemP").Frame("title:=dme2_appl_.")