我有一个QAbstractTableModel+QTableView,并分配了一个委托来创建一个QLabel小部件用作编辑器。
什么都不要做
我原以为这会很容易,但我一直想不出怎么做。
closeEditor
信号。代码如下所示。它有点长(以便成为独立的可执行文件),但显示的大部分内容只是标准的模型/视图/委托内容。有趣的部分在下面。我已经定义了一个槽(
on_closeEditor()
),并将其连接到
信号(参见
### ... ###
评论)。
当按下Enter键时,代理将捕捉并发出
关闭编辑器
打开关闭编辑器()
插槽被调用。所以这种联系似乎是正确的。
做
(还有一件事,即使我的代码
能够
当代理编辑器关闭时获得控制,我不清楚如何阻止它发生。但一次只做一件事……)
有没有直接的方法?我觉得我一定错过了什么。。。
谢谢!
样本代码
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
# ------------------------------------------------------------------------------
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data = [[]], headers = None, parent = None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.__data = data
def rowCount(self, parent):
return len(self.__data)
def columnCount(self, parent):
return len(self.__data[0])
def data(self, index, role):
row = index.row()
column = index.column()
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
value = self.__data[row][column]
return value
if role == QtCore.Qt.BackgroundRole:
return QtGui.QBrush(QtGui.QColor(230, 240, 250))
def setData(self, index, value, role = QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
if value is None:
value = ''
self.__data[row][column] = value
return True
return False
def flags(self, index):
return QtCore.Qt.ItemIsEnabled|QtCore.Qt.ItemIsEditable
# ------------------------------------------------------------------------------
class TableView(QtWidgets.QTableView):
def __init__(self, parent=None):
super().__init__(parent)
self.blocked = False
def keyPressEvent(self, event):
key = event.key()
mod = int(event.modifiers())
row = self.currentIndex().row()
if key == QtCore.Qt.Key_Q and mod == QtCore.Qt.CTRL:
self.close()
exit()
super().keyPressEvent(event)
# ------------------------------------------------------------------------------
class Delegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, option, index):
self.editor = QtWidgets.QLabel(parent)
return self.editor
def setEditorData(self, label, index):
print('setEditorData()')
model = index.model()
v = model.data(index, QtCore.Qt.EditRole)
model.setData(index, None, QtCore.Qt.EditRole)
def setModelData(self, label, model, index):
print('setModelData()')
value = label.text()
row = index.row()
col = index.column()
model.setData(index, value, QtCore.Qt.EditRole)
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
def eventFilter(self, target, event):
if event.type() == QtCore.QEvent.KeyPress:
key = event.key()
mod = int(event.modifiers())
if (
key >= QtCore.Qt.Key_Space and key <= QtCore.Qt.Key_AsciiTilde and
(mod == QtCore.Qt.NoModifier or mod == QtCore.Qt.SHIFT)
):
text = self.editor.text()
self.editor.setText(text + event.text())
return True
# Enter (or ctrl-Enter) explicitly emits commitData, closeEditor
elif (
key == QtCore.Qt.Key_Return and
(mod == QtCore.Qt.NoModifier or mod == QtCore.Qt.CTRL)
):
self.commitData.emit(target)
self.closeEditor.emit(target)
return True
return False
### closeEditor slot ###
def on_closeEditor(self, editor, hint):
print('closeEditor()')
# ------------------------------------------------------------------------------
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setStyle('fusion')
tableView = TableView()
tableView.resize(550, 160)
delegate = Delegate()
tableView.setItemDelegate(delegate)
### connect closeEditor signal to slot ###
delegate.closeEditor.connect(delegate.on_closeEditor)
tableView.show()
rowCount = 3
columnCount = 4
data = [
['foo', 'goo', 'zoo', 'moo'],
['bar', 'zar', 'jar', 'gar'],
['qux', 'lux', 'mux', 'sux']
]
model = TableModel(data)
tableView.setModel(model)
sys.exit(app.exec_())
[编辑]
我的下一个想法是可以为委托安装一个事件过滤器,并过滤掉FocusAboutToChange和/或FocusOut事件。事实上,我真的认为这将是一个完美的解决方案。
但没用。:-(
print()
eventFilter()
返回
True
,事件将停止。但事实似乎并非如此。光标无论如何都会离开编辑过的单元格。
代码
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
# ------------------------------------------------------------------------------
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data = [[]], headers = None, parent = None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.__data = data
def rowCount(self, parent):
return len(self.__data)
def columnCount(self, parent):
return len(self.__data[0])
def data(self, index, role):
row = index.row()
column = index.column()
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
value = self.__data[row][column]
return value
if role == QtCore.Qt.BackgroundRole:
return QtGui.QBrush(QtGui.QColor(230, 240, 250))
def setData(self, index, value, role = QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
if value is None:
value = ''
self.__data[row][column] = value
return True
return False
def flags(self, index):
return QtCore.Qt.ItemIsEnabled|QtCore.Qt.ItemIsEditable
# ------------------------------------------------------------------------------
class TableView(QtWidgets.QTableView):
def __init__(self, parent=None):
super().__init__(parent)
self.blocked = False
def keyPressEvent(self, event):
key = event.key()
mod = int(event.modifiers())
if key == QtCore.Qt.Key_Q and mod == QtCore.Qt.CTRL:
self.close()
exit()
super().keyPressEvent(event)
# ------------------------------------------------------------------------------
class Delegate(QtWidgets.QStyledItemDelegate):
def createEditor(self, parent, option, index):
self.editor = QtWidgets.QLabel(parent)
return self.editor
def setEditorData(self, label, index):
model = index.model()
v = model.data(index, QtCore.Qt.EditRole)
model.setData(index, None, QtCore.Qt.EditRole)
def setModelData(self, label, model, index):
value = label.text()
row = index.row()
col = index.column()
model.setData(index, value, QtCore.Qt.EditRole)
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
def eventFilter(self, target, event):
if event.type() == QtCore.QEvent.KeyPress:
key = event.key()
mod = int(event.modifiers())
# ASCII input
if (
key >= QtCore.Qt.Key_Space and key <= QtCore.Qt.Key_AsciiTilde and
(mod == QtCore.Qt.NoModifier or mod == QtCore.Qt.SHIFT)
):
text = self.editor.text()
self.editor.setText(text + event.text())
return True
### Ostensibly filter out FocusAboutToChange and FocusOut events ###
if event.type() == QtCore.QEvent.FocusAboutToChange:
print('FocusAboutToChange')
return True
if event.type() == QtCore.QEvent.FocusOut:
print('FocusOut')
return True
return False
# ------------------------------------------------------------------------------
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setStyle('fusion')
rowCount = 3
columnCount = 4
data = [
['foo', 'goo', 'zoo', 'moo'],
['bar', 'zar', 'jar', 'gar'],
['qux', 'lux', 'mux', 'sux']
]
tableView = TableView()
tableView.resize(550, 160)
delegate = Delegate()
tableView.setItemDelegate(delegate)
delegate.installEventFilter(delegate)
tableView.show()
model = TableModel(data)
tableView.setModel(model)
sys.exit(app.exec_())