When QComboBox is set editable - python

The code below creates QComboBox and QPushButton both assigned to the same layout. Combobox is set to be editable so the user is able to type a new combobox item's value.
If the user hits Tab keyboard key (instead of Enter) the New Value will not be added to the ComboBox.
Question: How to make sure the ComboBox's items are updated with the New Value even if the user leaves the ComboBox with Tab key?
from PyQt4 import QtGui
def comboActivated(arg=None):
print '\n ...comboActivated: %s'%arg
widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout()
widget.setLayout(layout)
combo = QtGui.QComboBox()
combo.setEditable(True)
combo.addItems(['One','Two','Three'])
combo.activated.connect(comboActivated)
layout.addWidget(combo)
layout.addWidget(QtGui.QPushButton('Push'))
widget.show()

When a user edits the text in the box, the editTextChanged() signal is emitted with the edited text as its argument. In addition, when the widget itself loses focus, as when the user types Tab to move to the button, the widget emits the focusOutEvent() signal. The argument for this signal is a QFocusEvent, which you can query for the reason focus was lost. The reason() method of the event would return Qt.TabFocusReason, for example, if the user hit the Tab button to leave the widget.
You can connect a slot to either (or both) of these signals, so that when the user leaves the widget after editing text, you process it and add it to the box's list of values.
You may also want to look into the QValidator class and its subclasses, which you attach to widgets with editable text, and define the types of valid input for the widget (e.g., integers, text, etc.). This is the best and easiest way to verify a user's input for editable widgets.

Related

PyQt5 connect Enter key to Widget

Currently I am working with my own custom widget that consists of a QLineEdit and a QPushButton. A user is limited to entering an integer between 0 and 1000 in the text field. Upon clicking the button, the widget's custom clicked signal emits the value in the field.
Here is the code:
class ResizeWidget(QWidget):
clicked = pyqtSignal(int)
def __init__(self):
super().__init__()
#NumField and Button
self.field = QLineEdit()
self.field.setPlaceholderText("Resize Percentage [0,1000]")
self.resizeButton = QPushButton("Resize")
#Layout
self.lay = QHBoxLayout()
self.setLayout(self.lay)
#Add to Widget
self.lay.addWidget(self.field)
self.lay.addWidget(self.resizeButton)
#Field limits
self.field.setMaxLength(4)
self.field.setValidator(QIntValidator(0,1000))
#Connection
self.resizeButton.clicked.connect(self.onClick)
#pyqtSlot()
def onClick(self):
val = int(self.field.text())
self.clicked.emit(val)
Now what I'd like to add to the class is some way of allowing the user to press enter when the blinking cursor | sometimes called a 'caret' is in the text field.
I am able to find documentation on the mouse in general, mouseEvent and mousePressEvent as a method within QWidgets. But I can't find any documentation that refers to the blinking cursor within the text field.
I would like to add some sort of pseudocode like this within init():
if(cursor == inQLineEdit and pressedEnter):
self.onClick()
I know QLineEdit::returnPressed plays a major role in creating the correct function but I only want the enter key to be valid if the user is using the ResizeWidget. Not some other part of my GUI. I would think the enter key isn't binded to only 1 widget in my entire application but I'd be interested to find out.
It was as simple as adding the following line:
self.field.returnPressed.connect(self.onClick)
As long as the caret (blinking cursor) isn't in the text field, pressing the Enter key doesn't cause any reaction from my custom widget.

How to toggle enabled state of widgets based on QcomboBox index

I am using pyQT 4.8.3 in order to create a proper GUI for a QGIS plugin
There are three widgets in the form
my_comboBox , my_lineEdit , my_spinBox
Assume that comboBox has three entries
'combo_first_item' , 'combo_second_item' , 'combo_third_item'
What exactly I want is;
if 'combo_second_item' is selected, then my_lineEdit toggles state to disabled
if 'combo_third_item' selected, then my_spinBox toggles state to disabled
So, how can I toggle enabled state of widgets in the form based on selected string (or index value) from the combobox?
What should be the proper signal -> slot assignment?
Unlike QbuttonBox, QcomboBox does not fire SetDisabled slot
Thanks.
Make a dictionary that maps the string to widget:
widgets = {'combo_first_item': my_comboBox,
'combo_second_item': my_lineEdit,
'combo_third_item': my_spinBox}
And a slot:
def disableWidget(currentIndex):
widget = widgets[currentIndex]
widget.setEnabled(False)
# or anything else you want to do on the widget
Then you can connect the currentIndexChanged[QString] signal to this:
comboBox.currentIndexChanged['QString'].connect(disableWidget)
Alternatively you can use currentIndexChanged[int] and a list instead of a dictionary.
PS: If this is inside a class instance, put self accordingly.

