简体   繁体   English

在任何情况下如何拉伸 QTableWidget 最后一列

[英]How strech QTableWidget last column in any cases

How make the last column always strech to the remaining space?如何使最后一列始终延伸到剩余空间?

Here what I don't want to see这里是我不想看到的

Here the code I'm using:这是我正在使用的代码:

import sys
from PyQt5.QtWidgets import *

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(300, 300)
        self.show()

        self.tableWidget = QTableWidget()
        self.setCentralWidget(self.tableWidget)

        self.tableWidget.setColumnCount(2)
        self.tableWidget.setHorizontalHeaderLabels(["column 1", "column 2"])
        self.tableWidget.setStyleSheet("QHeaderView::section{Background-color:cyan;}")
        self.tableWidget.setSortingEnabled(True)

        nb = 25
        self.tableWidget.setRowCount(nb)
        for i in range(nb):
            self.tableWidget.setItem(i, 0, QTableWidgetItem("A"*(nb-i)))
            self.tableWidget.setItem(i, 1, QTableWidgetItem("B"*(nb-i)))
        
        self.tableWidget.resizeColumnsToContents()
        self.tableWidget.horizontalHeader().setStretchLastSection(True)

app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())

And here how to reproduce that unwanted behaviour: launch the prog, scroll right the horizontal scrollbar, then resize a bit horizontally the width of the window在这里如何重现这种不需要的行为:启动 prog,向右滚动水平滚动条,然后水平调整 window 的宽度

It seems like a small bug in the updateGeometries code, which doesn't update the header offset when the visible columns remain the same and the scroll mode is ScrollPerItem ;这似乎是updateGeometries代码中的一个小错误,当可见列保持不变且滚动模式为ScrollPerItem时,它不会更新 header 偏移量; this also happens for the vertical header, but it's usually less noticeable since rows are generally smaller.垂直 header 也会发生这种情况,但通常不太明显,因为行通常较小。
Note that the issue is also present even without resizing columns (or rows) to contents, the problem is always present whenever at least two sections are visible and don't fit the view, causing the scroll bar to show.请注意,即使没有将列(或行)的大小调整为内容,问题也存在,只要至少有两个部分可见并且不适合视图,就会出现问题,从而导致显示滚动条。

A possible solution is to subclass the table, override the resizeEvent() and call setOffsetToLastSection() whenever required.一种可能的解决方案是对表进行子类化,覆盖resizeEvent()并在需要时调用setOffsetToLastSection() Theoretically it should be done in the updateGeometries call, but considering that this only happens when resizing (and updateGeometries gets called very often) I doubt it would make a lot of sense.理论上它应该在updateGeometries调用中完成,但考虑到这只发生在调整大小时(并且updateGeometries经常被调用),我怀疑它是否有意义。
It's probably a good idea to do some more experiments and research to ensure that the checks on the scroll mode and scrollbars are enough, and eventually submit a bug .多做一些实验和研究,确保对滚动模式和滚动条的检查足够,最终提交一个 bug可能是个好主意。

class MyTable(QtWidgets.QTableWidget):
    def resizeEvent(self, event):
        checkHorizontal = (self.horizontalScrollMode() == self.ScrollPerItem and 
            self.horizontalScrollBar().maximum() >= 1 and 
            self.horizontalScrollBar().value() == self.horizontalScrollBar().maximum())
        checkVertical = (self.verticalScrollMode() == self.ScrollPerItem and 
            self.verticalScrollBar().maximum() >= 1 and 
            self.verticalScrollBar().value() == self.verticalScrollBar().maximum())
        super().resizeEvent(event)
        if checkHorizontal:
            self.horizontalHeader().setOffsetToLastSection()
        if checkVertical:
            self.verticalHeader().setOffsetToLastSection()

If you plan to use lots of tables and subclasses, and you want to always use this behavior, you could do a small "hack" by directly patching the QTableView class (since it's what QTableWidget inherits from);如果您计划使用大量表和子类,并且希望始终使用此行为,则可以通过直接修补 QTableView class (因为它是 QTableWidget 继承的)来做一个小“hack”; note that this must be done in as soon as the class' module is imported (so, at the very beginning of your main script, right after importing QtWidgets for the very first time):请注意,这必须在导入类模块后立即完成(因此,在脚本的最开始,在第一次导入 QtWidgets 之后):

# create a new reference for the default implementation
QTableView._resizeEvent = QTableView.resizeEvent
# the general fix
def resizeEventFix(self, event):
    checkHorizontal = (self.horizontalScrollMode() == self.ScrollPerItem and 
        self.horizontalScrollBar().maximum() >= 1 and 
        self.horizontalScrollBar().value() == self.horizontalScrollBar().maximum())
    checkVertical = (self.verticalScrollMode() == self.ScrollPerItem and 
        self.verticalScrollBar().maximum() >= 1 and 
        self.verticalScrollBar().value() == self.verticalScrollBar().maximum())
    # call the original implementation we renamed before
    QTableView._resizeEvent(self, event)
    if checkHorizontal:
        self.horizontalHeader().setOffsetToLastSection()
    if checkVertical:
        self.verticalHeader().setOffsetToLastSection()
# apply the fix
QTableView.resizeEvent = resizeEventFix

The above trick is actually very useful when using UIs created in Designer, as it allows to fix/patch standard Qt classes without the need to always promote them: as long as objects are created with public functions (calls that could be intercepted by PyQt, not objects Qt creates with private methods), those classes will always be "patched".当使用在 Designer 中创建的 UI 时,上述技巧实际上非常有用,因为它允许修复/修补标准 Qt 类,而无需总是提升它们:只要对象是使用公共函数创建的(可能被 PyQt 拦截的调用,不是对象 Qt 使用私有方法创建的),这些类将始终被“修补”。 In this case it can be also useful for the suggested testing, you can create a certain amount of possible tables in Designer and then easily test them against the above fix.在这种情况下,它对于建议的测试也很有用,您可以在 Designer 中创建一定数量的可能表,然后根据上述修复轻松测试它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM