I'm trying to create variables at the top of my script so that users can manipulate it's values without needing to go down into the code. E.g.
# Airports
FROM = "Leeds Bradford"
TO = "Antalya"
...//Later in code
depart_from = driver.find_element_by_id("departure-airport-input")
depart_from.clear()
depart_from.send_keys(FROM)
depart_from = driver.find_element_by_id("destination-airport-input")
depart_from.clear()
depart_from.send_keys(TO)
One thing I can't seem to get my head around is where a user may have a choice between selecting one radio button or the other. At the moment it's rigid where I say click this type of radio button.
return_flight = driver.find_element_by_id('return-flight-selector').click()
But I want the user to decide which radio button to select between the above and below:
one_flight = driver.find_element_by_id('oneway-flight-selector').click()
Is there a way I can do this? I want to assign a number to a radio button, so that all the user needs to do is change a number to get either one or the other? Like for example having a variable call FLIGHT_TYPE = ? ? is either "0" meaning select the return_flight radio button, or "1" meaning select the one_flight radio button.
Sure make a boolean variable and call it, for instance, ONE_WAY. Then, depending on it's value decide which item to click:
ONE_WAY = True
if ONE_WAY:
driver.find_element_by_id('oneway-flight-selector').click()
else:
driver.find_element_by_id('return-flight-selector').click()
Related
I'm working to develop an application where the user enters information into text boxes that are generated when a radio button is selected and the information would be stored in a CSV file. When the application is opened, the first radio button is selected. While this is not an issue, none of the text boxes appear. If one of the radio buttons is selected then the first one is selected the text boxes appear no problem.
Here is the code that generate the radio buttons:
self.radioStaticBox = wx.StaticBox(self.panel,-1,"Material Type: ")
self.radioStaticBoxSizer = wx.StaticBoxSizer(self.radioStaticBox, wx.VERTICAL)
self.radioBox = sc.SizedPanel(self.panel, -1)
self.radioBox.SetSizerType("horizontal")
self.isoRadioButton = wx.RadioButton(self.radioBox,-1, "Isotropic")
self.orthoRadioButton = wx.RadioButton(self.radioBox,-1, "Orthotropic")
self.orthotRadioButton = wx.RadioButton(self.radioBox,-1, "Orthotropic (with thickness)")
self.isoRadioButton.SetValue(True)
self.radioBox.Bind(wx.EVT_RADIOBUTTON, self.set_type)
And the function that the radio buttons are being bound to:
def generate_params(self, event):
self.matStaticBoxSizer.Clear(True)
if self.matType == "Iso":
idSb = wx.StaticBox(self.panel, 0, "Name:")
idSbs = wx.StaticBoxSizer(idSb, wx.HORIZONTAL)
self.idText = wx.TextCtrl(self.panel)
idSbs.Add(self.idText, 0, wx.ALL|wx.LEFT, self.margin)
....
Thanks for the help!
In short, you appear to be defining part of the display in the initial section of your code and then another section in the define function generate_params, this will by definition, excuse the pun, ensure that you do not see what is defined there until that function executes.
Define all of the display items together in the initial section and then populate them within your functions, as appropriate to the function.
In other words, define the screen in one place, the beginning, populate values as and when.
I need to check multiple radio buttons from a qt ui with python.
Up to now we are using something similar to:
if main.ui.radioButton_1.isChecked():
responses["q1"] = "1"
elif main.ui.radioButton_2.isChecked():
responses["q1"] = "2"
elif main.ui.radioButton_3.isChecked():
responses["q1"] = "3"
if main.ui.radioButton_4.isChecked():
responses["q2"] = "1"
elif main.ui.radioButton_5.isChecked():
responses["q2"] = "2"
elif main.ui.radioButton_6.isChecked():
responses["q2"] = "3"
...
Since there are very many buttons and many different categories (q1, q2, ...) I was thinking of optimizing it a bit. So this is what I hoped would work (adopted from How to get the checked radiobutton from a groupbox in pyqt):
for i, button in enumerate(["main.ui.radioButton_" + str(1) for i in range(1, 8)]):
if button.isChecked():
responses["q1"] = str(i - 1)
I get why this doesn't work but writing it I hoped it would.
So I tried to iterate through the buttons using something similar to (Is there a way to loop through and execute all of the functions in a Python class?):
for idx, name, val in enumerate(main.ui.__dict__.iteritems()):
and then use some modulo 3 and such to assign the results. But that doesn't work either. Not sure if it's because i used __ dict __ or something else. The error I got was:
TypeError: 'QLabel' object is not iterable
Now some people could say that implicit is better that explicit and also because of readability the if elif chain is good the way it is but there are 400+ lines of that. Also after reading this post, Most efficient way of making an if-elif-elif-else statement when the else is done the most?, I thought there must be a better and more efficient way of doing this (see examples 3.py and 4.py of the of the accepted answer). Because I need to check the Boolean value of main.ui.radioButton_1.isChecked() and then assign thevalue according to the Buttons group (q1, q2,...), I haven't managed to implement the solution using dictionaries as described in the post.
Am I stuck with the if elif chain or is there a way to not only reduce the LOC but also make the code more efficient (faster)?
It looks like you have used Qt Designer to create your ui, so I would suggest putting each set of radio buttons in a QButtonGroup. This will give you a simple, ready-made API for getting the checked button in a group without having to query each button individually.
In Qt Designer, buttons can be added to a button-group by selecting them, and then choosing Assign to button group > New button group from the context menu. The button IDs (which you will need to use later) are assigned in the order the buttons are selected. So use Ctrl+Click to select each button of a group in the correct order. The IDs start at 1 for each group and just increase by one for each button that is added to that group.
When a new button-group is added, it will appear in the Object Inspector. This will allow you to select it and give it a more meaningful name.
Once you've created all the groups, you can get the checked button of a group like this:
responses["q1"] = str(main.ui.groupQ1.checkedId())
responses["q2"] = str(main.ui.groupQ2.checkedId())
# etc...
This could be simplified even further to process all the groups in a loop:
for index in range(1, 10):
key = 'q%d' % index
group = 'groupQ%d' % index
responses[key] = str(getattr(main.ui, group).checkedId())
Another way to do it is using signals. If you had lots of radio button in an application, I suspect this kind of approach would be noticeably faster. For example:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class MoodExample(QGroupBox):
def __init__(self):
super(MoodExample, self).__init__()
# Create an array of radio buttons
moods = [QRadioButton("Happy"), QRadioButton("Sad"), QRadioButton("Angry")]
# Set a radio button to be checked by default
moods[0].setChecked(True)
# Radio buttons usually are in a vertical layout
button_layout = QVBoxLayout()
# Create a button group for radio buttons
self.mood_button_group = QButtonGroup()
for i in xrange(len(moods)):
# Add each radio button to the button layout
button_layout.addWidget(moods[i])
# Add each radio button to the button group & give it an ID of i
self.mood_button_group.addButton(moods[i], i)
# Connect each radio button to a method to run when it's clicked
self.connect(moods[i], SIGNAL("clicked()"), self.radio_button_clicked)
# Set the layout of the group box to the button layout
self.setLayout(button_layout)
#Print out the ID & text of the checked radio button
def radio_button_clicked(self):
print(self.mood_button_group.checkedId())
print(self.mood_button_group.checkedButton().text())
app = QApplication(sys.argv)
mood_example = MoodExample()
mood_example.show()
sys.exit(app.exec_())
I found more information at:
http://codeprogress.com/python/libraries/pyqt/showPyQTExample.php?index=387&key=QButtonGroupClick
http://www.pythonschool.net/pyqt/radio-button-widget/
I have a listbox in Tkinter and I would like to change the item selected programatically when the user presses a key button. I have the keyPressed method but how do I change the selection in the Listbox in my key pressed method?
Because listboxes allow for single vs. continuous vs. distinct selection, and also allow for an active element, this question is ambiguous. The docs explain all the different things you can do.
The selection_set method adds an item to the current selection. This may or may not unselect other items, depending on your selection mode.
If you want to guarantee that you always get just that one item selected no matter what, you can clear the selection with selection_clear(0, END), then selection_set that one item.
If you want to also make the selected item active, also call activate on the item after setting it.
To understand about different selection modes, and how active and selected interact, read the docs.
If you need ListboxSelect event to be also triggered, use below code:
# create
self.lst = tk.Listbox(container)
# place
self.lst.pack()
# set event handler
self.lst_emails.bind('<<ListboxSelect>>', self.on_lst_select)
# select first item
self.lst.selection_set(0)
# trigger event manually
self.on_lst_select()
# event handler
def on_lst_select(self, e = None):
# Note here that Tkinter passes an event object to handler
if len(self.lst.curselection()) == 0:
return
index = int(self.lst.curselection()[0])
value = self.lst.get(index)
print (f'new item selected: {(index, value)}')
I'm trying to work on a GUI done in pyqt. I'm trying to create a pop-up window has a textbox where a user can type/set the user's id (1-99) and then click an 'ok' button to set it and close the window.
This is what I have so far.
def viewProfile(self)
profBox = QMessageBox()
QMessageBox.about(self, 'Profile', "///Text box where can type User ID:// ",
QMessageBox.Ok)
I am not sure how to generate the textbox.
Also, if I want to display the integer value or string of a variable in my message window /box do I just leave it out of quotation marks but include it? What's the syntax for it?
Thank you!
You want to use a QInputDialog. This has a bunch of static methods which generate a complete dialog, and return the selected integer when the user clicks OK. This means you don't need to worry about creating a dialog object, adding widgets and buttons, etc.
So you would want to call:
parent_window = self #probably..., depends on your code
minimum_value = 1
maximum_value = 99
default_value = 1
title = "Profile"
message = "Select your user ID"
user_id, ok = QInputDialog.getInt(parent_window, title, message, default_value, minimum_value, maximum_value)
When the QInputDialog line of code runs, a dialog will be presented to the user. When the user clicks OK or Cancel, the entered user_ID will be placed in user_id and ok will be a boolean value that indicates whether the OK button was clicked (True if the OK button was clicked, False if the cancel button was clicked)
If you want to place an integer in the message, you could do something like:
message = "Select your user ID. An integer I want you to know about is %d. I hope you find that useful."%my_integer
But that is really a Python string formatting question, which you should research separately. In short, in my example you can display one string. How long, that string is, is up to you (it can be multiple lines, have new line characters, etc)
You should use QDialog. That way you can customize it the way you want (add textbox, button...)
Take a look at my answer here, basically it's log-in dialog created in QTDesigner, but you can create it with code since it's way more simplier
[ ]All1 [ ]All2
[ ]checkbox1A [ ]checkbox1B
[ ]checkbox2A [ ]checkbox2B
Based on the chart above, a few things need to happen:
The All checkboxes only affect the on/off of the column it resides in, and checks on/off all the checkboxes in that column.
All checkboxes work in pairs, so if checkbox1A is on/off, checkbox1B needs to be on/off
If an All checkbox is checked on, and then the user proceeds to check off one or more checkbox in the column, the All checkbox should be unchecked, but all the checkboxes that are already checked should remain checked.
So really this is more like a chain reaction setup. If checkbox All1 is on, then chieckbox1A and 2A will be on, and because they are on, checkbox1B and 2B are also on, but checkbox All2 remains off. I tried hooking up the signals based on this logic, but only the paired logic works 100%. The All checkbox logic only works 50% of the time, and not accurately, and there's no way for me to turn off the All checkbox without turning all already checked checkboxes off.
Really really need help ... T-T
Sample code:
cbPairKeys = cbPairs.keys()
for key in cbPairKeys:
cbOne = cbPairs[key][0][0]
cbTwo = cbPairs[key][1][0]
cbOne.stateChanged.connect(self.syncCB)
cbTwo.stateChanged.connect(self.syncCB)
def syncCB(self):
pairKeys = cbPairs.keys()
for keys in pairKeys:
cbOne = cbPairs[keys][0][0]
cbOneAllCB = cbPairs[keys][0][4]
cbTwo = cbPairs[keys][1][0]
cbTwoAllCB = cbPairs[keys][1][4]
if self.sender() == cbOne:
if cbOne.isChecked() or cbTwoAllCB.isChecked():
cbTwo.setChecked(True)
else:
cbTwo.setChecked(False)
else:
if cbTwo.isChecked() or cbOneAllCB.isChecked():
cbOne.setChecked(True)
else:
cbOne.setChecked(False)
EDIT
Thanks to user Avaris's help and patience, I was able to reduce the code down to something much cleaner and works 100% of the time on the 1st and 2nd desired behavior:
#Connect checkbox pairs
cbPairKeys = cbPairs.keys()
for key in cbPairKeys:
cbOne = cbPairs[key][0][0]
cbTwo = cbPairs[key][1][0]
cbOne.toggled.connect(cbTwo.setChecked)
cbTwo.toggled.connect(cbOne.setChecked)
#Connect allCB and allRO signals
cbsKeys = allCBList.keys()
for keys in cbsKeys:
for checkbox in allCBList[keys]:
keys.toggled.connect(checkbox.setChecked)
Only need help on turning off the All checkbox when the user selectively turns off the modular checkboxes now
If I'm understanding your data structure, I have a solution. Correct me if I'm wrong: allCBList is a dict (confusing name! :) ). Its keys are the all* checkboxes. And a value allCBList[key] is a list with checkboxes associated with that all checkbox. For your example structure it'll be something like this:
{ All1 : [checkbox1A, checkbox1B],
All2 : [checkbox2A, checkbox2B]}
Then what you need to is this: when a checkbox is toggled and it is in checked state, then you need to check the All* checkbox if all the other checkboxes are in checked state. Otherwise it will be unchecked.
for key, checkboxes in allCBList.iteritems():
for checkbox in checkboxes:
checkbox.toggled.connect(lambda checked, checkboxes=checkboxes, key=key: key.setChecked(checked and all(checkbox.isChecked() for checkbox in checkboxes))
I guess, this statement requires a bit of explanation:
lambda checked, checkboxes=checkboxes, key=key:
lambda creates the callable that is connected to the signal. toggled passes checkbox status, and it will be passed to checked variable. checkboxes=checkboxes and key=key parts pass the current values to checkboxes and key parameters of the lambda. (You need this because of the closure in lambdas)
Next comes:
key.setChecked(...)
We are setting the checked state of key which is the appropriate All* checkbox. And inside this:
checked and all(checkbox.isChecked() for checkbox in checkboxes)
all is True if everything inside is True, where we check every checkboxs state. And this will return True if all are checked (i.e. isChecked() returns True).
checked and ... part is there to short-circuit the all. If the current checkbox turns unchecked, then we don't need to check others. All* would be unchecked.
(PS: By the way, you don't need to get .keys() of a dict to iterate over keys. You can just iterate over the dict and it will iterate over its keys.)
Edit: Just to avoid chain reaction with All* checkboxes toggled by clicking any sub-checkboxes, it's necessary to change the signal for All* checkboxes to clicked, instead of toggled. So, the All* check boxes will affect other below them only in the case of user interaction.
In the end, your modified code will be:
# Connect checkbox pairs
# you just use the values
# change 'itervalues' to 'values' if you are on Python 3.x
for cbPair in cbPairs.itervalues():
cbOne = cbPair[0][0]
cbTwo = cbPair[1][0]
cbOne.toggled.connect(cbTwo.setChecked)
cbTwo.toggled.connect(cbOne.setChecked)
# Connect allCB and allRO signals
# change 'iteritems' to 'items' if you are on Python 3.x
for key, checkboxes in allCBList.iteritems():
for checkbox in checkboxes:
key.clicked.connect(checkbox.setChecked)
checkbox.toggled.connect(lambda checked, checkboxes=checkboxes, key=key: key.setChecked(checked and all(checkbox.isChecked() for checkbox in checkboxes))
Your problem is that your checkboxes are connecting the toggled signal and toggling their state in your connected slots so the signal is emitted again (so the slots are executed again...) and you get unpredictable results. Obviously that is not your wanted behavior. You can fix it in several ways:
by disconnecting the signals at the beginning of the slots and connecting them again at the end
by using some clever code that controls the re-emission of signals (I think this is what Avari's code does in a very compact way, but I'm not completely sure)
by using a clicked signal because it is not re-emitted when the checkbox state changes
Which approach you follow is up to you. The following code uses the third approach:
self.cbPair = {}
self.cbPair['0'] = (QtGui.QCheckBox('all1', parent),
QtGui.QCheckBox('all2', parent))
self.cbPair['1'] = (QtGui.QCheckBox('1a', parent),
QtGui.QCheckBox('1b', parent))
self.cbPair['2'] = (QtGui.QCheckBox('2a', parent),
QtGui.QCheckBox('2b', parent))
for v in self.cbPair.values():
for cb in v:
cb.clicked.connect(self.updateCB)
def updateCB(self):
cb = self.sender()
is_checked = cb.isChecked()
id = str(cb.text())
try:
# Update a whole column
column = int(id[-1]) - 1
rows = ('1', '2')
except ValueError:
# Update a row and the headers row
rows = (id[0], )
column = {'a': 1, 'b': 0}.get(id[-1])
if not is_checked:
for c in (0, 1):
self.cbPair['0'][c].setChecked(is_checked)
for r in rows:
self.cbPair[r][column].setChecked(is_checked)
Note that I'm using the checkboxes text as a UID from wich row and colum values are calculated. If you want to use different text labels for your checkboxes you may need to set the UIDs as attributes to every checkbox.