pyqt4 QComboBox setEditable(True) - How to setMaxLength? - python

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)

Related

QTableWidget Signal and Slot move fields

I wonder if someone knows this.
as in attached pic let's say I have a tabwidget in qt designer and some lineEdit fields. What
I want to achieve is, if the user clicks on a row of the tabwidgets the values of the items will be moved to the lineEdit fields. I saw I can somehow connect them but how to achieve this with the signal and slot functionality in qt designer without programming.
No, it is not possible without implementing code manually as there is no signal to send the text. The logic is:
self.tableWidget.cellDoubleClicked.connect(self.handle_cellDoubleClicked)
# or self.tableWidget.cellClicked.connect(self.handle_cellDoubleClicked)
def cellDoubleClicked(self, row, column):
item = self.tableWidget.item(row, column)
text = item.text() if item is not None else ""
self.lineEdit.setText(text)

When QComboBox is set editable

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.

How to hide QComboBox items instead of clearing them out

I can't find a way to hide QComboBox items. So far the only way to filter its items out is to delete the existing ones (with .clear() method). And then to rebuild the entire QComboBox again using its .addItem() method.
I would rather temporary hide the items. And when they are needed to unhide them back.
Is hide/unhide on QCombobox items could be accomplished?
In case someone still looking for an answer:
By default, QComboBox uses QListView to display the popup list and QListView has the setRowHidden() method:
qobject_cast<QListView *>(comboBox->view())->setRowHidden(0, true);
Edit: fix code according to #Tobias Leupold's comment.
Edit: Python version:
# hide row
view = comboBox.view()
view.setRowHidden(row, True)
# disable item
model = comboBox.model()
item = model.item(row)
item.setFlags(item.flags() & ~Qt.ItemIsEnabled)
# enable item
view.setRowHidden(row, false)
item.setFlags(item.flags() | Qt.ItemIsEnabled)
To build on what #kef answered:
(excuse the C++ on the python question)
By default the QComboBox will use a QListView for the view, thus you can do the following:
QListView* view = qobject_cast<QListView *>(combo->view());
Q_ASSERT(view != nullptr);
view->setRowHidden(row, true);
The one drawback with the above is, that even though the item will be hidden from the popup, the user can still select it using the mouse wheel. To overcome this add the following for the hidden row:
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(combo->model());
Q_ASSERT(model != nullptr);
QStandardItem* item = model->item(row);
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
With the above the row will be hidden and the user will not be able to scroll to it with the mouse wheel.
To unhide it, just do the reverse:
view->setRowHidden(row, false);
item->setFlags(item->flags() | Qt::ItemIsEnabled);
You can use the removeItem() method to remove an item from the QComboBox.
void QComboBox::removeItem ( int index )
Removes the item at the given index from the combobox. This will update the current index if the index is removed.
This function does nothing if index is out of range.
If you don't know the index, use the findText() method.
There are no hide/unhide methods for QComboBox items.
Althought there is no direct way to hide the item of the QComboBox, but you can use QComboBox::setItemData and set the size to (0,0) to hide the item of QComboBox:
comboBox->setItemData(row, QSize(0,0), Qt::SizeHintRole);
Use the setVisible() to alter the visibility of your object:
.setVisible(False) # Not Visible
.setVisible(True) # Visible
To show the item again:
comboBox->setItemData(row, QVariant(), Qt::SizeHintRole);
Note: changing the SizeHintRole doesn't work on OS X.
I came across this thread after getting frustrated with a lack of hide functionality that would keep the item indexing etc.
I got it to work based on #Kef and #CJCombrink answers. This is basically just a python translation.
I had a problem with qobject_cast.
Solved it by setting .setView(QListView()) to the QComboBox.
combo=QComboBox()
combo.setView(QListView())
hide:
combo.view().setRowHidden(rowindex,True)
tmp_item=combo.model().item(rowindex)
tmp_item.setFlags(tmp_item.flags() & ~Qt.ItemIsEnabled)
unhide:
combo.view().setRowHidden(rowindex,False)
tmp_item=combo.model().item(rowindex)
tmp_item.setFlags(tmp_item.flags() | Qt.ItemIsEnabled)
I decided to subclass the QComboBox and add the hide functionality. Bellow is an use example for testing.
You are welcome to use it. I make no assurances.
import sys
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
#subclassed QComboBox with added hide row functionality
class ComboBox_whide(QComboBox):
def __init__(self):
super().__init__()
self.setView(QListView())#default self.view() is a QAbstractItemView object which is missing setRowHidden, therefore a QListView needs to be set
def hide_row_set(self,row,value=True):
"""sets the row accesibility
value=True hides the row"""
self.view().setRowHidden(row,value)#hides the item from dropdown, however the item is stil accesible by moving down with arrow keys or mouse wheel. The following disables solves that
tmp_item=self.model().item(row)
if value:#hide -> disable
tmp_item.setFlags(tmp_item.flags() & ~Qt.ItemIsEnabled)
else:#enable
tmp_item.setFlags(tmp_item.flags() | Qt.ItemIsEnabled)
def hide_row_toggle(self,row):
"""toggles the row accesibility"""
if self.view().isRowHidden(row):#is hidden, therefore make available
self.hide_row_set(row,False)
else:#is not hidden, therefore hide
self.hide_row_set(row,True)
class Main(QMainWindow):
def __init__(self):
super().__init__()
cwidg=QWidget()
clayer=QVBoxLayout()
cwidg.setLayout(clayer)
self.setCentralWidget(cwidg)
#button for testing
self.btn=QPushButton('Button')
self.btn.setCheckable(True)
clayer.addWidget(self.btn)
#subclassed QComboBox
self.combo=ComboBox_whide()
for n in range(3):#add 3 items with tooltips
self.combo.addItem('item%i'%n)
self.combo.setItemData(n,'tip%i'%n,Qt.ToolTipRole)
clayer.addWidget(self.combo)
#button test function - choose either or for testing
self.btn.clicked.connect(self.btn_clicked)
#uncomment for add/remove example self.btn.clicked.connect(self.remove_add_item)
def btn_clicked(self):
self.combo.hide_row_toggle(1)
def remove_add_item(self):# here for naive comparison and to show why removing and adding is not ok
if self.combo.count()==3:
self.combo.removeItem(1)
else:
self.combo.addItem('new')#new "item1" withouth the ToolTip
if __name__ == '__main__':
app = QApplication.instance()
if app is None:#Pyside2 ipython notebook check
app = QApplication(sys.argv)
main = Main()
main.show()
app.exec_()

How can I set auto-scroll for a QtGui.QTextEdit in PyQt4?

So, I have a QtGui.QTextEdit that will be dynamically inserted with plain text based on what the user enters to some other QtGui.QLineEdit. As the user enters text into the QLineEdit, the user would at some point in time need to scroll down to see the latest data.
Is it possible to set an auto-scroll to the QTextEdit (which is just read only, if it matters) so that it is automatically scrolls down to display the latest data entered by the user? If yes, how?
Thanks
when signal QLineEdit::textEdited is emitted, append the text in QLineEdit to QTextEdit, and then:
QTextCursor c = txtedit.textCursor();
c.movePosition(QTextCursor::End);
txtedit.setTextCursor(c);
// txtedit.ensureCursorVisible(); // you might need this also
reference here.

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.

Categories