RealRK
RealRK

Reputation: 317

Change QTableView widgets horizontal size based on data

I've been trying to get 2 QTableView widgets to resize with each other in PyQt5. The widgets are in a QComboBox and the layout is set to grid. I tried the resizeColumnToContents method but that just makes the QTableView's columns smaller in width.

How it is currently:

how it is

How it should be:

how it should be

QTableView 1 can have various columns or just one. I want the QTableView 2 to expand in layout so that it covers the entire space and QTableView 1 to be just the one column being displayed. Is there a way to do this? I tried using a splitter and dynamically changing the setstretchfactor, but am not able to implement it. Some clues or hints?

Upvotes: 0

Views: 441

Answers (2)

musicamante
musicamante

Reputation: 48260

There are two possible solutions.

If you want to use the QSplitter, allowing the user the possibility to resize columns, you could resize the contents after the window has resized. Since tables and splitters might need some time to adjust their sizes, this has to happen after a slight delay (an "event loop" cycle).

class Test(QtWidgets.QMainWindow):
    # ...
    def delaySplitterResize(self):
        if not self.model1.columnCount():
            return
        total = self.table1.width() + self.table2.width()
        leftWidth = self.table1.frameWidth() * 2 + self.table1.contentsMargins().left() * 2
        for s in range(self.model1.columnCount()):
            leftWidth += self.table1.horizontalHeader().sectionSize(s)
        self.splitter.setSizes([leftWidth, total - leftWidth])

    def resizeEvent(self, event):
        super().resizeEvent(event)
        QtCore.QTimer.singleShot(0, self.delaySplitterResize)

Another possibility is to subclass the table and update its sizeHint each time the model contents change. This works by calling updateGeometry() (which invalidates the sizeHint and tells the parent[s] to compute again sizes) each time the model size changes and the section are resized.

class MinimumSizeTable(QtWidgets.QTableView):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # an explicit minimum size is recommended
        self.setMinimumWidth(self.horizontalHeader().defaultSectionSize())
        # ensure that the widget tries to occupy only the width provided
        # by the sizeHint
        self.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
        # section resizing requires some time to "update" the section hints,
        # so we need to delay the call to updateGeometry
        self.horizontalHeader().sectionResized.connect(lambda: QtCore.QTimer.singleShot(0, self.updateGeometry))
        self.verticalHeader().sectionResized.connect(lambda: QtCore.QTimer.singleShot(0, self.updateGeometry))

    def setModel(self, model):
        if self.model():
            self.model().columnsInserted.disconnect(self.updateGeometry)
            self.model().columnsRemoved.disconnect(self.updateGeometry)
        super().setModel(model)
        if self.model():
            self.model().columnsInserted.connect(self.updateGeometry)
            self.model().columnsRemoved.connect(self.updateGeometry)
        self.updateGeometry()

    def sizeHint(self):
        hint = super().sizeHint()
        if not self.model() or not self.model().columnCount():
            hint.setWidth(self.horizontalHeader().defaultSectionSize())
        else:
            width = self.frameWidth() * 2 + self.contentsMargins().left() * 2
            for s in range(self.model().columnCount()):
                width += self.horizontalHeader().sectionSize(s)
            hint.setWidth(width)
        return hint

To be able to use this class in your UI you'll need to promote the table in Designer:

  • Right click on the table and select "Promote to"
  • Type the subclass name in the "Promoted class name" field
  • Type the python file that contains the subclass, without the extension (for example "mytable") in the "Header file" field
  • Click "Add", then "Promote", and save.

This approach can also be used with a QSplitter, but remember that, from the moment the splitter is manually resized, it will always try to keep proportional sizes based on the new position.

Upvotes: 1

Erick
Erick

Reputation: 314

You may want to use: heather = table.horizontalHeader for each column (col) in the table: header.setSectionResizemode(ncol, QHeadedrView.resizeToContents) #This will limit the width of the column. If you want a column to fill all of the available space use "QHeaderView.Stretch" Besides, you may use a QHBoxlayout and perhaps relating the width of both tables.

Upvotes: 0

Related Questions