如何在树模型视图中保存新数据

时间:2011-03-14 21:09:42

标签: python treeview pyqt

我正在尝试修改名为“Editabletreemodel”的pyqt4的优秀示例,但我遇到了一个无法管理的问题:在模型中添加新行后,如何保存或更新数据?插入文本文件? 或者更一般地说,如何将模型/视图中的数据保存到文件中?

感谢您的帮助。

# This is only needed for Python v2 but is harmless for Python v3.
import sip
sip.setapi('QVariant', 2)

from PyQt4 import QtCore, QtGui

import editabletreemodel
from ui_mainwindow import Ui_MainWindow
import sys, os, time
import paramiko
import threading


class TreeItem(object):
    def __init__(self, data, parent=None):
        self.parentItem = parent
        self.itemData = data
        self.childItems = []

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

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

    def childNumber(self):
        if self.parentItem != None:
            return self.parentItem.childItems.index(self)
        return 0

    def columnCount(self):
        return len(self.itemData)

    def data(self, column):
        return self.itemData[column]

    def insertChildren(self, position, count, columns):
        if position < 0 or position > len(self.childItems):
            return False

        for row in range(count):
            data = [None for v in range(columns)]
            item = TreeItem(data, self)
            self.childItems.insert(position, item)

        return True

    def insertColumns(self, position, columns):
        if position < 0 or position > len(self.itemData):
            return False

        for column in range(columns):
            self.itemData.insert(position, None)

        for child in self.childItems:
            child.insertColumns(position, columns)

        return True

    def parent(self):
        return self.parentItem

    def removeChildren(self, position, count):
        if position < 0 or position + count > len(self.childItems):
            return False

        for row in range(count):
            self.childItems.pop(position)

        return True

    def removeColumns(self, position, columns):
        if position < 0 or position + columns > len(self.itemData):
            return False

        for column in range(columns):
            self.itemData.pop(position)

        for child in self.childItems:
            child.removeColumns(position, columns)

        return True

    def setData(self, column, value):
        if column < 0 or column >= len(self.itemData):
            return False

        self.itemData[column] = value

        return True


class TreeModel(QtCore.QAbstractItemModel):
    def __init__(self, headers, data, parent=None):
        super(TreeModel, self).__init__(parent)

        rootData = [header for header in headers]
        self.rootItem = TreeItem(rootData)
        self.setupModelData(data.split("\n"), self.rootItem)

    def columnCount(self, parent=QtCore.QModelIndex()):
        return self.rootItem.columnCount()

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

        if role != QtCore.Qt.DisplayRole and role != QtCore.Qt.EditRole:
            return None

        item = self.getItem(index)
        return item.data(index.column())

    def flags(self, index):
        if not index.isValid():
            return 0

        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

    def getItem(self, index):
        if index.isValid():
            item = index.internalPointer()
            if item:
                return item

        return self.rootItem

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self.rootItem.data(section)

        return None

    def index(self, row, column, parent=QtCore.QModelIndex()):
        if parent.isValid() and parent.column() != 0:
            return QtCore.QModelIndex()

        parentItem = self.getItem(parent)
        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QtCore.QModelIndex()

    def insertColumns(self, position, columns, parent=QtCore.QModelIndex()):
        self.beginInsertColumns(parent, position, position + columns - 1)
        success = self.rootItem.insertColumns(position, columns)
        self.endInsertColumns()

        return success

    def insertRows(self, position, rows, parent=QtCore.QModelIndex()):
        parentItem = self.getItem(parent)
        self.beginInsertRows(parent, position, position + rows - 1)
        success = parentItem.insertChildren(position, rows,
                self.rootItem.columnCount())
        self.endInsertRows()

        return success

    def parent(self, index):
        if not index.isValid():
            return QtCore.QModelIndex()

        childItem = self.getItem(index)
        parentItem = childItem.parent()

        if parentItem == self.rootItem:
            return QtCore.QModelIndex()

        return self.createIndex(parentItem.childNumber(), 0, parentItem)

    def removeColumns(self, position, columns, parent=QtCore.QModelIndex()):
        self.beginRemoveColumns(parent, position, position + columns - 1)
        success = self.rootItem.removeColumns(position, columns)
        self.endRemoveColumns()

        if self.rootItem.columnCount() == 0:
            self.removeRows(0, rowCount())

        return success

    def removeRows(self, position, rows, parent=QtCore.QModelIndex()):
        parentItem = self.getItem(parent)

        self.beginRemoveRows(parent, position, position + rows - 1)
        success = parentItem.removeChildren(position, rows)
        self.endRemoveRows()

        return success

    def rowCount(self, parent=QtCore.QModelIndex()):
        parentItem = self.getItem(parent)

        return parentItem.childCount()

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if role != QtCore.Qt.EditRole:
            return False

        item = self.getItem(index)
        result = item.setData(index.column(), value)

        if result:
            self.dataChanged.emit(index, index)

        return result

    def setHeaderData(self, section, orientation, value, role=QtCore.Qt.EditRole):
        if role != QtCore.Qt.EditRole or orientation != QtCore.Qt.Horizontal:
            return False

        result = self.rootItem.setData(section, value)
        if result:
            self.headerDataChanged.emit(orientation, section, section)

        return result

    def setupModelData(self, lines, parent):
        parents = [parent]
        indentations = [0]

        number = 0

        while number < len(lines):
            position = 0
            while position < len(lines[number]):
                if lines[number][position] != " ":
                    break
                position += 1

            lineData = lines[number][position:].trimmed()

            if lineData:
                # Read the column data from the rest of the line.
                columnData = [s for s in lineData.split('\t') if s]

                if position > indentations[-1]:
                    # The last child of the current parent is now the new
                    # parent unless the current parent has no children.

                    if parents[-1].childCount() > 0:
                        parents.append(parents[-1].child(parents[-1].childCount() - 1))
                        indentations.append(position)

                else:
                    while position < indentations[-1] and len(parents) > 0:
                        parents.pop()
                        indentations.pop()

                # Append a new item to the current parent's list of children.
                parent = parents[-1]
                parent.insertChildren(parent.childCount(), 1,
                        self.rootItem.columnCount())
                for column in range(len(columnData)):
                    parent.child(parent.childCount() -1).setData(column, columnData[column])

            number += 1


