Resize Vertical Header of QTableView in PyQt4?
Asked Answered
D

3

7

enter image description here

I need to reduce the size of first column(the column with vertical headers)

How can I resize a vertical header of QTableView in PyQt4?

I have very large headers and small GUI block to show this table so, please help me!

I am able to resize all the columns but not able to figure out resizing the vertical headers?

I have tried many things like:

self.tableView.setColumnWidth(0, 30)  // only able to change the data columns in table not headers

self.tableView.verticalHeader().setResizeMode(QHeaderView.Interactive)  //Able to change the height of headers but not width of them

I want to make the headers which can be resized by the user and has no dependencies on any other parameters of the project like window size, size of other columns....

Can someone help me with this?

Debbydebee answered 22/12, 2016 at 20:39 Comment(3)
Have you considered using Qt Designer?Remsen
I am sorry I am new to this can you elaborate? How can I use Qt Designer?Debbydebee
Qt Designer allows you to create UIs using drag and drop elements. It is a lot easier to use than manually coding the UI and it cleans up your code. If this is for a big project, I would thoroughly recommend considering switching to Qt Designer - albeit some things still have to be coded explicitly, and ironically this is one of themRemsen
Z
8

You can limit the size of the vertical header using setMaximWidth, and use setTextElideMode to adjust how the text is cropped.

However, there is no built-in method for making the vertical header width resizable by the user. So as a work-around, you could use the resize-event to adjust the width of the vertical header to a percentage of the total width. That way, resizing the window will also change the width of the vertical header.

Here is a demo script that implements all of that:

import sys
from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self, rows, columns):
        super(Window, self).__init__()
        self.table = QtGui.QTableView(self)
        self.table.installEventFilter(self)
        self.table.verticalHeader().setTextElideMode(QtCore.Qt.ElideRight)
        model =  QtGui.QStandardItemModel(rows, columns, self.table)
        for row in range(rows):
            item = QtGui.QStandardItem('FOO_BAR_123_AB_CD_%s' % row)
            model.setVerticalHeaderItem(row, item)
            for column in range(columns):
                item = QtGui.QStandardItem('(%d, %d)' % (row, column))
                item.setTextAlignment(QtCore.Qt.AlignCenter)
                model.setItem(row, column, item)
        self.table.setModel(model)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.table)

    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.Resize and source is self.table:
            source.verticalHeader().setMaximumWidth(source.width() / 4)
        return super(Window, self).eventFilter(source, event)

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window(15, 5)
    window.setGeometry(600, 100, 400, 300)
    window.show()
    sys.exit(app.exec_())

UPDATE:

I had a go at writing a custom header class that implements user resizing of the vertical header width. It almost works, but I cannot find a way to update the view properly whilst dragging with the mouse. Anyway, here is a demo of what I have so far in case anyone can see how to make it work:

import sys
from PyQt4 import QtCore, QtGui

