Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QDataWidgetMapper and multiple delegates

Tags:

qt

pyqt

pyside

mapper = QtGui.QDataWidgetMapper()
mapper.setModel(my_table_model)
mapper.addMapping(widgetA, 0) #mapping widget to a column
mapper.addMapping(widgetB, 1) #mapping widget to a column
mapper.setItemDelegate(MyDelegateA(widgetA)) #Hmm. Where is the 'column' parameter?
mapper.setItemDelegate(MyDelegateB(widgetB)) #now itemDelegate is rewritten, MyDelegateB will be used

So... How do I set up mutiple delegates for a single QDataWidgetMapper? As far as I understand there is no QDataWidgetMapper.setItemDelegateForColumn() Or do I have to create some delegate factory, which will use appropriate delegates?

Thanks!

like image 761
AlexVhr Avatar asked Apr 01 '12 21:04

AlexVhr


3 Answers

You have to use one single delegate and handle the way behavior of the different widgets in the setEditorData and setModelData functions of the delegate. For an example (C++ but straight forward) check this article from Qt Quarterly.

like image 55
pnezis Avatar answered Nov 03 '22 21:11

pnezis


Ok, I got it. (At least, it works for me). So, the main idea is this class (a simplified version), which keeps a list of real delegate instances and routes data to\from them:

class DelegateProxy(QtGui.QStyledItemDelegate):

    def __init__(self, delegates, parent=None):
        QtGui.QStyledItemDelegate.__init__(self, parent)
        self.delegates = delegates

    def setEditorData(self, editor, index):
        delegate = self.delegates[index.column()] 
        delegate.setEditorData(editor, index)

    def setModelData(self, editor, model, index):
        delegate = self.delegates[index.column()]
        delegate.setModelData(editor, model, index)

Fully working example is in the pastebin

like image 3
AlexVhr Avatar answered Nov 03 '22 20:11

AlexVhr


I found this problem too, and it really sucks. I'm right now trying to subclass QtGui.QDataWidgetMapper in order to workaround this, the subclass having its own addMapping() with a delegate argument, a dict to store the delegate for each widget, and a matching meta-delegate that calls the appropiate delegate for each case.

The weirdest thing about this is the problem also existed in earlier versions of Qt 4 in QAbstractItemView (i.e tables and trees) and later was fixed adding the setItemDelegateForColumn() method, but QDataWidgetMapper didn't get the fix.

An alternative could be using more than a mapper, and connect them to keep them in sync if necessary, but it is a bit messy, specially if you need lots of different special delegates:

mainMapper = QtGui.QDataWidgetMapper()
mainMapper.setModel(my_table_model)

auxMapper1 = QtGui.QDataWidgetMapper()
auxMapper1.setModel(my_table_model)

# If you move the index in the main mapper, the auxiliary will follow
mainMapper.currentIndexChanged.connect(auxMapper1.setCurrentIndex)

mainMapper.addMapping(widgetA, 0) #mapping widget to a column
auxMapper1.addMapping(widgetB, 1) #mapping widget to a column

mainMapper.setItemDelegate(MyDelegateA(widgetA))
auxMapper1.setItemDelegate(MyDelegateB(widgetB))
like image 1
Shulai Avatar answered Nov 03 '22 21:11

Shulai