PyQT QTreeView不基于自定义QAbstractItemModel进行更新

时间:2015-12-03 20:27:39

标签: pyqt

我看了很多在线教程/视频试图让QTreeView工作。我了解基本原理并使示例工作。但是,现在我想对正常的数据更改机制进行更改。

通常,示例显示通过GUI更改数据。相反,我需要通过一个单独的运行线程来更改数据(即TreeView将是只读的)。在应用程序中,线程处理定期检索数据,我想相应地更新TreeView。

以下是我到目前为止尝试过的一些示例代码。 TreeView应显示第一列中的树结构,并显示第二列中每个树项的值。数据线程更新树节点值。我想看到的是价值自身增加。相反,当我鼠标打开/关闭项目时,我只看到更新的值。这告诉我线程成功更新了值,但看起来TreeView没有响应dataChanged信号。

我似乎很接近,但我看不出什么是不对的......想法?

import sys
import threading
import time
from PyQt4 import QtGui, QtCore


class Node(object):
    def __init__(self, name, parent=None):
        self._name = name
        self._value = 0
        self._children = []
        self._parent = parent

        if parent is not None:
            parent.addChild(self)

    def addChild(self, child):
        self._children.append(child)

    def name(self):
        return self._name

    def value(self):
        return self._value

    def setValue(self, value):
        self._value = value

    def child(self, row):
        return self._children[row]

    def childCount(self):
        return len(self._children)

    def children(self):
        return self._children

    def parent(self):
        return self._parent

    def row(self):
        if self._parent is not None:
            return self._parent._children.index(self)


class Model(QtCore.QAbstractItemModel):
    def __init__(self, parent=None):
        super(Model, self).__init__(parent)
        self._root = None
        self.setupData()

    def setupData(self):
        rootNode = Node('Root')
        childNode0 = Node('A', rootNode)
        childNode1 = Node('B', rootNode)

        childNode2 = Node('1', childNode0)
        childNode3 = Node('2', childNode0)
        childNode4 = Node('1', childNode1)
        childNode5 = Node('2', childNode1)

        childNode6 = Node('a', childNode3)
        childNode7 = Node('b', childNode3)
        childNode8 = Node('c', childNode3)

        childNode9 = Node('d', childNode4)
        childNode10 = Node('e', childNode4)
        childNode11 = Node('f', childNode4)

        self._root = rootNode

    def rowCount(self, parent=None):
        if not parent.isValid():
            parentNode = self._root
        else:
            parentNode = parent.internalPointer()

        return parentNode.childCount()

    def columnCount(self, parent=None):
        return 2

    def data(self, index, role):
        if not index.isValid():
            return None

        node = index.internalPointer()

        if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
            if index.column() == 0:
                return node.name()

            if index.column() == 1:
                return node.value()

        return None

    def headerData(self, section, orientation, role):
        if role == QtCore.Qt.DisplayRole:
            if section == 0:
                return 'Item'

            if section == 1:
                return 'Value'

        return None

    def index(self, row, column, parent):
        parentNode = self.getNode(parent)

        childItem = parentNode.child(row)

        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QtCore.QModelIndex()

    def getNode(self, index):
        if index.isValid():
            node = index.internalPointer()
            if node:
                return node

        return self._root

    def parent(self, index):
        node = self.getNode(index)
        parentNode = node.parent()

        if parentNode == self._root:
            return QtCore.QModelIndex()

        return self.createIndex(parentNode.row(), 0, parentNode)

    def changeData(self, name, value):
        # find the 'name' node and have setData make the change
        index = self.searchModel(name)
        self.setData(index, value)

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if index.isValid():
            if role == QtCore.Qt.EditRole:
                node = index.internalPointer()
                node.setValue(value)

                # signal the views that data has changed
                self.dataChanged.emit(index, index)
                return True
        return False

    def searchModel(self, name):
        def searchNode(node):
            for child in node.children():
                if child.name().endswith(name):
                    index = self.createIndex(child.row(), 0, child)
                    return index

                if child.childCount() > 0:
                    result = searchNode(child)
                    if result:
                        return result

        return searchNode(self._root)


class DataThread(threading.Thread):
    def __init__(self, model):
        threading.Thread.__init__(self)
        self.__model = model
        self.__runflag = False

    def run(self):
        print 'Running'

        value = 0
        self.__runflag = True
        while self.__runflag:
            # sample, change a single value
            self.__model.changeData('c', value)
            value += 1

            time.sleep(1)
        print 'Terminated'

    def stop(self):
        print 'Stopping'
        self.__runflag = False


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)

    model = Model()

    view = QtGui.QTreeView()
    view.setModel(model)
    view.expandAll()
    view.show()

    data_thread = DataThread(model)
    data_thread.start()

    app.exec_()

    data_thread.stop()

    sys.exit()

1 个答案:

答案 0 :(得分:1)

传递给dataChanged信号的模型索引的列值为0.但是,您要更新的列是1.

searchNode中,更改构造索引的行:

index = self.createIndex(child.row(), 1, child)

它应该工作。