如何解决PyQt5:QTableView 拖放单元格而不是行
我知道如何drag rows
QTableView.verticalHeader().setSectionsMovable(True)
QTableView.verticalHeader().setDragEnabled(True)
QTableView.verticalHeader().setDragDropMode(qtw.QAbstractItemView.InternalMove)
但我希望能够拖放一个(或一对)单元格。
谁能指出我正确的方向?
PS:我目前的想法是拦截 clicked()
-> dragenter()
-> dragLeave()
或 fork 到 dragDrop()
-> dragIndicatorPosition()
事件,但听起来有点复杂
我确实阅读了 this,但我对如何实现它感到困惑,尤其是“启用项目拖放”部分似乎正是我所需要的。我会看看我是否可以发布一个“苗条”的例子。
编辑:
这里有一些其他东西的例子。在 MyStandardItemmodel
中,我尝试做到这一点:
from PyQt5 import QtCore,QtWidgets,Qtsql
from PyQt5.QtCore import QModelIndex
from PyQt5.QtGui import QStandardItemmodel
from PyQt5.QtWidgets import QApplication,QTableView,QTableWidget
class MyStandardItemmodel(QStandardItemmodel):
def __init__(self,parent=None,*arg,**kwargs):
super().__init__(parent,**kwargs)
self.__readonly_cols = []
def flags(self,index: QtCore.QModelIndex) -> QtCore.Qt.ItemFlags:
try:
default_Flags = QStandardItemmodel.flags(self,index)
if (index.column() in self.__readonly_cols):
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
else:
if (index.isValid()):
return default_Flags | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled
else:
return default_Flags
except Exception as ex:
print(ex)
def setReadOnly(self,columns: [int]):
for i in columns:
if i <= (self.columnCount() - 1) and i not in self.__readonly_cols:
self.__readonly_cols.append(i)
def resetReadOnly(self):
self.__readonly_cols = []
class MyTableView(QtWidgets.QTableView):
def __init__(self,*args,**kwargs)
class CheckBoxDelegate(QtWidgets.QItemDelegate):
"""
A delegate that places a fully functioning QCheckBox cell of the column to which it's applied.
"""
# signal to inform clicking
user_click = QtCore.pyqtSignal(int,int,bool)
def __init__(self,parent):
QtWidgets.QItemDelegate.__init__(self,parent)
def createEditor(self,parent,option,index):
"""
Important,otherwise an editor is created if the user clicks in this cell.
"""
return None
def paint(self,painter,index):
"""
Paint a checkBox without the label.
"""
self.drawCheck(painter,option.rect,QtCore.Qt.Unchecked if int(index.data()) == 0 else QtCore.Qt.Checked)
def editorEvent(self,event,model,index):
'''
Change the data in the model and the state of the checkBox
if the user presses the left mousebutton and this cell is editable. Otherwise do nothing.
'''
if not int(index.flags() & QtCore.Qt.ItemIsEditable) > 0:
return False
if event.type() == QtCore.QEvent.MouseButtonRelease and event.button() == QtCore.Qt.LeftButton:
# Change the checkBox-state
self.setModelData(None,index)
return True
# if event.type() == QtCore.QEvent.MouseButtonPress or event.type() == QtCore.QEvent.MouseMove:
# return False
return False
def setModelData (self,editor,index):
'''
The user wanted to change the old state in the opposite.
'''
try:
if int(index.data()) == 0:
model.setData(index,1,QtCore.Qt.EditRole)
ret = True
else:
model.setData(index,QtCore.Qt.EditRole)
ret = False
# emit signal with row,col,and the status
self.user_click.emit(index.row(),index.column(),ret)
except Exception as ex:
print(ex)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
model = MyStandardItemmodel(5,5)
header_labels = ['','Signal','Type','Routing','Input']
model.setHorizontalHeaderLabels(header_labels)
tableView = MyTableView()
tableView.setModel(model)
delegate = CheckBoxDelegate(None)
tableView.setItemDelegateForColumn(0,delegate)
for row in range(5):
for column in range(4):
index = model.index(row,column,QModelIndex())
model.setData(index,0)
model.setReadOnly([1,2])
tableView.setwindowTitle("CheckBox,readonly and drag&drop example")
tableView.show()
sys.exit(app.exec_())
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。