You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python PyQt5窗口中添加垂直滚动并保持表格布局?

问题分析与解决方案

你的代码主要存在以下几个问题,导致滚动条无法正常工作或布局混乱:

  1. 未定义scroll_widget:代码中所有控件都以scroll_widget作为父控件,但这个变量从未创建,实际控件都直接挂载在主窗口上,根本没进入滚动区域。
  2. 缺少QScrollArea的正确配置:PyQt5中实现滚动必须通过QScrollArea,需要把承载表格内容的widget放入其中,再将滚动区域添加到主布局。
  3. 主窗口布局未启用:你创建了self.layout但没有调用self.setLayout(self.layout),导致所有控件都是绝对定位,无法和滚动区域配合。
  4. 滚动部件未设置合适大小:用绝对定位时,滚动部件的最小高度需要根据内容行数计算,否则滚动条不会触发。

修正后的完整代码

from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QLabel, QLineEdit, 
                             QPushButton, QScrollArea, QSizePolicy)
from PyQt5.QtCore import QSize

class ChemicalWindow(QWidget):
    def __init__(self, chemicals, data):
        super().__init__()

        self.setWindowTitle("Chemicals")
        self.setMinimumSize(QSize(600, 600))
        self.setStyleSheet("background-color:#eaf4f4;")
        self.chemicals = chemicals
        self.data = data

        # 主布局初始化并设置给窗口
        self.main_layout = QVBoxLayout()
        self.setLayout(self.main_layout)

        # 创建滚动区域
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)  # 允许滚动部件随内容调整大小
        self.scroll_area.setVerticalScrollBarPolicy(1)  # 总是显示垂直滚动条(可选)
        
        # 创建承载表格内容的widget
        self.scroll_widget = QWidget()
        self.scroll_area.setWidget(self.scroll_widget)

        # 将滚动区域加入主布局
        self.main_layout.addWidget(self.scroll_area)

        self.createBody()
        self.createButtons()

    def createBody(self):
        # 所有控件父控件改为self.scroll_widget
        headerLabel = QLabel('Chemicals', self.scroll_widget)
        headerLabel.move(265, 10)
        headerLabel.resize(70, 40)
        headerLabel.setStyleSheet("color:#000;")

        tcLabel = QLabel('Tc', self.scroll_widget)
        tcLabel.move(200, 50)
        tcLabel.resize(60, 30)
        tcLabel.setStyleSheet("color:#000;")

        pcLabel = QLabel('Pc', self.scroll_widget)
        pcLabel.move(280, 50)
        pcLabel.resize(60, 30)
        pcLabel.setStyleSheet("color:#000;")

        cpLabel = QLabel('Cp', self.scroll_widget)
        cpLabel.move(360, 50)
        cpLabel.resize(60, 30)
        cpLabel.setStyleSheet("color:#000;")

        self.chemical_names = self.chemicals.keys()

        y_position = 90
        self.chemical_inputs = dict()

        # 计算内容总高度,用于设置scroll_widget的最小高度
        content_height = 90 + len(self.chemical_names) * 40 + 20  # 20是底部留白

        # 创建化学品标签和输入框
        for name in self.chemical_names:
            chemicalLabel = QLabel(name, self.scroll_widget)
            chemicalLabel.move(70, y_position)
            chemicalLabel.resize(75, 30)
            chemicalLabel.setStyleSheet("color:#000;")
            chemicalLabel.setToolTip(name)

            current_chemical_inputs = dict()
            for chemical_input in self.chemicals[name]:
                current_chemical_inputs[chemical_input] = QLineEdit(self.scroll_widget) 
            self.chemical_inputs[name] = current_chemical_inputs

            y_position += 40

        position_y = 90
        for individual_chemical in self.chemical_inputs:
            position_x = 160
            for chemical_input in self.chemical_inputs[individual_chemical]:
                self.chemical_inputs[individual_chemical][chemical_input].setText(
                    str(self.data['chemicals'][individual_chemical][chemical_input])
                )
                self.chemical_inputs[individual_chemical][chemical_input].move(position_x, position_y)
                self.chemical_inputs[individual_chemical][chemical_input].resize(80, 30)
                self.chemical_inputs[individual_chemical][chemical_input].setStyleSheet(
                    "color:#000;background-color:#a9d6e5;padding:2px;"
                )
                
                position_x += 90                
            position_y += 40

        # 设置滚动widget的最小大小,确保内容超出时触发滚动
        self.scroll_widget.setMinimumSize(QSize(580, content_height))

    def createButtons(self):
        close_button = QPushButton('Close', self)
        close_button.move(510, 550)
        close_button.resize(70, 30)
        close_button.setStyleSheet("background-color:#00509d;color:#fff;")
        close_button.clicked.connect(self.close)

# 测试用例(可删除)
if __name__ == "__main__":
    from PyQt5.QtWidgets import QApplication
    import sys
    test_chemicals = {
        "H2O": ["Tc", "Pc", "Cp"],
        "CO2": ["Tc", "Pc", "Cp"],
        "CH4": ["Tc", "Pc", "Cp"],
        "C2H6": ["Tc", "Pc", "Cp"],
        "C3H8": ["Tc", "Pc", "Cp"],
        "C4H10": ["Tc", "Pc", "Cp"],
        "C5H12": ["Tc", "Pc", "Cp"],
    }
    test_data = {
        "chemicals": {
            name: {"Tc": "100", "Pc": "200", "Cp": "300"} for name in test_chemicals.keys()
        }
    }
    app = QApplication(sys.argv)
    window = ChemicalWindow(test_chemicals, test_data)
    window.show()
    sys.exit(app.exec_())

关键修改说明:

  • 新增了QScrollArea和内部的scroll_widget,所有表格控件都以scroll_widget为父控件,确保它们在滚动区域内。
  • 启用了主窗口的布局,将滚动区域加入主布局,保证滚动区域正确填充窗口。
  • 计算了内容总高度并设置scroll_widget的最小高度,当内容高度超过滚动区域的显示高度时,自动触发垂直滚动条。
  • 简化了关闭按钮的槽函数,直接用self.close()无需额外定义closeButton方法。

内容的提问来源于stack exchange,提问作者Noob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:31:23