1

I am working on a fairly simply PyQt program which basically is just a QTableWidget full of items. My goal is for the width and height of the items to automatically resize based on the size of the parent QTableWidget. For example, if I resize the window smaller, the items width and height should decrease in size but there should remain the same number of items and the items should still completely fill the parent QTableWidget. As you see, I am currently using setColumnWidth and setRowHeight to manually set the width and height.

I have tried the suggestions in the following Stack Overflow questions, as well as many other questions and websites, none of which do what I am attemping to do.

1. How to make qtablewidgets columns assume the maximum space

2. pyqt how to maximize the column width in a tableview

Here is the code I am using currently:

from PyQt4 import QtGui, QtCore
import PyQt4.Qt

class Window(QtGui.QWidget):
    def __init__(self, rows, columns):
        super(Window, self).__init__()
        self.setWindowState(QtCore.Qt.WindowMaximized)
        self.table = QtGui.QTableWidget(rows, columns, self)
        self.table.verticalHeader().setVisible(False)
        self.table.horizontalHeader().setVisible(False)

        # this is what I am currently using to set the row and column size
        for x in range(columns):
            self.table.setColumnWidth(x, 13)
        for x in range(rows):
            self.table.setRowHeight(x, 13)
        for row in range(rows):
            for column in range(columns):
                item = QtGui.QTableWidgetItem()
                self.table.setItem(row, column, item)

        layout = QtGui.QGridLayout(self)
        layout.addWidget(self.table, 0, 0, 1, 6)

        self.show()


def main():
    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window(54, 96)
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

I appoligize for the length of this question, but I wanted to make my question very clear. Thank you all in advance for your help!

Community
  • 1
  • 1
Mark Skelton
  • 3,663
  • 4
  • 27
  • 47

1 Answers1

1

You can do this using a QItemDelegate and overriding the sizeHint method. Then override the resizeEvent and showEvent methods of you main widget to update the sizes of each cell whenever the widget is resized.

import sys
from PyQt4 import QtGui, QtCore


class MyDelegate(QtGui.QItemDelegate):

    def __init__(self, parent, table):
        super(MyDelegate, self).__init__(parent)
        self.table = table

    def sizeHint(self, option, index):
        # Get full viewport size
        table_size = self.table.viewport().size()
        gw = 1  # Grid line width
        rows = self.table.rowCount() or 1
        cols = self.table.columnCount() or 1
        width = (table_size.width() - (gw * (cols - 1))) / cols
        height = (table_size.height() -  (gw * (rows - 1))) / rows
        return QtCore.QSize(width, height)


class Window(QtGui.QWidget):
    def __init__(self, rows, columns):
        super(Window, self).__init__()
        self.lay = QtGui.QVBoxLayout()
        self.setLayout(self.lay)
        self.table = QtGui.QTableWidget(rows, columns, self)
        self.table.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.lay.addWidget(self.table)
        self.delegate = MyDelegate(self, self.table)
        self.table.setItemDelegate(self.delegate)

    def showEvent(self, event):
        super(Window, self).showEvent(event)
        self.resizeTable()

    def resizeTable(self):
        self.table.resizeRowsToContents()
        self.table.resizeColumnsToContents()

    def resizeEvent(self, event):
        super(Window, self).resizeEvent(event)
        self.resizeTable()
Brendan Abel
  • 35,343
  • 14
  • 88
  • 118
  • I tired your code and it fills the table completely. However it does not stay within the bounds of the window. Is there a way that I can make it so it fills the window without going beyond the window? – Mark Skelton Feb 28 '16 at 13:26
  • What do you mean by "going beyond the window"? Can you post a screenshot? – Brendan Abel Feb 28 '16 at 19:21
  • [Here](http://i.stack.imgur.com/DTGAn.png) is the screenshot. I have more columns and rows than those that show up on the screen. – Mark Skelton Feb 29 '16 at 11:07
  • I think you'll have to account for the grid lines as well. They're probably only like 1-2 pixels. I updated the answer – Brendan Abel Feb 29 '16 at 16:49
  • Let me clarify, I have 50 rows and 50 columns. Only 30 rows and 46 columns show up, even after I retried your code. – Mark Skelton Feb 29 '16 at 16:52
  • It's the row and column headers. They also have sizeHints. You can do the same thing, create a delegate (make sure to create a new one, don't reuse the one from the table) and assign one to each HeaderView -- `table.horizontalHeader().setItemDelegate(delegate)`, but the row and column numbers are going to be scrunched together and overlapping. Or you can just hide the row and column headers if you don't need them. – Brendan Abel Feb 29 '16 at 17:28
  • Sorry it still doesn't work. When I tried hiding the headers that did nothing. When I tried setting the delegate for the header it gives me this error: `TypeError: QAbstractItemView.setItemDelegate(QAbstractItemDelegate): argument 1 has unexpected type 'PyQt4.QtCore.pyqtWrapperType'` – Mark Skelton Feb 29 '16 at 17:38