我编写了一个并排有两个表视图的工具。我在它们之间拖放数据。一切都很好,但是不能让一个空的模型工作。所以在开始的时候,我想要有一个空的TableView,并通过拖放来添加项目。当至少有一个对象在,但不是空的对象时,这是有效的。如果是空的,甚至连头都没有。
我认为问题在于当模型为空时,TableView不会将其称为headerData……但是不知道这是不是对的。这是我的模型
如果我不设置空模型,但等到模型中有一个项目,然后再设置它,这将会起作用。但这并不是真的很好。
class myTableModel(TableModel):
def __init__(self, headers = [], items = [[]], parent = None):
super(myTableModel,self).__init__(headers,items,parent)
self.__items = items
self.__headers = headers
def flags(self, index):
if not index.isValid():
return QtCore.Qt.ItemIsEnabled
if index.column() == 0:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled | QtCore.Qt.ItemIsEditable
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled
def supportedDropActions(self):
return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction
def removeRow(self, row, index=QtCore.QModelIndex()):
self.beginRemoveRows(QtCore.QModelIndex(), row, row)
self.__items.pop(row)
self.endRemoveRows()
return True
def insertRow(self, data,row=0,index=QtCore.QModelIndex()):
self.beginInsertRows(QtCore.QModelIndex(), 0,0)
self.__items.insert(0, data)
self.endInsertRows()
return True
def data(self,index,role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
row = index.row()
column = index.column()
if len(self.__items[row])-1 < column:
return ""
else:
return self.__items[row][column]
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
self.__items[row][column] = value
self.dataChanged.emit(index, index)
return True
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if len(self.__headers)-1 < section:
return ""
else:
#print "%s in section %i" %(self.__headers[section],section)
return self.__headers[section] 发布于 2016-11-04 23:02:25
我可能来不及想出答案了,但这个问题本身对我来说很有趣,所以我深入研究,找到了解决方案。
事实证明,以这样一种方式实现表模型的空状态有几个陷阱,即它仍然显示列标题,并且还允许将内容放在它自己上。
第一个问题是,如果columnCount方法为无效的QModelIndex返回0,Qt似乎不会绘制列标题。在这种情况下,它看起来甚至不会调用headerData方法。解决方案是永远不要用无效的QModelIndex从columnCount返回0,即使行数实际上是0,并且我们的底层数据结构是一个二维数组,其中0行表示0列。
第二个陷阱是,您似乎需要一个自定义视图的子类化QTableView,因为您需要重写dragEnterEvent和dragMoveEvent来接受拖动输入和拖动移动unconditionally.否则,即使将视图的acceptDrops属性设置为True,drop事件也没有触发的机会。dragEnterEvent和/或dragMoveEvent的默认实现似乎与视图的底层模型对话,如果模型没有行,则视图拒绝接受丢弃。
第三个陷阱并不是什么陷阱,它只是在你的模型的dropMimeData方法中,如果没有插入行,你需要插入行,以便为被丢弃的项腾出空间。
以下是使用Python2.7测试的PySide 1.2.1 / Qt 4.8.5的完整解决方案:
import sys
from PySide import QtCore, QtGui
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, headers = [], items = [[]], parent = None):
super(TableModel,self).__init__(parent)
self.__items = items
self.__headers = headers
row_counter = 0
for row_item in self.__items:
column_counter = 0
for column_item in row_item:
idx = self.createIndex(row_counter, column_counter)
self.setData(idx, column_item, QtCore.Qt.EditRole)
self.dataChanged.emit(idx, idx)
column_counter += 1
row_counter += 1
num_headers = len(self.__headers)
for section in range(0, num_headers):
self.setHeaderData(section, QtCore.Qt.Horizontal, self.__headers[section])
self.headerDataChanged.emit(QtCore.Qt.Horizontal, 0, num_headers)
def index(self, row, column, parent):
if row < 0 or row >= len(self.__items):
return QtCore.QModelIndex()
return self.createIndex(row, column, self.__items[row])
def parent(self, index):
return QtCore.QModelIndex()
def rowCount(self, index):
if index.isValid():
return
num_rows = len(self.__items)
# checking for empty nested columns list within a single "row"
if num_rows == 1:
if len(self.__items[0]) == 0:
return 0
return num_rows
def columnCount(self, index):
if index.isValid():
return 0
# compute the max column count within all rows
max_column_count = 0
for row in self.__items:
column_count = len(row)
if column_count > max_column_count:
max_column_count = column_count
# if there are no real columns, make the column count return the number of headers instead
if max_column_count < len(self.__headers):
max_column_count = len(self.__headers)
return max_column_count
def flags(self, index):
if not index.isValid():
return QtCore.Qt.ItemIsEnabled
if index.column() == 0:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled | \
QtCore.Qt.ItemIsDropEnabled | QtCore.Qt.ItemIsEditable
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | \
QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled
def supportedDropActions(self):
return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction
def insertRows(self, row, count, index):
if index.isValid():
return False
if count <= 0:
return False
num_columns = self.columnCount(index)
# inserting 'count' empty rows starting at 'row'
self.beginInsertRows(QtCore.QModelIndex(), row, row + count - 1)
for i in range(0, count):
# inserting as many columns as the table currently has
self.__items.insert(row + i, ["" for i in range(0, num_columns)])
self.endInsertRows()
return True
def removeRows(self, row, count, index):
if index.isValid():
return False
if count <= 0:
return False
num_rows = self.rowCount(QtCore.QModelIndex())
self.beginRemoveRows(QtCore.QModelIndex(), row, row + count - 1)
for i in range(count, 0, -1):
self.__items.pop(row - i + 1)
self.endRemoveRows()
return True
def data(self,index,role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
row = index.row()
column = index.column()
if row < 0 or row >= len(self.__items):
return ""
if column < 0 or column >= len(self.__items[row]):
return ""
else:
return self.__items[row][column]
return None
def setData(self, index, value, role=QtCore.Qt.EditRole):
if not index.isValid:
return False
if role == QtCore.Qt.EditRole:
row = index.row()
column = index.column()
if row < 0 or row >= self.rowCount(QtCore.QModelIndex()):
return False
if column < 0 or column >= len(self.__items[row]):
return False
self.__items[row].pop(column)
self.__items[row].insert(column, value)
self.dataChanged.emit(index, index)
return True
return False
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if section < 0 or section >= len(self.__headers):
return ""
else:
return self.__headers[section]
return None
def mimeTypes(self):
return ['application/vnd.tableviewdragdrop.list']
def mimeData(self, indexes):
mimedata = QtCore.QMimeData()
encoded_data = QtCore.QByteArray()
stream = QtCore.QDataStream(encoded_data, QtCore.QIODevice.WriteOnly)
for index in indexes:
if index.isValid():
text = self.data(index, QtCore.Qt.DisplayRole)
stream << QtCore.QByteArray(text)
mimedata.setData('application/vnd.tableviewdragdrop.list', encoded_data)
return mimedata
def dropMimeData(self, data, action, row, column, parent):
if action == QtCore.Qt.IgnoreAction:
return True
if not data.hasFormat('application/vnd.tableviewdragdrop.list'):
return False
if column > 0:
return False
num_rows = self.rowCount(QtCore.QModelIndex())
begin_row = 0
if row != -1:
begin_row = row
elif parent.isValid():
begin_row = parent.row()
else:
begin_row = num_rows
if begin_row == num_rows:
self.insertRows(begin_row, 1, QtCore.QModelIndex())
if column < 0:
if parent.isValid():
column = parent.column()
else:
column = 0
encoded_data = data.data('application/vnd.tableviewdragdrop.list')
stream = QtCore.QDataStream(encoded_data, QtCore.QIODevice.ReadOnly)
new_items = []
rows = 0
while not stream.atEnd():
text = QtCore.QByteArray()
stream >> text
new_items.append(str(text))
rows += 1
for text in new_items:
idx = self.index(begin_row, column, QtCore.QModelIndex())
self.setData(idx, text, QtCore.Qt.EditRole)
begin_row += 1
return True
class TableView(QtGui.QTableView):
def __init__(self, parent=None):
super(TableView, self).__init__(parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
event.accept()
def dragMoveEvent(self, event):
event.accept()
class MainForm(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainForm, self).__init__(parent)
self.left_model = TableModel(headers=["column0", "column1", "column2"])
#self.left_model = TableModel(items=[["left0", "left1", "left2"],["left3","left4","left5"]],
# headers=["column0", "column1", "column2"])
self.right_model = TableModel(items=[['right0', 'right1', 'right2'], ['right3', 'right4', 'right5']],
headers=['column0', 'column1', 'column2'])
self.left_view = TableView()
self.left_view.setModel(self.left_model)
self.left_view.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
self.right_view = TableView()
self.right_view.setModel(self.right_model)
self.right_view.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
self.layout = QtGui.QHBoxLayout()
self.layout.addWidget(self.left_view)
self.layout.addWidget(self.right_view)
self.window = QtGui.QWidget()
self.window.setLayout(self.layout)
self.setCentralWidget(self.window)
def main():
app = QtGui.QApplication(sys.argv)
form = MainForm()
form.show()
app.exec_()
if __name__ == '__main__':
main()https://stackoverflow.com/questions/38851944
复制相似问题