如何向 QScrollArea 添加固定标题?
我目前有一个 QScrollArea 定义为:
self.results_grid_scrollarea = QScrollArea()
self.results_grid_widget = QWidget()
self.results_grid_layout = QGridLayout()
self.results_grid_layout.setSizeConstraint(QLayout.SetMinAndMaxSize)
self.results_grid_widget.setLayout(self.results_grid_layout)
self.results_grid_scrollarea.setWidgetResizable(True)
self.results_grid_scrollarea.setWidget(self.results_grid_widget)
self.results_grid_scrollarea.setViewportMargins(0,20,0,0)
它非常愉快地嵌套在其他布局/小部件中,按预期调整大小等。
为了提供网格列的标题,我使用另一个位于滚动区域正上方的 QGridLayout - 这有效。但看起来有点奇怪,即使样式适当,尤其是当按需(垂直)滚动条根据需要出现或消失并且标题不再与网格列正确对齐时。我知道这是一个美学问题......但我有点挑剔;)
其他小部件在其他地方以编程方式添加/删除到 self.results_grid_layout
中。上面的最后一行是我最近添加的,因为我认为使用创建的边距区域 docs:
<块引用> <块引用>设置滚动区域周围的边距。这对于具有“锁定”行和列的电子表格等应用程序非常有用。边距空白; 将小部件放在未使用的区域。
但我一生都无法弄清楚如何真正实现这一目标,要么我的 GoogleFu 今天抛弃了我,要么很少有关于如何实现这一点的信息/示例实际上实现了这一点。
我的头脑告诉我,我可以只将一个由布局(包含任意数量的其他小部件)控制的小部件分配给滚动区域 - 正如我所做的那样。例如,如果我将 QHeaderview 添加到网格布局的第 0 行,它只会出现在视口边距下方并与布局的其余部分一起滚动?或者我错过了什么,只是只见树木不见森林?
我刚刚学习 Python/Qt,因此任何帮助、指针和/或示例(最好使用 Python,但不是必需的)将不胜感激!
编辑:遵循到目前为止给出的建议(我认为),我想出了以下小测试程序来尝试一下:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setMinimumSize(640, 480)
self.container_widget = QWidget()
self.container_layout = QVBoxLayout()
self.container_widget.setLayout(self.container_layout)
self.setCentralWidget(self.container_widget)
self.info_label = QLabel(
"Here you can see the problem.... I hope!\n"
"Once the window is resized everything behaves itself.")
self.info_label.setWordWrap(True)
self.headings_widget = QWidget()
self.headings_layout = QGridLayout()
self.headings_widget.setLayout(self.headings_layout)
self.headings_layout.setContentsMargins(1,1,0,0)
self.heading_label1 = QLabel("Column 1")
self.heading_label1.setContentsMargins(16,0,0,0)
self.heading_label2 = QLabel("Col 2")
self.heading_label2.setAlignment(Qt.AlignCenter)
self.heading_label2.setMaximumWidth(65)
self.heading_label3 = QLabel("Column 3")
self.heading_label3.setContentsMargins(8,0,0,0)
self.headings_layout.addWidget(self.heading_label1,0,0)
self.headings_layout.addWidget(self.heading_label2,0,1)
self.headings_layout.addWidget(self.heading_label3,0,2)
self.headings_widget.setStyleSheet(
"background: green; border-bottom: 1px solid black;" )
self.grid_scrollarea = QScrollArea()
self.grid_widget = QWidget()
self.grid_layout = QGridLayout()
self.grid_layout.setSizeConstraint(QLayout.SetMinAndMaxSize)
self.grid_widget.setLayout(self.grid_layout)
self.grid_scrollarea.setWidgetResizable(True)
self.grid_scrollarea.setWidget(self.grid_widget)
self.grid_scrollarea.setViewportMargins(0,30,0,0)
self.headings_widget.setParent(self.grid_scrollarea)
### Add some linedits to the scrollarea just to test
rows_to_add = 10
## Setting the above to a value greater than will fit in the initial
## window will cause the lineedits added below to display correctly,
## however - using the 10 above, the lineedits do not expand to fill
## the scrollarea's width until you resize the window horizontally.
## What's the best way to fix this odd initial behaviour?
for i in range(rows_to_add):
col1 = QLineEdit()
col2 = QLineEdit()
col2.setMaximumWidth(65)
col3 = QLineEdit()
row = self.grid_layout.rowCount()
self.grid_layout.addWidget(col1,row,0)
self.grid_layout.addWidget(col2,row,1)
self.grid_layout.addWidget(col3,row,2)
### Define Results group to hold the above sections
self.test_group = QGroupBox("Results")
self.test_layout = QVBoxLayout()
self.test_group.setLayout(self.test_layout)
self.test_layout.addWidget(self.info_label)
self.test_layout.addWidget(self.grid_scrollarea)
### Add everything to the main layout
self.container_layout.addWidget(self.test_group)
def resizeEvent(self, event):
scrollarea_vpsize = self.grid_scrollarea.viewport().size()
scrollarea_visible_size = self.grid_scrollarea.rect()
desired_width = scrollarea_vpsize.width()
desired_height = scrollarea_visible_size.height()
desired_height = desired_height - scrollarea_vpsize.height()
new_geom = QRect(0,0,desired_width+1,desired_height-1)
self.headings_widget.setGeometry(new_geom)
def main():
app = QApplication(sys.argv)
form = MainWindow()
form.show()
app.exec_()
if __name__ == '__main__':
main()
这些内容是否就是您所指向的方法?一切都按预期工作,这正是我所追求的,除了用户调整窗口大小之前的一些奇怪的初始行为,一旦调整大小,一切都会排列起来并且很好。 我可能又想太多了,或者至少忽略了一些事情……有什么想法吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你可能有点想太多了。
您需要做的就是使用滚动区域视口的几何形状和当前边距来计算要放置在边距中的任何小部件的几何形状。
这些小部件的几何形状也需要在滚动区域的
resizeEvent
中更新。如果您查看 QTableView 的源代码,我想您会发现它使用此方法来管理其标题视图(或非常类似的东西)。
编辑
为了处理测试用例中的小尺寸调整问题,我建议您阅读QRect 文档中的坐标部分(特别是第三段开始)。
我能够通过重写您的测试用例来获得更准确的大小调整,如下所示:
You may be over-thinking things slightly.
All you need to do is use the geometry of the scrollarea's viewport and the current margins to calculate the geometry of any widgets you want to place in the margins.
The geometry of these widgets would also need to be updated in the
resizeEvent
of the scrollarea.If you look at the source code for
QTableView
, I think you'll find it uses this method to manage its header-views (or something very similar).EDIT
To deal with the minor resizing problems in your test case, I would advise you to read the Coordinates section in the docs for
QRect
(in particular, the third paragraph onwards).I was able to get more accurate resizing by rewriting your test case like this:
我有一个类似的问题,解决方法略有不同。我没有使用一个 QScrollArea 我使用两个并向前移动下部滚动区域到顶部。下面的代码的作用是
I had a similar problem and solved it a little differently. Instead of using one QScrollArea I use two and forward a movement of the lower scroll area to the top one. What the code below does is