Hello,all! I'm trying to build my own completion in QComboBox. My overall setup with this thing is not working.Apparently I'm doing something wrong here. But what?
What I'm trying to do: let's suppose we have this completion list (for simplicity it's small and with one column only, real data have much more columns). So items goes like this: - item1 - item11 - item111 - item1111 if I type '111' in QComboBox I want a popup with 'item111','item1111' because '111' is only in those items. I'm defined my own TreeView,SourceModel, SourceFilterModel(like proxy for filtering of SourceModel) and bind them to standard QComboBox. Than I did a little trick with passing focus to lineEdit and back to Popup. Well, my whole schema is not working. Python recursively calls 'somethingIsTyped' method in which I'm trying to force popup to be filtered and shown with new data and I got stack overflow catched by python interpreter. Please see attached example with comments. Can anybody enlighten me on what I'm doing wrong? System: Python 2.5, pyqt 4.3.3, qt 4.3.3, winxp. --- [EMAIL PROTECTED]
import sys from PyQt4 import QtCore, QtGui, uic from PyQt4.QtCore import * app = QtGui.QApplication(sys.argv) form_class, base_class = uic.loadUiType("mainform.ui") class SourceModel(QtCore.QAbstractItemModel): """ sample model """ def __init__(self, parent=None): QtCore.QAbstractItemModel.__init__(self, parent) self.colLabels = ["column1","column2"] self.items=[ ['item1' , 'item2' ] , ['item11' , 'item22' ] , ['item111' , 'item222' ] , ['item1111' , 'item2222' ] , ['item11111' , 'item22222' ] , ] def index(self,row,column,parent): return self.createIndex(row,column,str(row)+str(column)) def parent(self, index): if not index.isValid(): return QtCore.QModelIndex() return QtCore.QModelIndex() def rowCount(self, parent): return len(self.items) def columnCount(self, parent): return len(self.colLabels) def data(self, index, role): if not index.isValid(): return QtCore.QVariant() elif role != QtCore.Qt.DisplayRole and role != QtCore.Qt.EditRole: return QtCore.QVariant() row = index.row() col = index.column() return QtCore.QVariant(str(self.items[row][col])) def flags(self, index): if not index.isValid(): return QtCore.Qt.ItemIsEnabled return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable def headerData(self, section, orientation, role): if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole: return QtCore.QVariant(self.colLabels[section]) return QtCore.QVariant() class SourceFilterModel(QtGui.QSortFilterProxyModel): """ used to filter and sort SourceModel. Acts like a proxy """ def __init__(self,parent): QtGui.QSortFilterProxyModel.__init__(self,parent) self.gui = parent def filterAcceptsRow(self,sourceRow,sourceParent): index = self.sourceModel().index(sourceRow,1,sourceParent) # get text from uderlying source model item_text = str(self.sourceModel().data(index,QtCore.Qt.DisplayRole).toString()) # get what user is typed in comboBox typed_text = str(self.gui.autoCombo.lineEdit().text()) # if typed text in item_text - then this item is Ok to show in # resulting filtering model if item_text.find(typed_text) == -1: return False else: return True class myTreeView(QtGui.QTreeView): """ display our model in 2 column plain list with headers """ def __init__(self, parent=None): QtGui.QTreeView.__init__(self, parent) # store MainForm instance for referencing autoCombo later. self.parent = parent def keyPressEvent(self, e): if e.key() in [QtCore.Qt.Key_Escape,QtCore.Qt.Key_Tab,QtCore.Qt.Key_Down,QtCore.Qt.Key_Up]: # escape, tab, Up, Down key events is passed to TreeView so we can # navigate popup list. QtGui.QTreeView.keyPressEvent(self,e) else: # typed chars is passed to autoCombo's lineEdit self.parent.autoCombo.keyPressEvent(e) class MainForm(QtGui.QDialog, form_class): def __init__(self, *args): QtGui.QWidget.__init__(self, *args) self.setupUi(self) self.treeView = QtGui.QTreeView(self) self.treeView.setSelectionMode(QtGui.QAbstractItemView.MultiSelection) self.treeView.setSortingEnabled(True) self.treeView.setAnimated(True) self.treeView.setWordWrap(True) self.treeView.setItemsExpandable(False) self.treeView.setRootIsDecorated(False) self.sourcemodel = SourceModel() self.proxyModel = SourceFilterModel(self) self.proxyModel.setSourceModel(self.sourcemodel) self.autoCombo.setModel(self.proxyModel) self.autoCombo.setView(self.treeView) # # setup a completer in order to turn off inline completion for # comboBox # self.autoCombo.completer().setCompletionMode(QtGui.QCompleter.PopupCompletion) self.autoCombo.clearEditText() self.connect(self.autoCombo, SIGNAL("editTextChanged ( QString )"), self.somethingIsTyped) def somethingIsTyped(self,text): # !!! WARNING: Memory error:Stack overflow !!! catched by python. # # that's where trouble lies... this function is going to be called # recursively until stack overflow. Why? print "editTextChanged ->",text # hide old popup self.autoCombo.hidePopup() print "now going to invalidate filter" # this is going to call filterAcceptsRow of SourceFilterModel # indirectly.We can compare what user is typed in lineEdit and what is # in our model and filter model's items self.proxyModel.invalidateFilter() # force popup to display new filtered content self.autoCombo.showPopup() # set focus back to autoCombo's lineEdit self.autoCombo.lineEdit().setFocus() form = MainForm() form.show() app.exec_()
mainform.ui
Description: Binary data
_______________________________________________ PyQt mailing list PyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt