Is there a way to make a Model View Table automatically open to show the whole table?

I have been working on this tutorial: Display tables in PyQt5, QTableView with conditional formatting, numpy and pandas
and in order to get the app to open up showing the whole table right away without having to resize it, I added window.resize(500,300) before window.show() at the end. However, I am wondering if this is the best way to do it. In particular, is there a way to get a QAbstractTableModel table to open showing the whole table regardless of size? I have searched the web for an example and tried adding a layout, but have had no success.
I appreciate any insight into how to do this - it seems like it should be possible, but I am not sure how to do it yet.

The following will do the trick –

    def resize_table_to_contents(self):
        vh = self.table.verticalHeader()
        hh = self.table.horizontalHeader()
        size = QtCore.QSize(hh.length(), vh.length())  # Get the length of the headers along each axis.
        size += QtCore.QSize(vh.size().width(), hh.size().height())  # Add on the lengths from the *other* header
        size += QtCore.QSize(20, 20)  # Extend further so scrollbars aren't shown.
        self.resize(size)

Note that it resizes the window since the tableview is constrained by the window it is in.

The first += line is needed since the vertical header actually adds a bit of width to the horizontal header (and vice versa) where they overlap at the square in the top. The hh.size() returns the current
visible dimensions not the size of the entire header, so we can only use it for the height on the horizontal, and width on the vertical.

The final adjustment is neccessary to push the window large enough that scrollbars aren’t triggered. If scrollbars are shown they cover part of the content. The values are arbitrary, but work.

1 Like

Thank you very much for this. It works fine. Just to make sure that I understand, I still have to resize the window using this new method (which belongs to the MainWindow class) just before I call window.show()?

How would I go about making the table fill the whole window when the window is resized? I’ve played around a bit with resizeEvents without success, and the QAbstractTableModel seems to work differently in terms of sizing and size policies.

Thank you very much for your help!

Yep that’s right. You should be able to call the resize method whenever you like – e.g. if you change the content of the table, you can re-update the window again (will need to wait til after the table as updated).

If the table is in a layout (on a QWidget) or set as the central widget (on a QMainWindow) the table should fill the available space automatically – so resizing the window, will also resize the table.

The key thing is that widgets are constrained by the window (or layout) they are in. Rather than the window resizing to fit its contents, the content fits the window. So you have to resize the outermost thing.

(This is probably worth making more explicit in the tutorials with some examples, since it can be counter-intuitive).

If the content is supposed to fit the window, then why doesn’t the Model Views Table expand when I expand the window? I tried adding a resize event incorporating the resize_table_to_contents method but then the main window wouldn’t resize at all.

If the window resize event is triggering the resize_table_to_contents then the window won’t be able to resize, as every time it tries it’s overruled by that method.

But the table should fill the window without that. Can you post a code snippet maybe?

Thank you for helping me with this. I had just added the resize_table_to_contents method to the final set of code which used Pandas.

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
import pandas as pd

class TableModel(QtCore.QAbstractTableModel):

def __init__(self, data):
    super(TableModel, self).__init__()
    self._data = data

def data(self, index, role):
    if role == Qt.DisplayRole:
        value = self._data.iloc[index.row(), index.column()]
        return str(value)

def rowCount(self, index):
    return self._data.shape[0]

def columnCount(self, index):
    return self._data.shape[1]

def headerData(self, section, orientation, role):
    # section is the index of the column/row.
    if role == Qt.DisplayRole:
        if orientation == Qt.Horizontal:
            return str(self._data.columns[section])

        if orientation == Qt.Vertical:
            return str(self._data.index[section])

class MainWindow(QtWidgets.QMainWindow):

def __init__(self):
    super().__init__()

    self.table = QtWidgets.QTableView()

    data = pd.DataFrame([
      [1, 9, 2],
      [1, 0, -1],
      [3, 5, 2],
      [3, 3, 2],
      [5, 8, 9],
    ], columns = ['A', 'B', 'C'], index=['Row 1', 'Row 2', 'Row 3', 'Row 4', 'Row 5'])

    self.model = TableModel(data)
    self.table.setModel(self.model)

    self.setCentralWidget(self.table)

def resize_table_to_contents(self): 
    vh = self.table.verticalHeader()
    hh = self.table.horizontalHeader()
    size = QtCore.QSize(hh.length(), vh.length())  # Get the length of the headers along each axis.
    size += QtCore.QSize(vh.size().width(), hh.size().height())  # Add on the lengths from the *other* header
    size += QtCore.QSize(20, 20)  # Extend further so scrollbars aren't shown.
    self.resize(size)

app=QtWidgets.QApplication(sys.argv)
window=MainWindow()
window.resize_table_to_contents()
window.show()
app.exec_()

Thank you for your help.