class HeaderView(QtGui.QHeaderView):
    def __init__(self, table):
        super(HeaderView, self).__init__(QtCore.Qt.Horizontal, table)
        self.setClickable(True)
        self.setHighlightSections(True)
        self.setResizeMode(QtGui.QHeaderView.Interactive)
        self._vheader = table.verticalHeader()
        self._resizing = False
        self._start_position = -1
        self._start_width = -1

    def mouseMoveEvent(self, event):
        if self._resizing:
            width = event.x() - self._start_position + self._start_width
            if width > 0:
                self._vheader.setFixedWidth(width)
                # TODO: find a proper replacement for this
                self.geometriesChanged.emit()
        else:
            super(HeaderView, self).mouseMoveEvent(event)
            if 0 <= event.x() <= 3:
                if not self.testAttribute(QtCore.Qt.WA_SetCursor):
                    self.setCursor(QtCore.Qt.SplitHCursor)

    def mousePressEvent(self, event):
        if not self._resizing and event.button() == QtCore.Qt.LeftButton:
            if 0 <= event.x() <= 3:
                self._start_position = event.x()
                self._start_width = self._vheader.width()
                self._resizing = True
                return
        super(HeaderView, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        self._resizing = False
        super(HeaderView, self).mouseReleaseEvent(event)

class Window(QtGui.QWidget):
    def __init__(self, rows, columns):
        super(Window, self).__init__()
        self.table = QtGui.QTableView(self)
        self.table.setHorizontalHeader(HeaderView(self.table))
        self.table.verticalHeader().setTextElideMode(QtCore.Qt.ElideRight)
        model =  QtGui.QStandardItemModel(rows, columns, self.table)
        for row in range(rows):
            item = QtGui.QStandardItem('FOO_BAR_123_AB_CD_%s' % row)
            item.setToolTip(item.text())
            model.setVerticalHeaderItem(row, item)
            for column in range(columns):
                item = QtGui.QStandardItem('(%d, %d)' % (row, column))
                item.setTextAlignment(QtCore.Qt.AlignCenter)
                model.setItem(row, column, item)
        self.table.setModel(model)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.table)

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window(15, 5)
    window.setGeometry(600, 100, 400, 300)
    window.show()
    sys.exit(app.exec_())
Zipah answered 10/1, 2017 at 18:37 Comment(6)
thanks for the answer! I have been thinking of this alternative about having a fixed maxWidth, but that is not exactly what I have been looking for. So you are saying that there is no way a user can resize this header on his will.Debbydebee
This is a big deal because some of header just have one character and some files have like some 1000 characters, So I do not want fixing the size with maxWidth,Debbydebee
@VenkataNarsiReddyVaddula. The maximum-width is not fixed. It is adjusted in the resize-event when the window is resized. I used a percentage of the table width, but you can use whatever method you like to set it.Zipah
Yeah but the Window size of the project is fixed here. I will look for a couple of days for another alternative, if not then I will accept and award the answer.Debbydebee
@VenkataNarsiReddyVaddula. Okay. I think you should make it clear in your question that you want to allow the user to resize the vertical header width. I think that may still be possible, but it would require a different kind of solution (probably a custom header class).Zipah
OMG! Aren't you the best! This works almost perfectly!Debbydebee
B
2

Ekhumoro's solution works nearly perfect. The choppy drag behavior seen during resize has to do with the coordinate space changing while the resize happens.

To fix this choppy behavior and have a smooth resize you should use the global coordinate space rather than the local coordinate for the headerView. To do this simply replace event.x() with event.globalX()

        #width = event.x() - self._start_position + self._start_width
        width = event.globalX() - self._start_position + self._start_width

            #self._start_position = event.x()
            self._start_position = event.globalX()

I also change the geometried Changed signal to be emited from the vertical header and not the horizontal header. Since it was the vertical header that actually changed size. However in my test case I couldn't tell that it mattered much but conceptually it seem correct.

            #self.geometriesChanged.emit()
            self._vheader.geometriesChanged.emit()
Bivalve answered 18/9, 2017 at 15:37 Comment(0)
R
-1

PyQt tends to have some poor documentation, but this page gives all possible information about the QTableView class.

I am not sure what your specific problem is, however you could try:

self.tableView.horizontalHeader().setSectionResizeMode(3)

The documentation of .setSectionResize()

Alternatively, if you want to resize each header to a set size, try:

self.tableView.horizontalHeader().resizeSection(0, pixelSize1)
self.tableView.horizontalHeader().resizeSection(1, pixelSize2)
self.tableView.horizontalHeader().resizeSection(2, pixelSize3)
...

The documentation of .resizeSection()

Remsen answered 22/12, 2016 at 21:4 Comment(1)
I have uploaded an Image which can help you better understand the problem. Also QHeaderView Does not have setSectionResizeMode(), I have tried setResizeMode()Debbydebee

© 2022 - 2024 — McMap. All rights reserved.