首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PySide填充空TableModel

PySide填充空TableModel
EN

Stack Overflow用户
提问于 2016-08-09 21:19:05
回答 1查看 549关注 0票数 0

我编写了一个并排有两个表视图的工具。我在它们之间拖放数据。一切都很好,但是不能让一个空的模型工作。所以在开始的时候,我想要有一个空的TableView,并通过拖放来添加项目。当至少有一个对象在,但不是空的对象时,这是有效的。如果是空的,甚至连头都没有。

我认为问题在于当模型为空时,TableView不会将其称为headerData……但是不知道这是不是对的。这是我的模型

如果我不设置空模型,但等到模型中有一个项目,然后再设置它,这将会起作用。但这并不是真的很好。

代码语言:javascript
复制
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]   
EN

回答 1

Stack Overflow用户

发布于 2016-11-04 23:02:25

我可能来不及想出答案了,但这个问题本身对我来说很有趣,所以我深入研究,找到了解决方案。

事实证明,以这样一种方式实现表模型的空状态有几个陷阱,即它仍然显示列标题,并且还允许将内容放在它自己上。

第一个问题是,如果columnCount方法为无效的QModelIndex返回0,Qt似乎不会绘制列标题。在这种情况下,它看起来甚至不会调用headerData方法。解决方案是永远不要用无效的QModelIndexcolumnCount返回0,即使行数实际上是0,并且我们的底层数据结构是一个二维数组,其中0行表示0列。

第二个陷阱是,您似乎需要一个自定义视图的子类化QTableView,因为您需要重写dragEnterEventdragMoveEvent来接受拖动输入和拖动移动unconditionally.否则,即使将视图的acceptDrops属性设置为True,drop事件也没有触发的机会。dragEnterEvent和/或dragMoveEvent的默认实现似乎与视图的底层模型对话,如果模型没有行,则视图拒绝接受丢弃。

第三个陷阱并不是什么陷阱,它只是在你的模型的dropMimeData方法中,如果没有插入行,你需要插入行,以便为被丢弃的项腾出空间。

以下是使用Python2.7测试的PySide 1.2.1 / Qt 4.8.5的完整解决方案:

代码语言:javascript
复制
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()
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38851944

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档