<div dir="ltr">Il giorno dom 20 mar 2022 alle ore 20:23 Matej Brezović <<a href="mailto:matey.brezovic@gmail.com">matey.brezovic@gmail.com</a>> ha scritto:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div style="font-family:arial,sans-serif;font-size:small;color:rgb(0,0,0)">Yes, seems like you're right. If I call setOffset() after calling show() on my window, the offset is visible but disappears as soon as I try to resize the window.</div><div style="font-family:arial,sans-serif;font-size:small;color:rgb(0,0,0)">Calling it after resizeEvent or paintEvent doesn't seems to work either, and if it did it would probably be inefficient.</div></div></blockquote><div><br></div><div>Calling it in the resizeEvent is not inefficient, and it's what many widgets actually do (but you *must* remember to call the base implementation first).<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div style="font-family:arial,sans-serif;font-size:small;color:rgb(0,0,0)"> I don't really know why does that function even exist if it doesn't seems to have an effect if the view is resizable.</div></div></blockquote><div><br></div><div>I believe you misinterpreted its purpose: that function is required by views, which set the offsets whenever their relative scroll bars change values.<br></div><div>Headers are not part of the items, nor the scrollarea viewport: they are direct child widgets of the view, their position is always fixed and based on the top left (or right, for RTL languages) corner, translated by the width or height of the opposite header; setting the offset allows the header to "scroll" its contents.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div style="font-family:arial,sans-serif;font-size:small;color:rgb(0,0,0)">And yes, my intention was to simply add some padding, just a few pixels, on the top of the first row, so that the table view would be slightly separated from the header view, but it seems I will have to give up on that idea.<br clear="all"></div></div></blockquote></div><div><br></div><div>I did some testing, but, as I was afraid, it's almost impossible or, at least, extremely difficult.</div><div><br></div><div>Even overriding the updateGeometries and calling setViewportMargins() won't be enough, as it would create further issues:</div><div>- the viewport margins are used to compute the span of scroll bars, and their value is used to know how much the viewport is scrolled (so the last row or column could become partially or even completely invisible);</div><div>- painting is always restricted to the widget rectangle, and adding a margin would only *translate* the origin point of the viewport: while the view would show a proper margin above the first row, scrolling would result in keeping that margin (so you will *always* have a blank margin on top);</div><div><br></div><div>The only way I could think of would be to completely override *lots* of functions, with the most difficult ones being those related to the scroll bars.</div><div><br></div><div>A *dirty* hack could be to use a model with a "ghost" row and do something similar to the frozen column example ( <a href="https://doc.qt.io/qt-5/qtwidgets-itemviews-frozencolumn-example.html">https://doc.qt.io/qt-5/qtwidgets-itemviews-frozencolumn-example.html</a> ): create a basic QWidget that is a child of the table view, ensure that it uses the same palette Base role as backgroundRole and that autoFillBackground is set, then setSectionResizeMode(0, QHeaderView.Fixed) anytime the view calls updateGeometries. Obviously, this has a lot of drawbacks, especially if the model is expected to support sorting.</div><div><br></div><div>Here is a basic example of the above:</div><div><br></div><div><span style="font-family:monospace">class Model(QtCore.QAbstractTableModel):<br>    def __init__(self, parent: Optional[QWidget] = None) -> None:<br>        super(Model, self).__init__(parent)<br>        self.__data = []<br>        for i in range(10):<br>            row = [i, 1, 2, 3, 4, 5, 6, 7]<br>            self.__data.append(row)<br><br>    def flags(self, index):<br>        if index.row() == 0:<br>            return QtCore.Qt.NoItemFlags<br>        return super().flags(index)<br><br>    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):<br>        if orientation == QtCore.Qt.Vertical:<br>            section -= 1<br>            if section < 0 and role == QtCore.Qt.DisplayRole:<br>                return<br>        return super().headerData(section, orientation, role)<br><br>    def rowCount(self, index: Optional[QtCore.QModelIndex] = None) -> int:<br>        return len(self.__data) + 1<br><br>    def columnCount(self, index: Optional[QtCore.QModelIndex] = None) -> int:<br>        return len(self.__data[0])<br><br>    def data(self, index: QtCore.QModelIndex,<br>             role: QtCore.Qt.ItemDataRole = Qt.DisplayRole) -> Any:<br>        if index.row() and role in [Qt.DisplayRole, Qt.EditRole]:<br>            return self.__data[index.row() - 1][index.column()]<br>        return None<br><br><br>class MarginTableView(QTableView):<br>    _margin = 0<br>    def __init__(self, *args, **kwargs):<br>        super().__init__(*args, **kwargs)<br>        self.marginWidget = QWidget(self)<br>        self.marginWidget.setBackgroundRole(QPalette.Base)<br>        self.marginWidget.setAutoFillBackground(True)<br>        self.verticalScrollBar().valueChanged.connect(self.updateMargin)<br><br>    @pyqtProperty(int)<br>    def margin(self):<br>        return self._margin<br><br>    @margin.setter<br>    def margin(self, margin):<br>        margin = max(0, margin)<br>        if self._margin != margin:<br>            self._margin = margin<br>            if self.isVisible():<br>                self.updateGeometries()<br><br>    def updateGeometries(self):<br>        super().updateGeometries()<br>        self.verticalHeader().setSectionResizeMode(0, QHeaderView.Fixed)<br>        self.verticalHeader().resizeSection(0, self.margin)<br>        self.updateMargin()<br><br>    def updateMargin(self):<br>        self.marginWidget.setGeometry(<br>            self.horizontalHeader().x(), <br>            self.verticalHeader().y(), <br>            self.viewport().width(), <br>            max(0, self.margin - 1 - self.verticalHeader().offset())<br>        )<br><br>    def resizeEvent(self, event):<br>        super().resizeEvent(event)<br>        self.updateMargin()<br><br><br>class MainWindow(QMainWindow):<br>    def __init__(self):<br>        super().__init__()<br>        self.resize(700, 700)<br><br>        self.central_widget = QWidget()<br>        self.central_widget_layout = QHBoxLayout(self.central_widget)<br><br>        view = MarginTableView(margin=50)<br>        model = Model()<br>        view.setModel(model)<br><br>        self.central_widget_layout.addWidget(view)<br>        self.setCentralWidget(self.central_widget)</span></div><div><br></div><div><br></div><div>It "works", but it's hacky and *ugly*. While I can understand your request, I'd just give up. As far as I know, solving this problem *easily* is impossible, and while technically doable, it would require an incredible amount of efforts that are just not worth something that would "just be nice to have".</div><div><br></div><div>Regards,</div><div>Maurizio<br></div><div><br></div>-- <br><div dir="ltr" class="gmail_signature">È difficile avere una convinzione precisa quando si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi<br><a href="http://www.jidesk.net" target="_blank">http://www.jidesk.net</a></div></div>