How to Resize a Window to Fit a QTableView

Automatically size your window to show the full table, and keep the table filling the window when resized
Heads up! You've already completed this tutorial.

I have a QTableView with a QAbstractTableModel, and when the app opens the table is clipped by the window size. Is there a way to make the window automatically open large enough to show the whole table? And once it's open, how do I make the table fill the window when the user resizes it?

When you display a table using QTableView in a PyQt6 application, the default window size might not be large enough to show all the rows and columns. You end up with scrollbars, even when there's plenty of screen space available. In this article, we'll look at how to resize the window to fit the table on startup, and how to make sure the table always fills the available window space when the user drags to resize.

Setting Up the Example

Let's start with a working example that uses a Pandas DataFrame displayed in a QTableView. This is based on the QTableView and Model/View tutorial — if you haven't worked through that yet, it's a good place to start.

Here's our starting point:

python
import sys

from PyQt6 import QtCore, QtWidgets
from PyQt6.QtCore import Qt
import pandas as pd


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

    def data(self, index, role):
        if role == Qt.ItemDataRole.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):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                return str(self._data.columns[section])
            if orientation == Qt.Orientation.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)


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

If you run this, you'll likely see a window that's smaller than the table content, with scrollbars showing. That's because the window has a default size and the table doesn't influence it.

Resizing the Window to Fit the Table

One approach is to call window.resize(500, 300) with hardcoded values before showing the window. That works, but it means you have to guess at the right size — and if the data changes, the size won't adapt.

A better approach is to calculate the size the window needs to be based on the actual table contents. We can do this by reading the dimensions from the table's headers.

Add this method to the MainWindow class:

python
def resize_to_fit_table(self):
    vh = self.table.verticalHeader()
    hh = self.table.horizontalHeader()

    # Start with the total length of all columns and all rows.
    size = QtCore.QSize(hh.length(), vh.length())

    # The headers overlap in the top-left corner. We need to add the
    # width contributed by the vertical header, and the height
    # contributed by the horizontal header.
    size += QtCore.QSize(vh.size().width(), hh.size().height())

    # Add a small margin so scrollbars aren't triggered.
    size += QtCore.QSize(20, 20)

    self.resize(size)

Here's what each step does:

  • hh.length() gives the total width of all columns combined. vh.length() gives the total height of all rows. Together these tell us how much space the actual cell content needs.
  • The vertical header (the row labels on the left) adds some width, and the horizontal header (the column labels on top) adds some height. We account for that with the second +=.
  • The final += QSize(20, 20) adds a small buffer. Without it, the window can end up just small enough to trigger scrollbars, which then cover part of the content.

This method resizes the window, because the table view is constrained by the window it sits in. Widgets in Qt don't push their parent to grow — the parent determines how much space is available, and the child fills it.

Call this method just before window.show():

python
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.resize_to_fit_table()
window.show()
app.exec()

Now the window will open at exactly the right size to show the full table.

The Table Already Fills the Window on Resize

You might wonder whether you need to do anything special to make the table expand when the user manually resizes the window. The good news: if the QTableView is set as the central widget of a QMainWindow (using setCentralWidget), it will automatically fill the available space. Dragging the window larger will make the table larger too. No extra work needed.

This also works if your table is inside a layout on a plain QWidget. Layouts in Qt manage the size and position of their child widgets, so the table will stretch to fill whatever space the layout gives it.

A Common Pitfall: Don't Resize in the Resize Event

It might seem logical to call resize_to_fit_table from a resizeEvent, so the window constantly adapts to the table. But this creates a conflict: every time the user tries to resize the window, the resizeEvent fires and immediately resizes the window back to fit the table. The result is that the window becomes impossible to resize manually — it snaps back to the calculated size on every attempt.

The resize_to_fit_table method is best used as a one-time call at startup, or whenever you update the table's data and want the window to re-adapt.

Complete Working Example

Here's the full example with the auto-sizing method included:

python
import sys

from PyQt6 import QtCore, QtWidgets
from PyQt6.QtCore import Qt
import pandas as pd


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

    def data(self, index, role):
        if role == Qt.ItemDataRole.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):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                return str(self._data.columns[section])
            if orientation == Qt.Orientation.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_to_fit_table(self):
        """Resize the window to fit the full table contents."""
        vh = self.table.verticalHeader()
        hh = self.table.horizontalHeader()

        # Total width of all columns, total height of all rows.
        size = QtCore.QSize(hh.length(), vh.length())

        # Add the width of the vertical header and height of the
        # horizontal header (they overlap in the top-left corner).
        size += QtCore.QSize(vh.size().width(), hh.size().height())

        # Small margin to prevent scrollbars from appearing.
        size += QtCore.QSize(20, 20)

        self.resize(size)


app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.resize_to_fit_table()
window.show()
app.exec()

Run this, and the window will open sized perfectly to show the entire table. You can then freely resize the window with the mouse — the table will expand or shrink to fill the available space, because it's set as the central widget.

If you later update the data in the model and want the window to re-adapt, just call window.resize_to_fit_table() again after the model has been updated.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Create GUI Applications with Python & Qt6 by Martin Fitzpatrick

(PyQt6 Edition) The hands-on guide to making apps with Python — Over 15,000 copies sold!

More info Get the book

Martin Fitzpatrick

How to Resize a Window to Fit a QTableView was written by Martin Fitzpatrick.

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.