Qt : Fit width of TableView to width of content
Solution 1
There are a couple of things about your width calcualtion that are wrong.
Firstly, you attempt to use QtGui.QStyle.PM_ScrollBarExtent
to get the width of the vertical scrollbar - but that is a constant, not a property. Instead, you need to use QStyle.pixelMetric:
tableView.style().pixelMetric(QtGui.QStyle.PM_ScrollBarExtent)
Secondly, you do not take into account the width of the tableview frame, which can be calculated like this:
tableView.frameWidth() * 2
Putting these values together with the dimensions of the headers, the final calculation should be:
vwidth = tableView.verticalHeader().width()
hwidth = tableView.horizontalHeader().length()
swidth = tableView.style().pixelMetric(QtGui.QStyle.PM_ScrollBarExtent)
fwidth = tableView.frameWidth() * 2
tableView.setFixedWidth(vwidth + hwidth + swidth + fwidth)
This should leave exactly the space needed for the vertical scrollbar.
PS:
Since you're setting a fixed width for the tableview, you could also get rid of the horizontal scrollbar, which is redundant:
tableView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
Solution 2
In C++ you can do something like this:
tableview->resizeColumnsToContents();
QHeaderView* header = tableview->horizontalHeader();
header->setStretchLastSection(true);
tablewview->setHorizontalHeader(header);
Solution 3
Starting with Qt 5.2 you can use the following:
view->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
or
view->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
Ilyes Ferchiou
I'm a mechanical engineer, a graphic designer and a website designer. I work as a freelancer.
Updated on July 19, 2022Comments
-
Ilyes Ferchiou almost 2 years
I have a window that contains a
QTableView
which columns are adjusted to content and are fixed in width. TheQTableView
is nested within aQWidget
that in turn is nested within aQScrollArea
that in turn is nested within a tabbedQMdiArea
which is thecentralWidget
of aQMainWindow
.When the
QScrollArea
is shown, theQTableView
has extra space to the right of the last column that I want to be removed :I want the
QTableView
to fit the exact width of the columns (i.e. no extra space after the rightmost column).I tried to use
tableView.setFixedWidth(desired_width)
but then the only way it could work was to iterate over all the columns and get their widths and sum them up together and add theverticalHeader
width and the scroll-bars width and pass it as thedesired_width
.It does work this way but it seems to be very complex for such an obvious requirement : I think a lot of program developers want their tables' width to fit the columns' width and this is what makes me wonder that maybe there is a method that does that automatically without the extra calculations and that I'm unaware of.
So my question is : is there a simpler way to achieve the same result ?
Here is my code for reference :
The code for the
t_main
module responsible for creating theQMainWindow
:import sys import t_wdw from PySide import QtGui class Main_Window(QtGui.QMainWindow): def __init__(self): super(Main_Window,self).__init__() self.initUI() def initUI(self): self.statusBar() # Defines QActions for menu self.new_window=QtGui.QAction("&Window alpha",self) self.new_window.triggered.connect(self.open_window) # Creates the menu self.menu_bar=self.menuBar() self.menu1=self.menu_bar.addMenu('&Menu 1') self.menu1.addAction(self.new_window) # Creates a QMdiArea to manage all windows. self.wmanager=QtGui.QMdiArea() self.wmanager.setViewMode(QtGui.QMdiArea.TabbedView) self.setCentralWidget(self.wmanager) self.showMaximized() # Opens the new window that holds the QTableView def open_window(self): t_wdw.launch_window() t_wdw.window_alpha=self.wmanager.addSubWindow(t_wdw.window) t_wdw.window_alpha.show() def main(): app=QtGui.QApplication(sys.argv) main_wdw=Main_Window() sys.exit(app.exec_()) if __name__=="__main__": main()
The code for
t_wdw
module that is responsible for creating theSubWindow
with theQTableView
.from PySide import QtGui from PySide import QtCore def launch_window(): global window # Creates a new window window=QtGui.QScrollArea() window1=QtGui.QWidget() row=0 data=[["VH"+str(row+i),1,2,3] for i in range(20)] headers=["HH1","HH2","HH3"] # Creates a table view with columns resized to fit the content. model=my_table(data,headers) tableView=QtGui.QTableView() tableView.setModel(model) tableView.resizeColumnsToContents() # Fixes the width of columns and the height of rows. tableView.horizontalHeader().setResizeMode(QtGui.QHeaderView.Fixed) tableView.verticalHeader().setResizeMode(QtGui.QHeaderView.Fixed) """ Here is the solution I resorted to to fix the tableView width equal to its content and that I want to make simpler """ vhwidth=tableView.verticalHeader().width() desired_width=QtGui.QStyle.PM_ScrollBarExtent*2+vhwidth+1 for i in range(len(headers)): desired_width+=tableView.columnWidth(i) tableView.setFixedWidth(desired_width) """ Sets the layouts and widgets using a QHBoxLayout because I want the QTableView to be centered on the window and more widgets and layouts are to be added later. """ window1.main_layout=QtGui.QHBoxLayout() window1.main_layout.addStretch(0) window1.main_layout.addWidget(tableView) window1.main_layout.addStretch(0) window.setLayout(window1.main_layout) window.setWidget(window1) class my_table(QtCore.QAbstractTableModel): def __init__(self,data,headers,parent=None): QtCore.QAbstractTableModel.__init__(self,parent) self.__data=data self.__headers=headers def rowCount(self,parent): return len(self.__data) def columnCount(self,parent): return len(self.__headers) def data(self, index, role): if role == QtCore.Qt.DisplayRole: row = index.row() column = index.column() return self.__data[row][column+1] def headerData(self,section,orientation,role): if role == QtCore.Qt.DisplayRole: if orientation == QtCore.Qt.Horizontal: return self.__headers[section] if orientation == QtCore.Qt.Vertical: return self.__data[section][0]
An extra question for those who read the code : Why do I need to multiply
PM_ScrollBarExtent
by 2 to get the correct result ?P.S : I'm using PySide 1.2.1 but answers in PyQt or C++ are fine.
-
Ilyes Ferchiou over 10 yearsThank you for your answer but
setStretchLastSection
just stretches the last column to fill the remaining space in thetableView
while I'm trying to do the opposite which is to shrink thetableView
to the width of the columns. -
Ilyes Ferchiou over 10 yearsThank you for your answer, I eventually ended up by using
tableView.horizontalHeader().length()
andtableView.verticalHeader().width()
as I said in the comments and I forgot to say but I replacedQtGui.QStyle.PM_ScrollBarExtent
bytableView.verticalScrollBar().sizeHint().width()
. Now I'm not sure which one is more correct,sizeHint()
or your method ? But I was always still adding 1 pixel to get the appropriate result and I guess now, thanks to your answer, that this pixel was accounting fortableView.frameWidth() * 2
. So sad there isn't a simpler method. Thank you again. -
eric over 9 years@ekhumoro This is really helpful. Strangely, I'm still left needing to add 6 pixels to get an exact fit. I thought this might be due to pixels added by lines between columns, but it is 6 pixels regardless of number of columns displayed. For now I just add it as a fudge factor, but prefer not to...
-
ekhumoro over 9 years@neuronet. Hard to say without seeing actual code. Please start a new question, and include a minimal working example that demonstrates the problem. You should probably say what platform you're on, as well.
-
eric over 9 years@ekhumoro: Just posted: stackoverflow.com/questions/26960006/…
-
goug over 5 yearsThese made no difference for me.