The code below creates a single QTableView driven by Model/Proxy framework.
The self.headerNames
list-variable declared in source-model
stores the names of the Header's Columns. The number of names in this list is used by the same source model
's columnCount()
method to return the number of column in a view:
def columnCount(self, parent=QModelIndex()):
return len(self.headerNames)
The Proxy
model's headerData()
access this self.headerNames
variable via source model
:
sourceModel=self.sourceModel()
On if role==Qt.DisplayRole
the Proxy retrieves and returns the name of the column to QTableView:
return QVariant( sourceModel.headerNames[column] )
There is a right-click menu implemented on header-column right-click. That portion is working fine. But since I could not find any examples on how others do it I had to design how it would work myself. I would appreciate if you find it could be improved.
What I want to implement next is the ability to re-arrange the column in arbitrary order. But I am not sure where to start.
P.s. Please disregard the names of the Items displayed in QTableView. I wanted to keep the code as simple as possible focusing on Header/Column subject only here.
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 = ['Item_A_001','Item_A_002','Item_B_001','Item_B_002']
self.headerNames=['Column 0','Column 1','Column 2','Column 3','Column 4','Column 5','Column 6','Column 7']
def rowCount(self, parent=QModelIndex()):
return len(self.items)
def columnCount(self, parent=QModelIndex()):
return len(self.headerNames)
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 filterAcceptsRow(self, row, parent):
return True
def headerData(self, column, orientation, role=Qt.DisplayRole):
sourceModel=self.sourceModel()
if role==Qt.TextAlignmentRole:
if orientation==Qt.Horizontal:
return QVariant(int(Qt.AlignHCenter|Qt.AlignVCenter))
return QVariant(int(Qt.AlignHCenter|Qt.AlignVCenter))
if role==Qt.DisplayRole:
if orientation==Qt.Horizontal:
return QVariant( sourceModel.headerNames[column] )
else:
return QVariant()
else:
return QVariant()
return QVariant(int(column+1))
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
tableModel=Model(self)
proxyModel=Proxy()
proxyModel.setSourceModel(tableModel)
self.tableview=QTableView(self)
self.tableview.setModel(proxyModel)
self.tableview.horizontalHeader().setStretchLastSection(True)
self.tableview.setSelectionMode(QAbstractItemView.MultiSelection)
header=self.tableview.horizontalHeader()
header.setContextMenuPolicy(Qt.CustomContextMenu)
header.connect(header, SIGNAL("customContextMenuRequested(QPoint)" ), self.headerRightClicked)
self.resHeaderMenu=QMenu(self)
for column in range(proxyModel.columnCount()):
columnName=proxyModel.headerData(column, Qt.Horizontal).toPyObject()
actn=QAction('%s'%columnName, self.resHeaderMenu, checkable=True)
actn.setChecked(True)
actn.triggered.connect(self.resHeaderMenuTriggered)
self.resHeaderMenu.addAction(actn)
layout = QVBoxLayout(self)
layout.addWidget(self.tableview)
self.setLayout(layout)
def headerRightClicked(self, QPos):
parentPosition=self.tableview.mapToGlobal(QPoint(0, 0))
menuPosition=parentPosition + QPos
self.resHeaderMenu.move(menuPosition)
self.resHeaderMenu.show()
def resHeaderMenuTriggered(self, arg):
print 'resHeaderMenuTriggered', arg
for i, actn in enumerate(self.resHeaderMenu.actions()):
if not actn.isChecked():
self.tableview.setColumnHidden(i, True)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
In Object Explorer, right-click the table with columns you want to reorder and select Design. Select the box to the left of the column name that you want to reorder. Drag the column to another location within the table.
Yes, column order does matter.
In case you really want to re-arrange the columns yourself:
You can move or swap sections via the moveSection and swapSections methods of the horizontalHeader
.
headerView.moveSection(x, y)
will move column x
such that it's column y
afterwards, while
headerView.swapSections(x,y)
will - obviously - swap the positions of the two columns.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With