[PyQt] Strange behaviour of key_return

Kamp, Peter van der (IMARES) peter.vanderkamp at wur.nl
Thu Apr 5 13:47:52 BST 2012


Hello,

In my application I have a tableview in which the user must be able to scroll through the (editable) cells by using Tab, Key_right and Return. Columns that are disabled must be skipped. When the lower right cell is reached, a new row must be created when one of the before mentioned keys is pressed. To implement this, I reimplemented QTableView and the event and keyPressEvent event handlers. This works OK in a 'non-graphics' mode i.e. QTableView is not 'painted' in a QGraphicsView. In this case, pressing one of the keys results in moving the cursor to the next cell or row.
As soon as the tableview is part of an QGraphicsView, pressing Return results in moving the cursor to the end of the row. This is due to the fact that event is called twice for a single Return press. It is unclear to me why this is happening. Anyone any ideas? I enclose the code. Calling main() runs the code in 'non-graphics' mode, calling maing() runs it in 'graphics' mode.
Python v. 2.6.5
PyQt v. 4.6.2

Peter

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import PyQt4.QtCore
from PyQt4 import QtCore
from PyQt4 import QtGui


import sys

my_array = [[1, "m", 12.0, 3.0], [2, "f", 10.0, 11.0]]
			
def maing():
	app = QApplication(sys.argv)
	scene = QtGui.QGraphicsScene()
	scene.setSceneRect(0,0,300,200)
	view = QtGui.QGraphicsView()
	view.setScene(scene)
	view.show() 
	
	w = MyWindow()
	t = scene.addWidget(w)
	layout = QtGui.QGraphicsLinearLayout()
	layout.addItem(t) 
#	w.show()
	sys.exit(app.exec_())

def main():
	app = QApplication(sys.argv)
	w = MyWindow()
	w.show()
	sys.exit(app.exec_())
	

class MyWindow(QTableView):
	def __init__(self, *args):
		QTableView.__init__(self, *args)

		self.tablemodel = MyTableModel(my_array, self)
		self.setModel(self.tablemodel)
		self.setItemDelegate(MyDelegate(self))
		
		hh = self.horizontalHeader()
		hh.setStretchLastSection(True)

		self.resizeColumnsToContents()

	def event(self, event):
		if (event.type() == QtCore.QEvent.ShortcutOverride) and \
			((event.key() == QtCore.Qt.Key_Tab) or (event.key() == QtCore.Qt.Key_Return)):
			print "Type: ", event.type()
			print "In event", id(event)
			end = self.endOfTable()
			if end:
				self.insertRow()
			if (event.key() == QtCore.Qt.Key_Return):
				self.toNextCellOrRow()
			return True
		else:
			return super(MyWindow, self).event(event)
	
	def keyPressEvent(self,  event):
		if (event.type() == QtCore.QEvent.KeyPress) and (event.key() == QtCore.Qt.Key_Right):
			end = self.endOfTable()
			print "in keypress"
			if end:
				self.insertRow()
			self.toNextCellOrRow()
		else:
			return super(MyWindow, self).keyPressEvent(event)
		
	def insertRow(self):
		nr_rows = self.tablemodel.rowCount()
		self.tablemodel.beginInsertRows(QtCore.QModelIndex(),nr_rows, nr_rows)
		self.tablemodel.endInsertRows()
		my_array.append([9, "f", 99.0, 99.0])
		
	def toNextCellOrRow(self):
		section = self.currentIndex().column()
		current_row = self.currentIndex().row()
		#nr_rows = self.tablemodel.rowCount()
		cursor_index = self.moveCursor(QAbstractItemView.MoveRight,  Qt.NoModifier)
		if (section == cursor_index.column()):
			index = self.tablemodel.createIndex(cursor_index.row()+1, 0)
			self.setCurrentIndex(index)
		else:
			self.setCurrentIndex(cursor_index)


	def endOfTable(self):
		section = self.currentIndex().column()
		current_row = self.currentIndex().row()
		nr_rows = self.tablemodel.rowCount()
		cursor_index = self.moveCursor(QAbstractItemView.MoveRight,  Qt.NoModifier)
		cursor_section = cursor_index.column()
		if (current_row == nr_rows -1) and (section == cursor_section):
			return True
		return False

