Hello!First of all,I'm so sorry for this huge post!!I wrote the whole code from the book,that's why the post is so big!!I'm reading this book : Rapid Gui Programming with Python and Qt.And I have problem understanding some parts of the code.I would be really thankful if someone could help me understand.In chapter 16 the writer creates a QTreeView.
-According to the book: "Since we have 6 fields (each field is separated by an asterisk) this means that the first 4 fields will be shown in the tree part of the tree widget with the remaining 2 fields shown as separate columns in the rows that have leaves.The resultant tree view will have 3 columns,one containing the tree and 2 more showing the extra fields." What I don't understand is where in the code is shown that the 4 fields will be shown in the tree part and the 2 fields will be the 2 extra columns that will have the information about the leaves??Where does he fill the 2 columns?I don't get how he comes to this conclusion.Also,if in the text file,each line had different number of fields(and not 6 fields in each line),what would happen then??How could we create the tree view of this example then??
-One last thing that I don't understand is this: In the serverinfo.py ,in the end of the script there is this line of code: form=MainForm(os.path.join(os.path.dirname(__file__), "servers.txt"),nesting, ""),this comes from self.treeWidget=TreeOfTableWidget(filename,nesting,separator)?? And why does he use os.path.join(os.path.dirname(__file__))?

serverinfo.pyw

#!/usr/bin/env python    
import os
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import treeoftable

class 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):
    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, e:
            QMessageBox.warning(self, "Server Info - Error",
                                unicode(e))
        self.connect(self, SIGNAL("activated(QModelIndex)"),
                     self.activated)
        self.connect(self, SIGNAL("expanded(QModelIndex)"),
                     self.expanded)
        self.expanded()

    def currentFields(self):
        return self.model().asRecord(self.currentIndex())

    def activated(self, index):
        self.emit(SIGNAL("activated"), self.model().asRecord(index))

    def expanded(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.connect(self.treeWidget, SIGNAL("activated"),
                     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 = 3
if len(sys.argv) > 1:
    try:
        nesting = int(sys.argv[1])
    except:
        pass
    if nesting not in (1, 2, 3, 4):
        nesting = 3

form = MainForm(os.path.join(os.path.dirname(__file__), "servers.txt"),
                nesting, "*")
form.resize(750, 550)
form.show()
app.exec_()
print "*".join(form.picked())

treeoftable.py

#!/usr/bin/env python

import bisect
import codecs
from PyQt4.QtCore import *
from PyQt4.QtGui import *

KEY, NODE = range(2)

class BranchNode(object):
    def __init__(self, name, parent=None):
        super(BranchNode, self).__init__(parent)
        self.name = name
        self.parent = parent
        self.children = []

    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
        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__(parent)
        self.parent = parent
        self.fields = fields

    def orderKey(self):
        return u"\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): 
        assert nesting > 0
        self.nesting = nesting
        self.root = BranchNode("")
        exception = None
        fh = None
        try:
            for line in codecs.open(unicode(filename), "rU", "utf8"):
                if not line:
                    continue
                self.addRecord(line.split(separator), False)
        except IOError, e:
            exception = e
        finally:
            if fh is not None:
                fh.close()
            self.reset()
            for i in range(self.columns):
                self.headers.append("Column #%d" % 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.reset()

    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 QVariant(node.toString()) \
                if index.column() == 0 else QVariant(QString(""))
        return QVariant(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 QVariant(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

A part of the servers.txt file is like this:

Australia(No State)AdelaideDove Traceroute GatewayApache/1.3.6203.15.24.1
Australia
(No State)KenwickEscape NetApache/1.1.1203.25.185.2
Australia(No State)(Unknown City)Telstra NetApache/1.3.9210.8.232.2
Austria
(No State)ViennaAT NetRoxen·Challenger/1.3.11162.116.33.47
Austria(No State)(Unknown City)ISP AustriaApache/1.2.4195.58.162.92
Belgium
(No State)(Unknown City)Belgian Research NetworkApache/1.3.3193.190.198.13
Belgium(No State)(Unknown City)IntersightMicrosoft-IIS/3.0193.121.16.55
Bulgaria
(No State)SofiaLirex Looking GlassApache/1.3.3194.12.224.34
Canada(No State)Sherwood ParkDavid's Net-PresenceApache/1.3.9204.209.9.33
Canada
(No State)Prince GeorgeMag-Net InternetApache/1.3.9207.102.83.2
Czech Republic(No State)Frydek-MistekTraceroute AppleT.czApache/1.3.9212.71.150.6
Denmark
(No State)TranbjergTeledenmark Erhverv Data DivisionenApache/1.2b8193.162.146.38
Denmark(No State)LyngbyNiels Bohr InstituteCERN/3.0130.225.212.55
Estonia
(No State)TallinnMicroLink OnlineApache/1.1.1194.106.96.6
etc.

Recommended Answers

All 5 Replies

The MainForm __init__ arguments are
(self, filename, nesting, separator, parent=None)
and should give you a hint

The author of the book does not do any necessary commenting and should be discounted. I would return the lousy book.

file is the name of de module file that is actually in use.
os.path.dirname gets the directory path where the file is stored.
os.path.join creates a new path concatenating first argument to second argument.

Thank you -both of you- for your time and for your answers!
@HiHe : It's actually a very good book.The writer explains most of the code in the book.It's entirely my fault.It's just that I'm a beginner in programming and I can't understand some parts of the code if they are not explained in detail (or at all).

One good tool to see what is going on in strange code is to put in temporary test print()

Although I'm a little bit late,thank you!!!I'll keep that in mind!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.