A code below create a window with QListView on a left side and QTableView on a right.
Using .setModel() QListView was assigned ListModel and QTableView was assigned TableModel.
On a window start-up only a List View gets populated with the items. A right-table-view gets populated only when left-side-list-view gets clicked.
Question: Why this code crashes? Is it because two models in use in the same time?
import sys, os
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}
class ListModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
key=str(self.items[index.row()])
if role==QtCore.Qt.UserRole:
return key
if role==QtCore.Qt.DisplayRole:
return key
def addItem(self, key=None, column=0):
totalItems=self.rowCount()+1
self.beginInsertRows(QtCore.QModelIndex(), totalItems, column)
self.items.append(str(key))
self.endInsertRows()
def buildItems(self):
for key in elements:
self.addItem(key)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 4
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
if role==QtCore.Qt.DisplayRole:
return key
def addItem(self, each=None, column=0):
totalItems=self.rowCount()+1
self.beginInsertRows(QtCore.QModelIndex(), totalItems, column)
self.items.append(str(each))
self.endInsertRows()
def rebuildItems(self, index):
key = index.data(QtCore.Qt.UserRole)
if not key: return
key=str(key.toString())
for each in elements[key]:
self.addItem(str(each))
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
self.dataModel=ListModel()
self.dataModel.buildItems()
self.dataModelB=TableModel()
self.viewA=QtGui.QListView()
self.viewA.setModel(self.dataModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QTableView()
self.viewB.setModel(self.dataModelB)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self, index):
self.viewB.model().rebuildItems(index)
window=Window()
sys.exit(app.exec_())
EDITED LATER:
Below is a fixed code. In the original example the problem was caused by improper usage of .beginInsertRows() method. I mistakenly thought that the last argument to be supplied is a column number. But according to the documentation (thanks to three_pineapples for pointing out) the last argument should be the last row-number to be inserted.
import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}
class ListModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
key=str(self.items[index.row()])
if role==QtCore.Qt.UserRole:
return key
if role==QtCore.Qt.DisplayRole:
return key
def addItem(self, key=None):
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self.items.append(str(key))
self.endInsertRows()
def buildItems(self):
for key in elements:
self.addItem(key)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 4
def data(self, index, role):
key=str(self.items[index.row()])
column=index.column()
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
if role==QtCore.Qt.DisplayRole:
if not column: return key
else:
print key, column, elements.get(key,{}).get(column)
return elements.get(key,{}).get(column)
def rebuildItems(self, index):
key=index.data(QtCore.Qt.UserRole).toString()
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self.items.append(key)
self.endInsertRows()
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
self.dataModel=ListModel()
self.dataModel.buildItems()
self.dataModelB=TableModel()
self.viewA=QtGui.QListView()
self.viewA.setModel(self.dataModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QTableView()
self.viewB.setModel(self.dataModelB)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self, index):
self.viewB.model().rebuildItems(index)
window=Window()
sys.exit(app.exec_())
I can't reproduce your crash on PyQt v4.11.1, 32-bit Python 2.7, Windows 8.1.
However, your TableModel implementation is completely broken, so presumably that would explain why it crashes on your Mac?
Specifically:
The signature for beginInsertRows appears to be wrong. It doesn't follow the documentation here (linked to from the QAbstractTableModel page here). The signature is not beginInsertRows(parent, row, column) but rather beginInsertRows(parent, row, numRows).
The value for the row you are inserting to should be self.rowCount() as row indexing starts from 0. So when you have 0 items in your model, you insert to row 0 (the first row). When you have 1 item in your model, you insert into row 1 (the second row), etc.
The TableModel.data() method is broken. Specifically it appears to be missing the line key=str(self.items[index.row()])
My question would be, since you seem to be having trouble with models quite regularly (I feel like I've seen many questions on here from you in regards to implementing a custom model), why aren't you using the predefined Qt model QStandardItemModel which does all of the complex stuff for you? (You don't need to subclass it to use it)
If you want help translating the example you've posted above to using QStandardItemModel, please post a new question. I'm sure either I or someone else will answer it quickly.
Related
With two views:
listView=QtGui.QListView()
tableView==QtGui.QTableView()
I go ahead and define a custom DataModel to be used by both listView and tableView:
class DataModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.data=[['One':'Two'],['Three','Four']]
def data(self, index, role):
row=index.row()
if requested by listView:
return self.data[row][0]
elif requested by tableView:
return self.data[row][1]
Finally assigning the instance of the model to both views:
model=DataModel()
listView.setModel(model)
tableView.setModel(model)
Since both views share the same model there is a chance the model would need to return different values based on what view widget is requesting it. If you take a look at data() method there is fake if/elif statement showing what I need. Is there any way to do this logic from inside of model methods: if requested by ListView... and elif requested by TableView
Edited later:
import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{0:'Bison',1:'Panther',2:'Elephant'},'Birds':{0:'Duck',1:'Hawk',2:'Pigeon'},'Fish':{0:'Shark',1:'Salmon',2:'Piranha'}}
class DataModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.modelDict={}
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 3
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
key=str(self.items[index.row()])
column=index.column()
if role==QtCore.Qt.ItemDataRole: return self.modelDict.get(str(index.data().toString()))
if role==QtCore.Qt.DisplayRole:
if column==0 and not self.columnCount():
return key
else:
return self.modelDict.get(key).get(column)
def addItem(self, itemName=None, column=0):
totalItems=self.rowCount()+1
self.beginInsertRows(QtCore.QModelIndex(), totalItems, column)
if not itemName: itemName='Item %s'%self.rowCount()
self.items.append(itemName)
self.endInsertRows()
def buildItems(self):
for key in self.modelDict:
index=QtCore.QModelIndex()
self.addItem(key)
class ProxyTableModel(QtGui.QSortFilterProxyModel):
def __init__(self, parent=None):
super(ProxyTableModel, self).__init__(parent)
def headerData(self, column, orientation, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.TextAlignmentRole:
if orientation == QtCore.Qt.Horizontal:
return QtCore.QVariant(int(QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter))
return QtCore.QVariant(int(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter))
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation==QtCore.Qt.Horizontal:
if column==0:
return QtCore.QVariant("Spicie 0")
elif column==1:
return QtCore.QVariant("Spicie 1")
elif column==2:
return QtCore.QVariant("Spicie 2")
return QtCore.QVariant(int(column + 1))
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
self.dataModel=DataModel()
self.dataModel.modelDict=elements
self.dataModel.buildItems()
self.proxyModel=ProxyTableModel()
self.proxyModel.setFilterKeyColumn(0)
self.proxyModel.setSourceModel(self.dataModel)
self.viewA=QtGui.QListView()
self.viewA.setModel(self.dataModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QTableView()
self.viewB.setModel(self.proxyModel)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self):
index=self.viewA.currentIndex()
key=self.dataModel.data(index, QtCore.Qt.DisplayRole)
value=self.dataModel.data(index, QtCore.Qt.ItemDataRole)
self.proxyModel.setFilterRegExp('%s'%key)
print 'onClick(): key: %s'%key
window=Window()
sys.exit(app.exec_())
Done, by hiding the zeroth "key" column:
class DataModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.modelDict={}
self.names=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.names)
def columnCount(self, index=QtCore.QModelIndex()):
return 4
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.names)): return QtCore.QVariant()
row,col = index.row(),index.column()
if col==0:
if role==QtCore.Qt.DisplayRole:
return self.names[row]
else:
if role==QtCore.Qt.DisplayRole:
return self.modelDict[self.names[row]][col]
def addItem(self, itemName=None, column=0):
totalItems=self.rowCount()+1
self.beginInsertRows(QtCore.QModelIndex(), totalItems, column)
if not itemName: itemName='Item %s'%self.rowCount()
self.names.append(itemName)
self.endInsertRows()
def buildItems(self):
for key in self.modelDict:
index=QtCore.QModelIndex()
self.addItem(key)
class ProxyModel(QtGui.QSortFilterProxyModel):
def __init__(self, parent=None):
super(ProxyModel, self).__init__(parent)
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
self.dataModel=DataModel()
self.dataModel.modelDict=elements
self.dataModel.buildItems()
self.proxyModel=ProxyModel()
self.proxyModel.setFilterKeyColumn(0)
self.proxyModel.setSourceModel(self.dataModel)
self.viewA=QtGui.QListView()
self.viewA.setModel(self.dataModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QTableView()
self.viewB.setModel(self.proxyModel)
self.viewB.setColumnHidden(0,True)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self):
index=self.viewA.currentIndex()
key=self.dataModel.data(index, QtCore.Qt.DisplayRole)
self.proxyModel.setFilterRegExp('%s'%key)
The code below creates a single QListView. An instance of MyClass (it is inherited from QAbstractListModel) is assigned to its self.setModel(self.model). If I click the view I can select the items in a list (so they do exist). But no names of the items displayed. How do I control how the QListView items are displayed?
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
class MyClass(QtCore.QAbstractListModel):
def __init__(self):
super(MyClass, self).__init__()
self.elements={'Animals':['Bison','Panther','Elephant'],'Birds':['Duck','Hawk','Pigeon'],'Fish':['Shark','Salmon','Piranha']}
def rowCount(self, index=QtCore.QModelIndex()):
return len(self.elements)
def data(self, index, role=QtCore.Qt.DisplayRole):
print'MyClass.data():',index,role
class ListView(QtGui.QListView):
def __init__(self):
super(ListView, self).__init__()
self.model=MyClass()
self.setModel(self.model)
self.show()
window=ListView()
sys.exit(app.exec_())
I don't know how to use a dictionary for the elements, but using lists:
self.elements=['Bison','Panther','Elephant','Duck','Hawk','Pigeon','Shark','Salmon','Piranha']
You just have to return self.elements[index.row()] in the data() method. For instance:
class MyClass(QtCore.QAbstractListModel):
def __init__(self):
super(MyClass, self).__init__()
self.elements=['Bison','Panther','Elephant','Duck','Hawk','Pigeon','Shark','Salmon','Piranha']
def rowCount(self, index=QtCore.QModelIndex()):
return len(self.elements)
def data(self, index, role=QtCore.Qt.DisplayRole):
print'MyClass.data():',index,role
if index.isValid() and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant(self.elements[index.row()])
else:
return QtCore.QVariant()
A code below creates a single QListView. Clicking its item should delete it from .model(). While an item gets deleted there is IndexError: list index out of range. What is wrong with the code?
import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}
class Model(QtCore.QAbstractListModel):
def __init__(self):
QtCore.QAbstractListModel.__init__(self)
self.items=[]
self.modelDict={}
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.modelDict)
def data(self, index, role):
if index.isValid():
if role==QtCore.Qt.ItemDataRole:
key=str(index.data().toString())
returnedValue=self.modelDict.get(key)
return QtCore.QVariant(returnedValue)
elif role==QtCore.Qt.DisplayRole:
row=index.row()
itemTitle=self.items[row]
return QtCore.QVariant(itemTitle)
def addItems(self):
for key in self.modelDict:
index=QtCore.QModelIndex()
self.beginInsertRows(index, 0, 0)
self.items.append(key)
inst=self.modelDict.get(key)
self.setData(index, QtCore.QVariant(inst), QtCore.Qt.DisplayRole)
self.endInsertRows()
def removeByIndex(self, index):
if index.isValid():
row=index.row()
self.beginRemoveRows(QtCore.QModelIndex(), row, 0)
self.items=[each for i,each in enumerate(self.items[:]) if i!=row]
self.endRemoveRows()
class ListView(QtGui.QListView):
def __init__(self):
super(ListView, self).__init__()
self.model= Model()
self.model.modelDict=elements
self.model.addItems()
self.setModel(self.model)
self.clicked.connect(self.itemClicked)
self.show()
def itemClicked(self, index):
itemTitle=self.model.data(index, QtCore.Qt.DisplayRole).toString()
itemData=self.model.data(index, QtCore.Qt.ItemDataRole).toPyObject()
print 'itemTitle: "%s" itemData: %s'%(itemTitle,itemData)
self.model.removeByIndex(index)
window=ListView()
sys.exit(app.exec_())
You were deleting rows without updating the rowCount; and latterly this led to empty elements where you were not supplying data. This works (note that I have removed the QVariants, for simplicity):
class Model(QtCore.QAbstractListModel):
def __init__(self):
QtCore.QAbstractListModel.__init__(self)
self.items=[]
self.modelDict={}
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def data(self, index, role):
if index.isValid():
if role==QtCore.Qt.ItemDataRole:
key=str(index.data().toString())
returnedValue=self.modelDict.get(key)
return QtCore.QVariant(returnedValue)
elif role==QtCore.Qt.DisplayRole:
row=index.row()
itemTitle=self.items[row]
return itemTitle
def addItems(self):
for key in self.modelDict:
index=QtCore.QModelIndex()
self.beginInsertRows(index, 0, 0)
self.items.append(key)
inst=self.modelDict.get(key)
self.setData(index, inst, QtCore.Qt.DisplayRole)
self.endInsertRows()
def removeByIndex(self, index):
if index.isValid():
row=index.row()
self.beginRemoveRows(QtCore.QModelIndex(), row, 0)
self.items=[each for i,each in enumerate(self.items[:]) if i!=row]
self.endRemoveRows()
class ListView(QtGui.QListView):
def __init__(self):
super(ListView, self).__init__()
self.model= Model()
self.model.modelDict=elements
self.model.addItems()
self.setModel(self.model)
self.clicked.connect(self.itemClicked)
self.show()
def itemClicked(self, index):
itemTitle=str(self.model.data(index, QtCore.Qt.DisplayRole))
print 'itemTitle: "%s"'%(itemTitle)
self.model.removeByIndex(index)
There is a dictionary with three keys: 'Animals', 'Birds' and 'Fish'.
The main dialog has two List views. The left view viewA displays the list of the keys mentioned above.
When one of its items is clicked the right view viewB displays the list of the species.
The question is how to manage viewB's display... Let's say the user clicks 'Animals': listB goes ahead and builds a brand new list of QListWidgetItem for every animal in a list. Then the user clicks 'Birds'. What should I do with already built viewB's "animal" items? Should I hide them? (hiding "Animals" items (instead of deleting) would allow me unhide them later when 'Animals' is clicked again (makes total sense if ListItems are heavy on graphics: thumbs, icons and etc. If a list of animals is 1000+ there will be a noticeable difference between rebuilding the ListItems from scratch and unhiding the ones that were build on a last click).
Another approach I see is to user viewB.clear() every time viewA's item is clicked. So the listB items are rebuilt every time listA item is clicked. But as I have mentioned with a long list of items it could be really slow. What logic to implement in situation like this?
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
layout=QtGui.QHBoxLayout()
self.setLayout(layout)
self.viewA=QtGui.QListWidget()
self.viewA.addItems(elements.keys())
self.viewA.itemClicked.connect(self.aClicked)
self.viewB=QtGui.QListWidget()
layout.addWidget(self.viewA)
layout.addWidget(self.viewB)
self.show()
def aClicked(self, item):
key='%s'%item.text()
values=elements.get(key)
items=[QtGui.QListWidgetItem(val) for val in values]
result=[self.viewB.addItem(item) for item in items]
elements={'Animals':['Bison','Panther','Elephant'],'Birds':['Duck','Hawk','Pigeon'],'Fish':['Shark','Salmon','Piranha']}
window=Window()
sys.exit(app.exec_())
I suggest to use Model-View approach instead.
You'll have two models: KeysModel and ValuesModel inherited from QAbstractListModel or QStringListModel. Two views QTableView: KeysView and ValuesView. And one proxy model QSortFilterProxyModel ProxyModel which will help you to show values filtered by a key in ValuesView.
When an item in KeysView is selected just assign a new filter to ProxyModel and values in ValuesView will be changed.
On the other class QColumnView it can design hierarchy of data. Try read document it.
Using a single model for both views: QListView and QTableView:
import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}
class DataModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.modelDict={}
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 4
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
key=str(self.items[index.row()])
column=index.column()
if role==QtCore.Qt.ItemDataRole: return self.modelDict.get(str(index.data().toString()))
if role==QtCore.Qt.DisplayRole:
if column==0:
return key
else:
return self.modelDict.get(key).get(column)
def addItem(self, itemName=None, column=0):
totalItems=self.rowCount()+1
self.beginInsertRows(QtCore.QModelIndex(), totalItems, column)
if not itemName: itemName='Item %s'%self.rowCount()
self.items.append(itemName)
self.endInsertRows()
def buildItems(self):
for key in self.modelDict:
index=QtCore.QModelIndex()
self.addItem(key)
class ProxyTableModel(QtGui.QSortFilterProxyModel):
def __init__(self, parent=None):
super(ProxyTableModel, self).__init__(parent)
def headerData(self, column, orientation, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.TextAlignmentRole:
if orientation == QtCore.Qt.Horizontal:
return QtCore.QVariant(int(QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter))
return QtCore.QVariant(int(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter))
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation==QtCore.Qt.Horizontal:
if column==1:
return QtCore.QVariant("Species 1")
elif column==2:
return QtCore.QVariant("Species 2")
elif column==3:
return QtCore.QVariant("Species 3")
return QtCore.QVariant(int(column + 1))
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
self.dataModel=DataModel()
self.dataModel.modelDict=elements
self.dataModel.buildItems()
self.proxyModel=ProxyTableModel()
self.proxyModel.setFilterKeyColumn(0)
self.proxyModel.setSourceModel(self.dataModel)
self.viewA=QtGui.QListView()
self.viewA.setModel(self.dataModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QTableView()
self.viewB.setModel(self.proxyModel)
self.viewB.setColumnHidden(0,True)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self):
index=self.viewA.currentIndex()
key=self.dataModel.data(index, QtCore.Qt.DisplayRole)
value=self.dataModel.data(index, QtCore.Qt.ItemDataRole)
self.proxyModel.setFilterRegExp('%s'%key)
print 'onClick(): key: %s'%type('%s'%key)
window=Window()
sys.exit(app.exec_())
The code below creates QTableView with a single column. How to make the header column stretch along the entire width of the QTableView view?
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
def rowCount(self, parent=QtCore.QModelIndex()):
return 0
def columnCount(self, index=QtCore.QModelIndex()):
return 1
def headerData(self, column, orientation, role=QtCore.Qt.DisplayRole):
if role!=QtCore.Qt.DisplayRole: return QtCore.QVariant()
if orientation==QtCore.Qt.Horizontal: return QtCore.QVariant('Column Name')
class TableView(QtGui.QTableView):
def __init__(self):
super(TableView, self).__init__()
model=TableModel()
self.setModel(model)
self.show()
view=TableView()
sys.exit(app.exec_())
What you're looking for is the QHeaderView::setResizeMode function. I would recommend checking out the docs, but here's the code
self.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
or, if you want to only stretch the least header item:
self.horizontalHeader().setStretchLastSection(True)