[PyKDE] strange problems with lxml and PyQt4

Andreas Pakulat apaku at gmx.de
Thu Jan 12 17:21:31 GMT 2006


On 12.01.06 09:48:24, Phil Thompson wrote:
> You need to post a short, but complete, example that demonstrates the problem. 

No Problem, is attached including a sample xml file.

> When people select code fragments to post, but can't find the error, its 
> usually because they are looking in the wrong place.

Or they don't have the slightest idea what could cause an error like
the posted one and therefore cannot do more than look at the traceback.

To reproduce just execute the script and select the entry then try to
add a new entry (the upper button) or remove it (the lower one). Adding
a new entry when nothing is selected works.

Andreas

-- 
Tonight's the night: Sleep in a eucalyptus tree.
-------------- next part --------------
<?xml version="1.0" encoding="utf-8"?>
<pictureFormats xmlns="testns">
  <pictureFormat>Widescreen 1:2,35</pictureFormat>
</pictureFormats>
-------------- next part --------------
from PyQt4 import QtGui, QtCore
from lxml import etree
import sys

moviedbns = "testns"

def buildQName(ns, name):
    return "{%s}%s" % (ns, name)


def buildElement(parent, elementType):
    return etree.SubElement(parent, buildQName(moviedbns, elementType))


modeldata = { 
    'elementname':'pictureFormat', 
    'items': 
    [
        { 
            'elemattr' : 'format',
            'variantmethod' : 'toString',
            'header' : QtCore.QT_TR_NOOP('Format')
        },
    ]
}


class Ui_PictureFormatWidget(object):
    def setupUi(self, PictureFormatWidget):
        PictureFormatWidget.setObjectName("PictureFormatWidget")
        PictureFormatWidget.resize(QtCore.QSize(QtCore.QRect(0,0,298,120).size()).expandedTo(PictureFormatWidget.minimumSizeHint()))
        
        self.vboxlayout = QtGui.QVBoxLayout(PictureFormatWidget)
        self.vboxlayout.setMargin(0)
        self.vboxlayout.setSpacing(6)
        self.vboxlayout.setObjectName("vboxlayout")
        
        self.groupBox = QtGui.QGroupBox(PictureFormatWidget)
        self.groupBox.setObjectName("groupBox")
        
        self.hboxlayout = QtGui.QHBoxLayout(self.groupBox)
        self.hboxlayout.setMargin(6)
        self.hboxlayout.setSpacing(6)
        self.hboxlayout.setObjectName("hboxlayout")
        
        self.pictureFormats = QtGui.QTableView(self.groupBox)
        self.pictureFormats.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.pictureFormats.setObjectName("pictureFormats")
        self.hboxlayout.addWidget(self.pictureFormats)
        
        self.vboxlayout1 = QtGui.QVBoxLayout()
        self.vboxlayout1.setMargin(0)
        self.vboxlayout1.setSpacing(6)
        self.vboxlayout1.setObjectName("vboxlayout1")
        
        spacerItem = QtGui.QSpacerItem(20,40,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding)
        self.vboxlayout1.addItem(spacerItem)
        
        self.addPictureFormat = QtGui.QPushButton(self.groupBox)
        self.addPictureFormat.setIcon(QtGui.QIcon(":/widgets/images/add_64x64.png"))
        self.addPictureFormat.setObjectName("addPictureFormat")
        self.vboxlayout1.addWidget(self.addPictureFormat)
        
        self.removePictureFormat = QtGui.QPushButton(self.groupBox)
        self.removePictureFormat.setIcon(QtGui.QIcon(":/widgets/images/remove_64x64.png"))
        self.removePictureFormat.setObjectName("removePictureFormat")
        self.vboxlayout1.addWidget(self.removePictureFormat)
        
        spacerItem1 = QtGui.QSpacerItem(20,40,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding)
        self.vboxlayout1.addItem(spacerItem1)
        self.hboxlayout.addLayout(self.vboxlayout1)
        self.vboxlayout.addWidget(self.groupBox)
        
        self.retranslateUi(PictureFormatWidget)

    
    def tr(self, string):
        return QtGui.QApplication.translate("PictureFormatWidget", string, None, QtGui.QApplication.UnicodeUTF8)
    
    def retranslateUi(self, PictureFormatWidget):
        PictureFormatWidget.setWindowTitle(self.tr("Form"))
        self.groupBox.setTitle(self.tr("PictureFormats"))


