如何调整 QMainWindow 的大小以适应具有 setVerticalHeaderLabels 的 QTableWidget
How to size QMainWindow to fit a QTableWidget that has setVerticalHeaderLabels
示例代码如下:
from PyQt5.QtWidgets import QApplication, QTableWidget, QTableWidgetItem, \
QMainWindow
from PyQt5.QtCore import QSize
import sys
DATA = {
f'col{i}': [f'{i * j}' for j in range(1, 10)] for i in range(1, 10)
}
class Table(QTableWidget):
def __init__(self, d):
m = len(d[next(iter(d))])
n = len(DATA)
super().__init__(m, n)
hor_headers = []
for n, (key, values) in enumerate(DATA.items()):
hor_headers.append(key)
for m, item in enumerate(values):
qtitem = QTableWidgetItem(item)
self.setItem(m, n, qtitem)
self.setHorizontalHeaderLabels(hor_headers)
# the sizeHint works fine if I disable this line
self.setVerticalHeaderLabels(f'row{i}' for i in range(1, m + 2))
self.resizeColumnsToContents()
self.resizeRowsToContents()
# improves the situation but still the window is smaller than the table
def sizeHint(self):
hh = self.horizontalHeader()
vh = self.verticalHeader()
fw = self.frameWidth() * 2
return QSize(
hh.length() + vh.width() + fw,
vh.length() + hh.height() + fw)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('<TITLE>')
table = Table(DATA)
self.setCentralWidget(table)
# did not work
# self.setFixedSize(self.layout().sizeHint())
def main(args):
app = QApplication(args)
main_win = MainWindow()
main_win.show()
raise SystemExit(app.exec_())
if __name__ == "__main__":
main(sys.argv)
结果如下:
第9行第9列没有显示,有滚动条
如果我注释掉 self.setVerticalHeaderLabels(f'row{i}' for i in range(1, m + 2))
行,那么它将起作用:
如何在具有垂直 header 标签的情况下将主要 window 完美地适合 table 小部件?
正如您在代码注释中看到的那样,我已经尝试了 python qt : automatically resizing main window to fit content 中建议的解决方案,但它们并没有起作用。
问题在于,当像项目视图这样的复杂小部件尚未“映射”时,其 children 的 实际 大小(header s 和滚动条)尚未更新。只有当视图最终显示并可能添加到布局时,它才会再次调整自身大小,以便使用 updateGeometries
.
正确调整其 children 的大小
这意味着,在此之前,每个 header 的大小基于其默认的基本内容(垂直 header 的行号)。
解决方案很简单:不要使用 header 大小,而是使用它们的提示,这些提示是使用将要显示的实际文本计算得出的:
def sizeHint(self):
hh = self.horizontalHeader()
vh = self.verticalHeader()
fw = self.frameWidth() * 2
return QSize(
hh.length() + vh.sizeHint().width() + fw,
vh.length() + hh.sizeHint().height() + fw)
示例代码如下:
from PyQt5.QtWidgets import QApplication, QTableWidget, QTableWidgetItem, \
QMainWindow
from PyQt5.QtCore import QSize
import sys
DATA = {
f'col{i}': [f'{i * j}' for j in range(1, 10)] for i in range(1, 10)
}
class Table(QTableWidget):
def __init__(self, d):
m = len(d[next(iter(d))])
n = len(DATA)
super().__init__(m, n)
hor_headers = []
for n, (key, values) in enumerate(DATA.items()):
hor_headers.append(key)
for m, item in enumerate(values):
qtitem = QTableWidgetItem(item)
self.setItem(m, n, qtitem)
self.setHorizontalHeaderLabels(hor_headers)
# the sizeHint works fine if I disable this line
self.setVerticalHeaderLabels(f'row{i}' for i in range(1, m + 2))
self.resizeColumnsToContents()
self.resizeRowsToContents()
# improves the situation but still the window is smaller than the table
def sizeHint(self):
hh = self.horizontalHeader()
vh = self.verticalHeader()
fw = self.frameWidth() * 2
return QSize(
hh.length() + vh.width() + fw,
vh.length() + hh.height() + fw)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('<TITLE>')
table = Table(DATA)
self.setCentralWidget(table)
# did not work
# self.setFixedSize(self.layout().sizeHint())
def main(args):
app = QApplication(args)
main_win = MainWindow()
main_win.show()
raise SystemExit(app.exec_())
if __name__ == "__main__":
main(sys.argv)
结果如下:
第9行第9列没有显示,有滚动条
如果我注释掉 self.setVerticalHeaderLabels(f'row{i}' for i in range(1, m + 2))
行,那么它将起作用:
如何在具有垂直 header 标签的情况下将主要 window 完美地适合 table 小部件?
正如您在代码注释中看到的那样,我已经尝试了 python qt : automatically resizing main window to fit content 中建议的解决方案,但它们并没有起作用。
问题在于,当像项目视图这样的复杂小部件尚未“映射”时,其 children 的 实际 大小(header s 和滚动条)尚未更新。只有当视图最终显示并可能添加到布局时,它才会再次调整自身大小,以便使用 updateGeometries
.
这意味着,在此之前,每个 header 的大小基于其默认的基本内容(垂直 header 的行号)。
解决方案很简单:不要使用 header 大小,而是使用它们的提示,这些提示是使用将要显示的实际文本计算得出的:
def sizeHint(self):
hh = self.horizontalHeader()
vh = self.verticalHeader()
fw = self.frameWidth() * 2
return QSize(
hh.length() + vh.sizeHint().width() + fw,
vh.length() + hh.sizeHint().height() + fw)