How to configure Tkinter Listbox to disable state keeping selected item highlighted

I am having a problem configuring a listbox widget such that the selection remains highlighted even while it is set (programmatically) to the DISABLED state. Below code shows the problem:
from Tkinter import *
master = Tk()
listbox = Listbox(master)
listbox.pack()
listbox.insert(END, "Text1")
listbox.insert(END, "Text2")
listbox.insert(END, "Text3")
listbox.selection_set(first=0, last=None)
listbox.configure(exportselection=False)
listbox.configure(state=DISABLED)
Now when I change state to NORMAL, selected item is being highlighted. Is there a way I could disable widget (i.e. No response on mouse clicks) but keep the selected object remain highlighted?
Intent:
I want to utilise this widget on wizard App that I am creating. I would like this widget to indicate the current page / wizard number which the user selected. Is there any other widget I could use instead of it? (Labels possibly?)
You can leave it enabled but remove or override all of the default bindings; that would give you the effect that you want.
You can remove all the default bindings by removing the "Listbox" bindtag, or by adding your own bindings that override the default ones.
Here's how to set the bindtags so that all of the standard Listbox bindings are removed:
listbox.bindtags((listbox, master, "all"))

Big number of pushbuttons and smart checking which is checked

I have dialog:
It contains many flat QPushButtons, QTextEdit and another QPushButton. After click on 'Get list' we can see list of checked buttons in QTextEdit.
My question is how to get this functionality in some smart way. Right now I'm checking every button:
if self.ui.bq6o.isChecked():
cards.append("Q6o")
if self.ui.bk2o.isChecked():
cards.append("K2o")
if self.ui.bq3o.isChecked():
cards.append("Q3o")
if self.ui.bt7s.isChecked():
cards.append("T7s")
if self.ui.bq4o.isChecked():
cards.append("Q4o")
if self.ui.bt4s.isChecked():
cards.append("T4s")
if self.ui.b98o.isChecked():
cards.append("98o")
if self.ui.bjto.isChecked():
cards.append("JTo")
if self.ui.btt.isChecked():
cards.append("TT")
if self.ui.bq7o.isChecked():
cards.append("Q7o")
[...]
Obviously I can't like code like that. I was looking for some widget "button matrix" like, but without luck. I will be grateful for advises.
All the buttons should be children of the same widget, probably the dialog itself. Just get a handle to that widget to get all the child buttons, then loop through them and if they're checked, included their text.
parent = dialog # or whatever
cards = [widget.text() for widget in parent.children() if isinstance(widget, QPushButton) and widget.isChecked()]
You may need to include some code in the if statement to exclude the "Get List" button, or any other pushbuttons in your dialog that could be set to "checked" but shouldn't be included in cards list.
As #Brendan suggested in the other question, you could loop through them in a single list comprehension. But one other approach is to connect each buttons toggled signal to a slot that allows them to register when they are checked.
# somewhere in your class
self.checkedList = set()
def buttonChecked(self, checked):
button = self.sender()
if checked:
self.checkedList.add(button)
else:
if button in self.checkedList:
self.checkedList.remove(button)
# when you create a new button
button.toggled.connect(self.buttonChecked)
This would let you always have a set of just the checked buttons, which are self reporting. Otherwise, you would have to track them under their parent and loop to find out which are checked each time.
Update
Here is a another version that combines #Brendans loop and my signal suggestion. This might help in a situation where your buttons are a bit more spread out across your UI as opposed to be all under a single parent... but first assuming them all under a parent...
parent = dialog
for widget in parent.children():
if isinstance(widget, QPushButton):
widget.toggled.connect(self.buttonChecked)
You could repeat this in your __init__() for all the locations of your buttons and get them all registered to the slot.

pyqt4 QComboBox setEditable(True) - How to setMaxLength?

I have a QComboBox that is tied to database VARCHAR(45) field.
The QComboBox dropdown list provides a set of default values but it is EDIT enabled and user can enter anything in it.
I want to limit the user entry length to max of 45 chars
QComboBox does not have a setMaxLength(int) like QLineEdit does.
Anyone have any suggestions?
self.myDropDown = QComboBox()
self.myDropDown.setEditable(True)
Thanks
If a combo-box is editable, its lineEdit method will give access to its line-edit widget:
self.myDropDown = QComboBox()
self.myDropDown.setEditable(True)
self.myDropDown.lineEdit().setMaxLength(45)

Categories