python3+PyQt5 树中表达表格数据

来源:互联网 发布:华语网络十大男歌手 编辑:程序博客网 时间:2024/05/17 22:23

关联数据项选择的一个解决方案就是使用树视图。本文通过Python3+pyqt5实现了python Qt GUI 快速编程的16章的树视图例子。

/home/yrd/eric_workspace/chap16/treeoftable.py

#!/usr/bin/env python3import bisectimport codecsfrom PyQt5.QtCore import (QAbstractItemModel, QModelIndex,QVariant, Qt)KEY, NODE = range(2)class BranchNode(object):    def __init__(self, name, parent=None):        super(BranchNode, self).__init__()        self.name = name        self.parent = parent        self.children = []    def __lt__(self, other):        if isinstance(other, BranchNode):            return self.orderKey() < other.orderKey()        return False    def orderKey(self):        return self.name.lower()    def toString(self):        return self.name    def __len__(self):        return len(self.children)    def childAtRow(self, row):        assert 0 <= row < len(self.children)        return self.children[row][NODE]    def rowOfChild(self, child):        for i, item in enumerate(self.children):            if item[NODE] == child:                return i        return -1    def childWithKey(self, key):        if not self.children:            return None        # Causes a -3 deprecation warning. Solution will be to        # reimplement bisect_left and provide a key function.        i = bisect.bisect_left(self.children, (key, None))        if i < 0 or i >= len(self.children):            return None        if self.children[i][KEY] == key:            return self.children[i][NODE]        return None    def insertChild(self, child):        child.parent = self        bisect.insort(self.children, (child.orderKey(), child))    def hasLeaves(self):        if not self.children:            return False        return isinstance(self.children[0], LeafNode)class LeafNode(object):    def __init__(self, fields, parent=None):        super(LeafNode, self).__init__()        self.parent = parent        self.fields = fields    def orderKey(self):        return "\t".join(self.fields).lower()    def toString(self, separator="\t"):        return separator.join(self.fields)    def __len__(self):        return len(self.fields)    def asRecord(self):        record = []        branch = self.parent        while branch is not None:            record.insert(0, branch.toString())            branch = branch.parent        assert record and not record[0]        record = record[1:]        return record + self.fields    def field(self, column):        assert 0 <= column <= len(self.fields)        return self.fields[column]class TreeOfTableModel(QAbstractItemModel):    def __init__(self, parent=None):        super(TreeOfTableModel, self).__init__(parent)        self.columns = 0        self.root = BranchNode("")        self.headers = []    def load(self, filename, nesting, separator):        self.beginResetModel()        assert nesting > 0        self.nesting = nesting        self.root = BranchNode("")        exception = None        fh = None        try:            for line in codecs.open(str(filename), "rU", "utf8"):                if not line:                    continue                self.addRecord(line.split(separator), False)        except IOError as e:            exception = e        finally:            if fh is not None:                fh.close()            #self.reset()            self.endResetModel()            for i in range(self.columns):                self.headers.append("Column #{0}".format(i))            if exception is not None:                raise exception    def addRecord(self, fields, callReset=True):        assert len(fields) > self.nesting        root = self.root        branch = None        for i in range(self.nesting):            key = fields[i].lower()            branch = root.childWithKey(key)            if branch is not None:                root = branch            else:                branch = BranchNode(fields[i])                root.insertChild(branch)                root = branch        assert branch is not None        items = fields[self.nesting:]        self.columns = max(self.columns, len(items))        branch.insertChild(LeafNode(items, branch))        if callReset:            self.beginResetModel()            self.endResetModel()    def asRecord(self, index):        leaf = self.nodeFromIndex(index)        if leaf is not None and isinstance(leaf, LeafNode):            return leaf.asRecord()        return []    def rowCount(self, parent):        node = self.nodeFromIndex(parent)        if node is None or isinstance(node, LeafNode):            return 0        return len(node)    def columnCount(self, parent):        return self.columns    def data(self, index, role):        if role == Qt.TextAlignmentRole:            return QVariant(int(Qt.AlignTop|Qt.AlignLeft))        if role != Qt.DisplayRole:            return QVariant()        node = self.nodeFromIndex(index)        assert node is not None        if isinstance(node, BranchNode):            return node.toString() if index.column() == 0 else ""        return node.field(index.column())    def headerData(self, section, orientation, role):        if (orientation == Qt.Horizontal and            role == Qt.DisplayRole):            assert 0 <= section <= len(self.headers)            return self.headers[section]        return QVariant()    def index(self, row, column, parent):        assert self.root        branch = self.nodeFromIndex(parent)        assert branch is not None        return self.createIndex(row, column,                                branch.childAtRow(row))    def parent(self, child):        node = self.nodeFromIndex(child)        if node is None:            return QModelIndex()        parent = node.parent        if parent is None:            return QModelIndex()        grandparent = parent.parent        if grandparent is None:            return QModelIndex()        row = grandparent.rowOfChild(parent)        assert row != -1        return self.createIndex(row, 0, parent)    def nodeFromIndex(self, index):        return (index.internalPointer()                if index.isValid() else self.root)

