Python PyQt Tab Completion example
This is my OLD blog. I've copied this post over to my NEW blog at:
http://www.saltycrane.com/blog/2008/01/python-pyqt-tab-completion-example/
You should be redirected in 2 seconds.
Here is an example Python GUI that implements tab completion. It uses the open source Qt 4.3 toolkit and PyQt 4.3 Python bindings.
A list of words is presented in a list box. As the user types, the list is shortened to show possible matches. If the user presses TAB, the input text is "completed" to the longest possible string match. This may be a whole word or a common substring of multiple words.
This example consists of two basic elements:
MyLineEditis a subclass of theQLineEditclass. It is used as an input box to enter text. I needed to subclassQLineEditbecause I needed to capture the TAB key press event for tab completion. (See this previous post.)-
QListViewandMyListModelimplement a list with a simple model/view architechture.MyListModelis a subclass ofQAbstractListModel. I implemented the requiredrowCountanddatamethods as well as a method calledsetAllDatawhich replaces the entire existing data with a new list of data.
This example makes use of two SIGNALs:
- The
textChangedsignal is emitted each time the user types a letter inside theQLineEditbox. It is connected to thetext_changedmethod which updates the list of words in theQListView.MyListModel'ssetAllDatamethod is used to update the data. - The
tabPressedsignal is a custom signal I added to myQLineEditsubclass. It is emitted each time the user presses the TAB key. This signal is connected thetab_pressedmethod which completes the input to the longest matching substring of the available words.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
LIST_DATA = ['a', 'aardvark', 'aardvarks', 'aardwolf', 'aardwolves',
'abacus', 'babel', 'bach', 'cache',
'daggle', 'facet', 'kabob', 'kansas']
####################################################################
def main():
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
####################################################################
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
# create objects
self.la = QLabel("Start typing to match items in list:")
self.le = MyLineEdit()
self.lm = MyListModel(LIST_DATA, self)
self.lv = QListView()
self.lv.setModel(self.lm)
# layout
layout = QVBoxLayout()
layout.addWidget(self.la)
layout.addWidget(self.le)
layout.addWidget(self.lv)
self.setLayout(layout)
# connections
self.connect(self.le, SIGNAL("textChanged(QString)"),
self.text_changed)
self.connect(self.le, SIGNAL("tabPressed"),
self.tab_pressed)
def text_changed(self):
""" updates the list of possible completions each time a key is
pressed """
pattern = str(self.le.text())
self.new_list = [item for item in LIST_DATA if item.find(pattern) == 0]
self.lm.setAllData(self.new_list)
def tab_pressed(self):
""" completes the word to the longest matching string
when the tab key is pressed """
# only one item in the completion list
if len(self.new_list) == 1:
newtext = self.new_list[0] + " "
self.le.setText(newtext)
# more than one remaining matches
elif len(self.new_list) > 1:
match = self.new_list.pop(0)
for word in self.new_list:
match = string_intersect(word, match)
self.le.setText(match)
####################################################################
class MyLineEdit(QLineEdit):
def __init__(self, *args):
QLineEdit.__init__(self, *args)
def event(self, event):
if (event.type()==QEvent.KeyPress) and (event.key()==Qt.Key_Tab):
self.emit(SIGNAL("tabPressed"))
return True
return QLineEdit.event(self, event)
####################################################################
class MyListModel(QAbstractListModel):
def __init__(self, datain, parent=None, *args):
""" datain: a list where each item is a row
"""
QAbstractTableModel.__init__(self, parent, *args)
self.listdata = datain
def rowCount(self, parent=QModelIndex()):
return len(self.listdata)
def data(self, index, role):
if index.isValid() and role == Qt.DisplayRole:
return QVariant(self.listdata[index.row()])
else:
return QVariant()
def setAllData(self, newdata):
""" replace all data with new data """
self.listdata = newdata
self.reset()
####################################################################
def string_intersect(str1, str2):
newlist = []
for i,j in zip(str1, str2):
if i == j:
newlist.append(i)
else:
break
return ''.join(newlist)
####################################################################
if __name__ == "__main__":
main()
No comments:
Post a Comment