每当在表格视图中选择一行时,如何使第二列在编辑模式下有效(如以下此gif所示)?我正在尝试在python / pyside中重新创建它。
理想情况下,我想使用某种项目委托,以便我可以轻松地处理column单元格中的keyPressEvents并添加自定义(X)清除按钮。但是我不确定在使用ItemModels时如何使用这样的委托。因此,对帮助实现此任务的任何帮助表示赞赏。
class ExampleDelegate(QtGui.QStyledItemDelegate):
def createEditor(self, parent, option, index):
line_edit = QtGui.QLineEdit(parent)
return line_edit
这是我的代码和屏幕截图:
import os, sys
from PySide import QtGui, QtCore
class HotkeyItem():
def __init__(self, command, shortcut):
self.command = command
self.shortcut = shortcut
class HotkeysModel(QtCore.QAbstractTableModel):
def __init__(self):
super(HotkeysModel, self).__init__()
self.items = []
self.headers = ['Command','Hotkey']
def clear(self):
self.beginResetModel()
self.items = []
self.endResetModel()
def rowCount(self, parent=QtCore.QModelIndex()):
if parent.isValid():
return 0
return len(self.items)
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if orientation == QtCore.Qt.Horizontal:
if role == QtCore.Qt.DisplayRole:
cnt = len(self.headers)
if section < cnt:
return self.headers[section]
return None
def columnCount(self, parent=QtCore.QModelIndex()):
if parent.isValid():
return 0
return len(self.headers)
def index(self, row, column, parent=QtCore.QModelIndex()):
return self.createIndex(row, column, parent)
def addItem(self, item):
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self.items.append(item)
self.endInsertRows()
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return
row = index.row()
col = index.column()
if 0 <= row < self.rowCount():
item = self.items[row]
if role == QtCore.Qt.DisplayRole:
if col == 0:
return getattr(item, 'command', 'N/A')
elif col == 1:
return getattr(item, 'shortcut', '')
if role == QtCore.Qt.BackgroundRole:
shortcuts = filter(None, [x.shortcut for x in self.items])
dups = shortcuts.count(getattr(item, 'shortcut', ''))
if dups > 1:
return QtGui.QBrush(QtGui.QColor(255, 50, 50, 255))
elif role == QtCore.Qt.FontRole:
shortcuts = filter(None, [x.shortcut for x in self.items])
dups = shortcuts.count(getattr(item, 'shortcut', ''))
if dups > 1:
fnt = QtGui.QFont()
fnt.setBold(True)
fnt.setItalic(True)
return fnt
return None
def flags(self, index):
if not index.isValid():
return 0
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
class Example(QtGui.QWidget):
def __init__(self, parent=None):
super(Example, self).__init__(parent)
self.resize(600, 400)
model = HotkeysModel()
proxyModel = QtGui.QSortFilterProxyModel()
proxyModel.setFilterKeyColumn(0)
proxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
proxyModel.setSourceModel(model)
self.uiView = QtGui.QTableView()
self.uiView.setSortingEnabled(True)
self.uiView.setModel(proxyModel)
self.uiView.setAlternatingRowColors(True)
self.uiView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.uiView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
self.uiView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.uiView.verticalHeader().hide()
self.uiView.horizontalHeader().show()
lay = QtGui.QVBoxLayout()
lay.addWidget(self.uiView)
self.setLayout(lay)
self.populate()
# connections
selection = self.uiView.selectionModel()
selection.currentRowChanged.connect(self.selection_changed)
# ui->tableView->setCurrentIndex(index);
# ui->tableView->edit(index);
def selection_changed(self, index):
if index.isValid():
row = index.row()
self.uiView.setCurrentIndex(index)
self.uiView.edit(index)
def populate(self):
model = self.uiView.model().sourceModel()
model.clear()
items = [
HotkeyItem(command='Save', shortcut='Ctrl+S'),
HotkeyItem(command='Open', shortcut='Ctrl+O'),
HotkeyItem(command='Close', shortcut='Ctrl+Q'),
HotkeyItem(command='Align Top', shortcut=''),
HotkeyItem(command='Align Bottom', shortcut=''),
HotkeyItem(command='Align Left', shortcut=''),
HotkeyItem(command='Align Right', shortcut=''),
HotkeyItem(command='Align Center', shortcut='Ctrl+O')
]
for x in items:
model.addItem(x)
self.uiView.sortByColumn(0, QtCore.Qt.AscendingOrder)
self.uiView.resizeColumnsToContents()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
答案 0 :(得分:2)
部分问题在于,要使某个项目可编辑,必须激活标记QtCore.Qt.ItemIsEditable
。另一部分是,通过selection_changed的索引可以来自第一列中的项目,而不是来自第二列,因此使用该索引应该从第二列中获取索引。
在Qt5中,已经实现了清除按钮,并且仅使用setClearButtonEnabled(True)
激活了清除按钮,并使用qss更改了图标,但是对于Qt4,它不存在,因此必须使用{{ 3}}。
最后,您还必须实现setData()
方法。
import os
import sys
from PySide import QtGui, QtCore
class LineEdit(QtGui.QLineEdit):
def __init__(self, parent=None):
super(LineEdit, self).__init__(parent)
btnSize = self.sizeHint().height() - 5
self.clearButton = QtGui.QToolButton(self)
icon = QtGui.QIcon("clear.png")
self.clearButton.setIcon(icon)
self.clearButton.setCursor(QtCore.Qt.ArrowCursor)
self.clearButton.setStyleSheet("QToolButton { border: none; padding: 2px}")
self.clearButton.setFixedSize(btnSize, btnSize)
self.clearButton.hide()
frameWidth = self.style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
self.setStyleSheet("QLineEdit{{ padding-right: {}px }}".format(btnSize - frameWidth))
self.setMinimumHeight(self.sizeHint().height())
self.clearButton.clicked.connect(self.clear)
self.textChanged.connect(self.onTextChanged)
def resizeEvent(self, event):
frameWidth = self.style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
self.clearButton.move(self.width() - self.clearButton.width() - frameWidth, 0)
def onTextChanged(self, text):
self.clearButton.setVisible(text != "")
class Delegate(QtGui.QStyledItemDelegate):
def createEditor(self, parent, option, index):
editor = LineEdit(parent)
font = index.data(QtCore.Qt.FontRole)
editor.setFont(font)
return editor
def setEditorData(self, editor, index):
text = index.data()
editor.setText(text)
def setModelData(self, editor, model, index):
model.setData(index, editor.text())
class HotkeyItem():
def __init__(self, command, shortcut):
self.command = command
self.shortcut = shortcut
class HotkeysModel(QtCore.QAbstractTableModel):
def __init__(self):
super(HotkeysModel, self).__init__()
self.items = []
self.headers = ['Command','Hotkey']
def clear(self):
self.beginResetModel()
self.items = []
self.endResetModel()
def rowCount(self, parent=QtCore.QModelIndex()):
if parent.isValid():
return 0
return len(self.items)
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if orientation == QtCore.Qt.Horizontal:
if role == QtCore.Qt.DisplayRole:
cnt = len(self.headers)
if section < cnt:
return self.headers[section]
return None
def columnCount(self, parent=QtCore.QModelIndex()):
if parent.isValid():
return 0
return len(self.headers)
def addItem(self, item):
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self.items.append(item)
self.endInsertRows()
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return
row = index.row()
col = index.column()
if 0 <= row < self.rowCount():
item = self.items[row]
if role == QtCore.Qt.DisplayRole:
if col == 0:
return getattr(item, 'command', 'N/A')
elif col == 1:
return getattr(item, 'shortcut', '')
if role == QtCore.Qt.BackgroundRole:
shortcuts = filter(None, [x.shortcut for x in self.items])
dups = shortcuts.count(getattr(item, 'shortcut', ''))
if dups > 1:
return QtGui.QBrush(QtGui.QColor(255, 50, 50, 255))
elif role == QtCore.Qt.FontRole:
shortcuts = filter(None, [x.shortcut for x in self.items])
dups = shortcuts.count(getattr(item, 'shortcut', ''))
if dups > 1:
fnt = QtGui.QFont()
fnt.setBold(True)
fnt.setItalic(True)
return fnt
def setData(self, index, value, role=QtCore.Qt.EditRole):
if index.isValid():
row = index.row()
col = index.column()
if 0 <= row < self.rowCount() and 0 <= col < self.columnCount():
it = self.items[row]
if col == 0:
it.command = value
elif col == 1:
it.shortcut = value
return True
return False
def flags(self, index):
fl = QtCore.Qt.NoItemFlags
if index.isValid():
fl |= QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
if index.column() == 1:
fl |= QtCore.Qt.ItemIsEditable
return fl
class Example(QtGui.QWidget):
def __init__(self, parent=None):
super(Example, self).__init__(parent)
self.resize(600, 400)
model = HotkeysModel()
proxyModel = QtGui.QSortFilterProxyModel()
proxyModel.setFilterKeyColumn(0)
proxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
proxyModel.setSourceModel(model)
self.uiView = QtGui.QTableView()
self.uiView.setSortingEnabled(True)
self.uiView.setModel(proxyModel)
self.uiView.setAlternatingRowColors(True)
delegate = Delegate(self)
self.uiView.setItemDelegateForColumn(1, delegate)
self.uiView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.uiView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
self.uiView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.uiView.verticalHeader().hide()
self.uiView.horizontalHeader().show()
lay = QtGui.QVBoxLayout()
lay.addWidget(self.uiView)
self.setLayout(lay)
self.populate()
# connections
selection = self.uiView.selectionModel()
selection.currentChanged.connect(self.openEditor)
self.uiView.clicked.connect(self.openEditor)
def openEditor(self, index):
if index.isValid():
ix = index.sibling(index.row(), 1)
self.uiView.setCurrentIndex(ix)
self.uiView.edit(ix)
def populate(self):
model = self.uiView.model().sourceModel()
model.clear()
items = [
HotkeyItem(command='Save', shortcut='Ctrl+S'),
HotkeyItem(command='Open', shortcut='Ctrl+O'),
HotkeyItem(command='Close', shortcut='Ctrl+Q'),
HotkeyItem(command='Align Top', shortcut=''),
HotkeyItem(command='Align Bottom', shortcut=''),
HotkeyItem(command='Align Left', shortcut=''),
HotkeyItem(command='Align Right', shortcut=''),
HotkeyItem(command='Align Center', shortcut='Ctrl+O')
]
for x in items:
model.addItem(x)
self.uiView.sortByColumn(0, QtCore.Qt.AscendingOrder)
self.uiView.resizeColumnsToContents()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()