1

The code below creates a window with two QTableViews placed side-by-side:

enter image description here

The left-side TableView is linked to QAbstractTableModel. And according to a logic defined in Model.data() the tableView's items are positioned vertically.

The right-side TableView is linked to a QSortFilterProxyModel. And I want to use it to change the vertical TableView items placement to horizontal.

Please post your suggestions on how that could be achieved. It's OK if the solution on changing the item's orientation wouldn't require ProxyModel... as long as it works!

SOURCE CODE POSTED LATER.

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Model(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = ['Row0_Column0','Row0_Column1','Row0_Column2']

    def rowCount(self, parent):
        return len(self.items)       
    def columnCount(self, parent):
        return 1

    def data(self, index, role):
        if not index.isValid(): return QVariant()
        elif role != Qt.DisplayRole:
            return QVariant()

        row=index.row()
        if row<len(self.items):
            return QVariant(self.items[row])
        else:
            return QVariant()

class Proxy(QSortFilterProxyModel):
    def __init__(self):
        super(Proxy, self).__init__()

    def rowCount(self, parent):
        return 1 
    def columnCount(self, parent):
        sourceModel=self.sourceModel()
        return len(sourceModel.items) 

    def filterAcceptsRow(self, row, parent):
        sourceModel=self.sourceModel()
        sourceModelIndex=sourceModel.index(row, 0, QModelIndex())

        sourceModelIndexName=sourceModel.data(sourceModelIndex, Qt.DisplayRole).toString()
        return True

class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)

        tablemodel=Model(self)               

        proxy=Proxy()
        proxy.setSourceModel(tablemodel)

        tableviewA=QTableView() 
        tableviewA.setModel(tablemodel)

        tableviewB=QTableView() 
        tableviewB.setModel(proxy)

        layout = QHBoxLayout(self)
        layout.addWidget(tableviewA)
        layout.addWidget(tableviewB)
        self.setLayout(layout)

    def test(self, arg):
        print arg

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())
NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
alphanumeric
  • 17,967
  • 64
  • 244
  • 392
  • There's a similar solution in C++ at http://stackoverflow.com/questions/21653253/how-to-change-orientation-of-qt-tableview – savolai ᯓ Jul 11 '15 at 18:14

2 Answers2

2

An interesting assignment...

class Model2(QAbstractTableModel):
    def __init__(self, model, parent=None):
        self.model = model
        QAbstractTableModel.__init__(self, parent)

    def rowCount(self):
        return self.model.columnCount()

    def columnCount(self):
        return self.model.rowCount()

    def data(self, a, b):
        return self.model.data(b, a)
mdurant
  • 27,272
  • 5
  • 45
  • 74
0

Here is the working solution of using Proxy to re-orient the items from Vertical to Horizontal.

The trick is to override the soruce model's .data() method by declaring it under the Proxy model. When declared on Proxy it takes a precedence over the source model's .data() method:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Model(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = ['Row0_Column0','Row0_Column1','Row0_Column2']

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable

    def rowCount(self, parent):
        return len(self.items)       
    def columnCount(self, parent):
        return len(self.items)  

    def data(self, index, role):
        if not index.isValid(): return QVariant()
        elif role != Qt.DisplayRole:
            return QVariant()

        row=index.row()
        if row<len(self.items):
            return QVariant(self.items[row])
        else:
            return QVariant()

    def setData(self, index, value, role=Qt.EditRole):
        if index.isValid():            
            if role == Qt.EditRole:                
                row = index.row()
                self.items[row]=value  
                return True
        return False

class Proxy(QSortFilterProxyModel):
    def __init__(self):
        super(Proxy, self).__init__()        

    def rowCount(self, parent):
        return 1 
    def columnCount(self, parent):
        sourceModel=self.sourceModel()
        return len(sourceModel.items) 

    def filterAcceptsRow(self, row, parent):
        sourceModel=self.sourceModel()
        sourceModelIndex=sourceModel.index(row, 0, QModelIndex())

        sourceModelIndexName=sourceModel.data(sourceModelIndex, Qt.DisplayRole).toString()
        return True

    def data(self, index, role):
        sourceModel=self.sourceModel()
        items=sourceModel.items

        if not index.isValid(): return QVariant()
        elif role != Qt.DisplayRole:
            return QVariant()

        row=index.row()
        column=index.column()

        if column<len(items):
            return QVariant(items[column])
        else:
            return QVariant()


class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)

        tablemodel=Model(self)               

        proxy=Proxy()
        proxy.setSourceModel(tablemodel)

        tableviewA=QTableView() 
        tableviewA.setModel(tablemodel)

        tableviewB=QTableView() 
        tableviewB.setModel(proxy)

        layout = QHBoxLayout(self)
        layout.addWidget(tableviewA)
        layout.addWidget(tableviewB)
        self.setLayout(layout)

    def test(self, arg):
        print arg

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

And here is a second solution inspired by mdurant answer. I am suing here two QAbstractTableModel. The second model queries the first model self.items data variable.

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Horizontal(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = ['Row0_Column0','Row0_Column1','Row0_Column2']
        self.childModel=None

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable

    def rowCount(self, parent):
        return len(self.items)       
    def columnCount(self, parent):
        return 1

    def data(self, index, role):
        if not index.isValid(): return QVariant()
        elif role != Qt.DisplayRole:
            return QVariant()

        row=index.row()
        if row<len(self.items):
            return QVariant(self.items[row])
        else:
            return QVariant()

    def setData(self, index, value, role=Qt.EditRole):
        if index.isValid():            
            if role == Qt.EditRole:                
                row = index.row()
                self.items[row]=value  
                if self.childModel: self.childModel.reset()
                return True
        return False

class Vertical(QAbstractTableModel):
    def __init__(self, items=None, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = items

    def rowCount(self, parent):
        return 1      
    def columnCount(self, parent):
        return len(self.items)    

    def data(self, index, role):
        if not index.isValid(): return QVariant()
        elif role != Qt.DisplayRole:
            return QVariant()

        column=index.column()
        if column<len(self.items):
            return QVariant(self.items[column])
        else:
            return QVariant()

class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)

        modelV=Horizontal(self)         

        tableviewA=QTableView() 
        tableviewA.setModel(modelV)

        modelH=Vertical(modelV.items)
        modelV.childModel=modelH

        tableviewB=QTableView() 
        tableviewB.setModel(modelH)

        layout = QHBoxLayout(self)
        layout.addWidget(tableviewA)
        layout.addWidget(tableviewB)
        self.setLayout(layout)

    def test(self, arg):
        print arg

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())
Community
  • 1
  • 1
alphanumeric
  • 17,967
  • 64
  • 244
  • 392