class MyTableModel(PyQt4.QtCore.QAbstractTableModel):	
	NR_COLS = 4
	FISHNR, GENDER, WEIGHT, LENGTH = range(NR_COLS)

	def __init__(self, datain, parent=None, *args):
		QAbstractTableModel.__init__(self, parent, *args)
		self.arraydata = datain
		self.editable = {}
		self.editable[MyTableModel.FISHNR] = True
		self.editable[MyTableModel.GENDER] = True
		self.editable[MyTableModel.WEIGHT] = False
		self.editable[MyTableModel.LENGTH] = True

	def rowCount(self, parent=None):
		return len(self.arraydata)
		#return 2
		
	def columnCount(self, parent=None):
		#return len(self.arraydata[0])
		return 4
		
	def data(self, index, role):
		if not index.isValid():
			return QVariant()
		elif role != Qt.DisplayRole:
			return QVariant()
		return QVariant(self.arraydata[index.row()][index.column()])

	def headerData(self, section, orientation, role=PyQt4.QtCore.Qt.DisplayRole):
		#self.log.debug("headerdata called, section:%d" % section)
		if role == PyQt4.QtCore.Qt.TextAlignmentRole:
			if orientation == PyQt4.QtCore.Qt.Horizontal:
				return PyQt4.QtCore.QVariant(int(PyQt4.QtCore.Qt.AlignLeft|PyQt4.QtCore.Qt.AlignVCenter))
			return PyQt4.QtCore.QVariant(int(PyQt4.QtCore.Qt.AlignRight|PyQt4.QtCore.Qt.AlignVCenter))
		if role != PyQt4.QtCore.Qt.DisplayRole:
			return PyQt4.QtCore.QVariant()
		if orientation == PyQt4.QtCore.Qt.Horizontal:
			if section == MyTableModel.FISHNR:
				return PyQt4.QtCore.QVariant("Fishnr")
			if section == MyTableModel.GENDER:
				return PyQt4.QtCore.QVariant("Gender")
			if section == MyTableModel.WEIGHT:
				return PyQt4.QtCore.QVariant("Weight")
			if section == MyTableModel.LENGTH:
				return PyQt4.QtCore.QVariant("Length")
		return PyQt4.QtCore.QVariant(int(section + 1))

	def flags(self, index):
		if not index.isValid():
			return QtCore.Qt.ItemIsEnabled
		section = index.column()
		if self.editable[section]:
			return QtCore.Qt.ItemFlags(QtCore.QAbstractTableModel.flags(self, index)|QtCore.Qt.ItemIsEditable|QtCore.Qt.ItemIsEnabled)
		else:
			return QtCore.Qt.NoItemFlags

	def get_editable(self):
		return self.editable


class MyDelegate(QtGui.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(MyDelegate, self).__init__(parent)
        self.parent = parent

    def createEditor(self, parent, option, index):
        if index.column() == MyTableModel.FISHNR:
            editor = QtGui.QLineEdit(parent)
            editor.setValidator(QtGui.QIntValidator(1, 9999, parent))
            #self.connect(editor, SIGNAL("returnPressed()"),
            #             self.commitAndCloseEditor)
            return editor
        elif index.column() == MyTableModel.WEIGHT:
            editor = QtGui.QLineEdit(parent)
            #self.connect(editor, SIGNAL("returnPressed()"),
             #            self.commitAndCloseEditor)
            return editor
        elif index.column() == MyTableModel.LENGTH:
            editor = QtGui.QLineEdit(parent)
            editor.setValidator(QtGui.QIntValidator(0.000001,99.999999, parent))
            #self.connect(editor, SIGNAL("returnPressed()"),
              #           self.commitAndCloseEditor)
            return editor
        elif index.column() == MyTableModel.GENDER:
            editor = QtGui.QLineEdit(parent)
            #self.connect(editor, SIGNAL("returnPressed()"),
              #          self.commitAndCloseEditor)
            return editor
        else:
            return QtGui.QStyledItemDelegate.createEditor(self,parent, option, index)

	def setEditorData(self, editor, index):
		if index.isValid():
			text = index.model().data(index, QtCore.Qt.DisplayRole).toString()
			editor.setText(text)

    def setModelData(self, editor, model, index):
		#pass
		model.setData(index, editor.text())


if __name__ == "__main__":
	main()


Peter HJ van der Kamp
Software developer
Wageningen IMARES, afd. Visserij
Postbus 68
1970 AB  IJmuiden
Tel. 0317-487176




More information about the PyQt mailing list