class GeneralTableModel(QtCore.QAbstractItemModel):
    """
    Customizable Model for Tables and Lists being build on a list of ElementTree Elements
    
    Customization is provided in the modeldata initialization parameter for the
    list given as list parameter. The modeldata needs to be a dictionary that has
    an items and an elementname entry. 
    
    elementname contains the XML Element name for new data items
    
    items contains a list of dictionaries resembling the columns of the table/list.
    Each dictionary in the list needs to provide 3 entries:
        elemattr specifies the attribute that this column should work on
        variantmethod specifies which QVariant "toXXX" method should be used for conversion
        header contains the string that should be display in the header
    """
    
    def __init__(self, list, modeldata, parent = None):
        QtCore.QAbstractItemModel.__init__(self, parent)
        self.datalist = list
        self.items = modeldata['items']
        self.elementname = modeldata['elementname']
        
    def data(self, index, role):
        if not index.isValid() or \
                    ( role != QtCore.Qt.DisplayRole and role != QtCore.Qt.EditRole ) or \
                    not self.datalist:
            return QtCore.QVariant()
            
        if index.row() >= 0 and index.row() < self.rowCount(index.parent()) and \
                index.column() < self.columnCount(index) and index.column() >= 0:
            data = getattr(self.datalist[index.row()], self.items[index.column()]['elemattr'])
            return QtCore.QVariant(data)
        
        return QtCore.QVariant()
        
    def headerData( self, column, orientation, role = QtCore.Qt.DisplayRole):
        if orientation == QtCore.Qt.Horizontal:
            return QtCore.QVariant(self.items[column]['header'])
        return QtCore.QVariant()
        
    def index(self, row, column, parent = QtCore.QModelIndex()):
        if parent == QtCore.QModelIndex() and row >= 0 and row < self.rowCount(parent) and self.datalist:
            return self.createIndex(row, column)
        return QModelIndex()
            
    def rowCount(self, parent = QtCore.QModelIndex()):
        if parent == QtCore.QModelIndex() and self.datalist:
            return len(self.datalist)
        return 0
        
    def columnCount(self, index = QtCore.QModelIndex()):
        return len(self.items)
        
    def flags(self, index):
        if not index.isValid():
            return QtCore.Qt.ItemIsEnabled
        return QtCore.QAbstractItemModel.flags(self, index) | QtCore.Qt.ItemIsEditable
        
    def insertRows(self, row, count, parent = QtCore.QModelIndex()):
        if not self.datalist:
            return False
        
        self.beginInsertRows( parent, row, count+row-1)
        for i in range(0, count):
            self.datalist.insert(row+i, buildElement(self.datalist, self.elementname))
        self.endInsertRows()
        return True
    
    def removeRows(self, row, count, parent = QtCore.QModelIndex()):
        if not self.datalist or len(self.datalist) < count:
            return False
        self.beginRemoveRows(QtCore.QModelIndex(), row, count+row-1)
        lst = self.datalist
        del lst[row:row+count]
        self.endRemoveRows()
        return True
        
    def setData(self, index, data, role = QtCore.Qt.EditRole):
        if self.datalist and index.isValid() and role == QtCore.Qt.EditRole and \
                index.row() >= 0 and index.row() < self.rowCount(index.parent()) and \
                index.column() >= 0 and index.column() < self.columnCount(index):
            qvariantfunc = getattr(QtCore.QVariant, self.items[index.row()]['variantmethod'])
            setattr(self.datalist[index.row()], self.items[index.column()]['elemattr'], qvariantfunc(data))
            return True
        return False


class PictureFormatWidget(QtGui.QWidget, Ui_PictureFormatWidget):
    def __init__(self, parent = None):
        QtGui.QWidget.__init__(self, parent)
        Ui_PictureFormatWidget.__init__(self)
        self.setupUi(self)
        self.pictureFormats.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
        self.connect(self.removePictureFormat, QtCore.SIGNAL('clicked()'), self.on_removePictureFormat_clicked)
        self.connect(self.addPictureFormat, QtCore.SIGNAL('clicked()'), self.on_addPictureFormat_clicked)
    
    def setPictureFormatList( self, list ):
        model = GeneralTableModel(list, modeldata, self)
        old = self.pictureFormats.model()
        self.pictureFormats.setModel(model)
        if old:
            old = None
            
    def on_removePictureFormat_clicked(self):
        list = self.pictureFormats.selectionModel().selectedIndexes()
        model = self.pictureFormats.model()
        for index in list:
            model.removeRows(index.row(), 1, index.parent())

    def on_addPictureFormat_clicked(self):
        self.pictureFormats.model().insertRows(self.pictureFormats.model().rowCount(), 1)

class PictureFormat(etree.ElementBase):
    """Stores PictureFormat information"""
    
    def format(self):
        return str(self.text)
    
    def setFormat(self, format):
        self.text = format
    
    format = property(format, setFormat)

def main():
    myns = etree.Namespace(moviedbns)
    myns['pictureFormat'] = PictureFormat
    app = QtGui.QApplication(sys.argv)
    tree = etree.parse("filmdb.xml")
    doc = tree.getroot()
    widget = PictureFormatWidget()
    widget.setPictureFormatList(doc)
    widget.show()
    return app.exec_()

if __name__ == "__main__":
    sys.exit(main())


More information about the PyQt mailing list