/home/yrd/eric_workspace/chap16/serverinfo.pyw

#!/usr/bin/env python3import osimport sysfrom PyQt5.QtCore import (QModelIndex, QVariant, Qt,pyqtSignal)from PyQt5.QtWidgets import (QApplication, QMainWindow,QMessageBox,  QShortcut, QTreeView)from PyQt5.QtGui import QKeySequence,QPixmapimport treeoftableclass ServerModel(treeoftable.TreeOfTableModel):    def __init__(self, parent=None):        super(ServerModel, self).__init__(parent)    def data(self, index, role):        if role == Qt.DecorationRole:            node = self.nodeFromIndex(index)            if node is None:                return QVariant()            if isinstance(node, treeoftable.BranchNode):                if index.column() != 0:                    return QVariant()                filename = node.toString().replace(" ", "_")                parent = node.parent.toString()                if parent and parent != "USA":                    return QVariant()                if parent == "USA":                    filename = "USA_" + filename                filename = os.path.join(os.path.dirname(__file__),                                        "flags", filename + ".png")                pixmap = QPixmap(filename)                if pixmap.isNull():                    return QVariant()                return QVariant(pixmap)        return treeoftable.TreeOfTableModel.data(self, index, role)class TreeOfTableWidget(QTreeView):    activated_signal=pyqtSignal(list)    def __init__(self, filename, nesting, separator, parent=None):        super(TreeOfTableWidget, self).__init__(parent)        self.setSelectionBehavior(QTreeView.SelectItems)        self.setUniformRowHeights(True)        model = ServerModel(self)        self.setModel(model)        try:            model.load(filename, nesting, separator)        except IOError as e:            QMessageBox.warning(self, "Server Info - Error", str(e))        self.activated[QModelIndex].connect(self.activate)        self.expanded.connect(self.expand)        self.expand()    def currentFields(self):        return self.model().asRecord(self.currentIndex())    def activate(self, index):        self.activated_signal.emit(self.model().asRecord(index))    def expand(self):        for column in range(self.model().columnCount(                            QModelIndex())):            self.resizeColumnToContents(column)class MainForm(QMainWindow):    def __init__(self, filename, nesting, separator, parent=None):        super(MainForm, self).__init__(parent)        headers = ["Country/State (US)/City/Provider", "Server", "IP"]        if nesting != 3:            if nesting == 1:                headers = ["Country/State (US)", "City", "Provider",                           "Server"]            elif nesting == 2:                headers = ["Country/State (US)/City", "Provider",                           "Server"]            elif nesting == 4:                headers = ["Country/State (US)/City/Provider/Server"]            headers.append("IP")        self.treeWidget = TreeOfTableWidget(filename, nesting,                                            separator)        self.treeWidget.model().headers = headers        self.setCentralWidget(self.treeWidget)        QShortcut(QKeySequence("Escape"), self, self.close)        QShortcut(QKeySequence("Ctrl+Q"), self, self.close)        self.treeWidget.activated_signal[list].connect(self.activated)        self.setWindowTitle("Server Info")        self.statusBar().showMessage("Ready...", 5000)    def picked(self):        return self.treeWidget.currentFields()    def activated(self, fields):        self.statusBar().showMessage("*".join(fields), 60000)app = QApplication(sys.argv)nesting = 3if len(sys.argv) > 1:    try:        nesting = int(sys.argv[1])    except:        pass    if nesting not in (1, 2, 3, 4):        nesting = 3form = MainForm(os.path.join(os.path.dirname(__file__), "servers.txt"),                nesting, "*")form.resize(750, 550)form.show()app.exec_()print("*".join(form.picked()))

运行结果:

这里写图片描述

1 0
原创粉丝点击