class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.setupUi(self)

        headers = ("Sendor Name", "Address", "Comments")

        file = QtCore.QFile('./default.txt')
        file.open(QtCore.QIODevice.ReadOnly)
        model = TreeModel(headers, file.readAll())
        file.close()

        print model.invisibleRootItem()


        self.view.setModel(model)
        for column in range(model.columnCount(QtCore.QModelIndex())):
            self.view.resizeColumnToContents(column)

        self.exitAction.triggered.connect(QtGui.qApp.quit)

        self.view.selectionModel().selectionChanged.connect(self.updateActions)

        self.actionsMenu.aboutToShow.connect(self.updateActions)
        self.insertRowAction.triggered.connect(self.insertRow)
        self.insertColumnAction.triggered.connect(self.insertColumn)
        self.removeRowAction.triggered.connect(self.removeRow)
        self.removeColumnAction.triggered.connect(self.removeColumn)
        self.insertChildAction.triggered.connect(self.insertChild)
        self.callSensorsButton.clicked.connect(self.call_sensors)

        self.updateActions()

        self.view.expandAll()
        self.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.view.customContextMenuRequested.connect(self.openMenu)

        self.connection = connection_thread()
        self.connect(self.connection, QtCore.SIGNAL("started()"), self.start_progressBar)
        self.connect(self.connection, QtCore.SIGNAL("finished()"), self.stop_progressBar)
        self.connect(self.connection, QtCore.SIGNAL("terminated()"), self.stop_progressBar)

        self.SaveListButton.clicked.connect(self.save_sensor_list)
        self.pushButton.clicked.connect(self.prova)


    def save_sensor_list(self):
        index = self.view.selectionModel().currentIndex()
        model = self.view.model()

        print model.rootItem

        for i in range(0, model.rootItem.rowCount()):
            print model.child(i)



    def prova(self):
        index = self.view.selectionModel().currentIndex()
        model = self.view.model()

        print model.data(index,0)

    def openMenu(self, position):
        indexes = self.view.selectedIndexes()
        model = self.view.model()
        if len(indexes) > 0:

            level = 0
            index = indexes[0]
            while index.parent().isValid():
                index = index.parent()
                level += 1

        menu = QtGui.QMenu()
        if level == 0:
            menu.addAction(self.tr("Call all %ss" % (model.data(index,0))))
            menu.addSeparator()
            menu.addAction(self.tr("Add new sensor family"),self.insertRow)
            menu.addAction(self.tr("Add new sensor"),self.insertChild)
        elif level == 1:
            menu.addAction(self.tr("Call this sensor"))
            menu.addSeparator()
            menu.addAction(self.tr("Add new sensor"),self.insertRow)
        elif level == 2:
            menu.addAction(self.tr("Edit object"))

        menu.exec_(self.view.viewport().mapToGlobal(position))

    def insertChild(self):
        index = self.view.selectionModel().currentIndex()
        model = self.view.model()

        if model.columnCount(index) == 0:
            if not model.insertColumn(0, index):
                return

        if not model.insertRow(0, index):
            return

        for column in range(model.columnCount(index)):
            child = model.index(0, column, index)
            model.setData(child, "[No data]", QtCore.Qt.EditRole)
            if not model.headerData(column, QtCore.Qt.Horizontal).isValid():
                model.setHeaderData(column, QtCore.Qt.Horizontal,
                        "[No header]", QtCore.Qt.EditRole)

        self.view.selectionModel().setCurrentIndex(model.index(0, 0, index),
                QtGui.QItemSelectionModel.ClearAndSelect)
        self.updateActions()

    def insertColumn(self, parent=QtCore.QModelIndex()):
        model = self.view.model()
        column = self.view.selectionModel().currentIndex().column()

        # Insert a column in the parent item.
        changed = model.insertColumn(column + 1, parent)
        if changed:
            model.setHeaderData(column + 1, QtCore.Qt.Horizontal,
                    "[No header]", QtCore.Qt.EditRole)

        self.updateActions()

        return changed

    def insertRow(self):
        index = self.view.selectionModel().currentIndex()
        model = self.view.model()

        if not model.insertRow(index.row()+1, index.parent()):
            return

        self.updateActions()

        for column in range(model.columnCount(index.parent())):
            child = model.index(index.row()+1, column, index.parent())
            model.setData(child, "[No data]", QtCore.Qt.EditRole)

    def removeColumn(self, parent=QtCore.QModelIndex()):
        model = self.view.model()
        column = self.view.selectionModel().currentIndex().column()

        # Insert columns in each child of the parent item.
        changed = model.removeColumn(column, parent)

        if not parent.isValid() and changed:
            self.updateActions()

        return changed

    def removeRow(self):
        index = self.view.selectionModel().currentIndex()
        model = self.view.model()

        if (model.removeRow(index.row(), index.parent())):
            self.updateActions()

    def updateActions(self):
        hasSelection = not self.view.selectionModel().selection().isEmpty()
        self.removeRowAction.setEnabled(hasSelection)
        self.removeColumnAction.setEnabled(hasSelection)

        hasCurrent = self.view.selectionModel().currentIndex().isValid()
        self.insertRowAction.setEnabled(hasCurrent)
        self.insertColumnAction.setEnabled(hasCurrent)

        if hasCurrent:
            self.view.closePersistentEditor(self.view.selectionModel().currentIndex())

            row = self.view.selectionModel().currentIndex().row()
            column = self.view.selectionModel().currentIndex().column()
            if self.view.selectionModel().currentIndex().parent().isValid():
                self.statusBar().showMessage("Position: (%d,%d)" % (row, column))
            else:
                self.statusBar().showMessage("Position: (%d,%d) in top level" % (row, column))

    def start_progressBar(self):
        self.progressBar.setRange(0,0)
        self.progressBar.setValue(0)

    def stop_progressBar(self):
        self.progressBar.setRange(0,1)
        self.progressBar.setValue(1)

    def call_sensors(self):
        self.textEdit.insertPlainText("Connecting to Fox...\n")
        self.connection.start_thread(self.textEdit)


class connection_thread(QtCore.QThread):
    def __init__(self, parent = None):
        QtCore.QThread.__init__(self, parent)

    def start_thread(self,textEdit):
        self.textEdit = textEdit
        self.start()

    def run(self):
        print "Dentro il thread"
        time.sleep(10)
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect('192.168.0.90', username='root', password='netusg20')
            self.textEdit.insertPlainText("Calling sensor list...\n")
            app.processEvents()
            stdin, stdout, stderr = ssh.exec_command('python g20.py c')
            self.textEdit.insertPlainText(stdout.read())
            self.textEdit.insertPlainText(stderr.read())
            self.textEdit.insertPlainText("Connection closed\n")
            ssh.close()
            app.processEvents()
        except:
            self.textEdit.insertPlainText(str(sys.exc_info()[1]))
            ssh.close()
            app.processEvents()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

1 个答案:

答案 0 :(得分:2)

我想简单的方法是迭代模型项并通过QDataStream保存到文件。 QDataStream支持读取\写入QVariant,您可以将模型项的数据设置为QVariant。下面是一个小例子,为简单起见,我使用QStandardItemModel

import sys
from PyQt4 import QtGui, QtCore

class MainForm(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)
        self.setMinimumSize(400, 400)

        # create model
        self.model = QtGui.QStandardItemModel()        
        for k in range(0, 4):
            parentItem = self.model.invisibleRootItem()
            for i in range(0, 4):
                item = QtGui.QStandardItem(QtCore.QString("item %0 %1").arg(k).arg(i))
                parentItem.appendRow(item)
                parentItem = item

        # create treeview
        self.view = QtGui.QTreeView(self)
        self.view.setModel(self.model)
        self.view.setMinimumSize(300, 400)

        self.saveButton = QtGui.QPushButton("save", self)
        self.saveButton.move(300, 1)
        self.saveButton.clicked.connect(self.on_save_button_clicked)

        self.layout = QtGui.QVBoxLayout(self.centralWidget())        
        self.layout.addWidget(self.view)
        self.layout.addWidget(self.saveButton)

    def on_save_button_clicked(self):
        # create text file
        file = QtCore.QFile("save.txt")
        file.open(QtCore.QIODevice.WriteOnly)
        # open data stream
        out = QtCore.QDataStream(file)
        # recursively write model item into the datastream 
        self.save_item(self.model.invisibleRootItem(), out)

    def save_item(self, item, out):
        for i in range(0, item.rowCount()):
            child = item.child(i)
            child.write(out)
            self.save_item(child, out)

def main():
    app = QtGui.QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    main() 

希望这有帮助,尊重