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

多标签页下QPushButton无法传递QDoubleSpinBox值至类内函数

背景

我想要开发一个电源电压控制界面,用PyQt5设计了包含电压输入框、应用/检查电压按钮的多标签页界面。界面使用QDoubleSpinBox作为电压输入控件,QPushButton作为操作按钮,期望点击按钮时,把自旋框中的值传入实际执行电压控制的函数(实际依赖nidaqmx库,这里用print()代替)。程序里所有函数都放在类中,包含UI构建函数和应用、检查等功能函数。

问题

点击按钮时,无法将自旋框的值传递到对应的电压应用/检查函数。参考过Qt的按钮点击示例和标签对话框示例,但问题依然存在。

示例程序

以下是最小可复现代码,包含自旋框、两个标签页及CHECK按钮:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import QtWidgets

# 各标签页通用功能类
class Commands:
    def __init__(self):
        self.AuxVolt    = [0]*16
        self.BufferVolt = [0]*16

    def check(self):
        print(f"DC01 = {self.DC01.value():.3f} V")
    def apply(self):
        print(f"Applying voltages")
        # 实际nidaqmx仪器控制逻辑写在这里

# 主窗口类
class Ui_MainWindow(QtWidgets.QWidget,Commands):
    def __init__(self, parent: QtWidgets.QWidget = None):
        super().__init__(parent)
        
        self.setFixedSize(500, 400)
        tabs = QtWidgets.QTabWidget()       
        tabs.addTab(tab1UI(),"Tab 1")
        tabs.addTab(tab2UI(),"Tab 2")
        RESET = QtWidgets.QPushButton('RESET')
        RESET.setObjectName("RESET")
        RESET.clicked.connect(self.reset)
        
        main_layout = QtWidgets.QVBoxLayout()
        main_layout.addWidget(tabs)
        main_layout.addWidget(RESET)
        self.setLayout(main_layout)
        self.setWindowTitle("Voltage control")

# 标签页1
class tab1UI(QtWidgets.QWidget,Commands):
    def __init__(self, parent: QtWidgets.QWidget):
        super().__init__(parent)
        main_layout = QtWidgets.QGridLayout()
                                    
        DC01 = QtWidgets.QDoubleSpinBox()
        DC01.setObjectName("DC01")
        DC02 = QtWidgets.QDoubleSpinBox()
        DC02.setObjectName("DC02")

        main_layout.addWidget(DC01,0,1)
        main_layout.addWidget(DC02,1,1)       
        CHECK = QtWidgets.QPushButton('CHECK')      
        CHECK.setObjectName("CHECK")
              
        main_layout.addWidget(CHECK,10,0)
        CHECK.clicked.connect(self.check)
        self.setLayout(main_layout)   

# 标签页2
class tab2UI(QtWidgets.QWidget,Commands):
    def __init__(self, parent: QtWidgets.QWidget):
        super().__init__(parent)
        main_layout = QtWidgets.QGridLayout()
                                    
        DC01 = QtWidgets.QDoubleSpinBox()
        DC01.setObjectName("DC01")
        DC02 = QtWidgets.QDoubleSpinBox()
        DC02.setObjectName("DC02")

        main_layout.addWidget(DC01,0,1)
        main_layout.addWidget(DC02,1,1)       
        CHECK = QtWidgets.QPushButton('CHECK')      
        CHECK.setObjectName("CHECK")
              
        main_layout.addWidget(CHECK,10,0)
        CHECK.clicked.connect(self.check)
        self.setLayout(main_layout)   

# 运行程序
def main():
    app = QtWidgets.QApplication(sys.argv)
    ex = Ui_MainWindow()
    ex.show()
    sys.exit(app.exec_())
    
if __name__ == '__main__':
    main()
报错信息

点击CHECK按钮时出现如下错误:

print(f"DC01 = {self.DC01.value():.3f} V")
                ^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'value'

点击任意按钮都会出现类似错误,仿佛QDoubleSpinBox的值未正确传递至函数,即使已使用self。

解决方案

问题根源

  1. 控件未绑定为实例属性:在tab1UI和tab2UI中,创建的DC01、DC02是局部变量,没有通过self.xxx绑定为类实例的属性,导致self.DC01不存在,调用时返回None。
  2. 继承逻辑冗余:主窗口和标签页都继承了Commands类,造成功能逻辑分散,且主窗口类并不需要这些功能。

修改步骤

  1. 将控件设为实例属性:创建自旋框时用self.DC01代替局部变量DC01,确保实例能访问到控件。
  2. 复用标签页代码:创建基类统一实现标签页的UI和功能绑定,避免重复编写相同逻辑。
  3. 调整继承关系:主窗口不再继承Commands,仅标签页继承该功能类。

修改后的代码

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import QtWidgets

# 通用功能类
class Commands:
    def __init__(self):
        self.AuxVolt    = [0]*16
        self.BufferVolt = [0]*16

    def check(self):
        print(f"DC01 = {self.DC01.value():.3f} V")
        print(f"DC02 = {self.DC02.value():.3f} V")
    def apply(self):
        print(f"Applying voltages")
        # 实际nidaqmx仪器控制逻辑写在这里

# 标签页基类,统一实现UI和功能绑定
class BaseTab(QtWidgets.QWidget, Commands):
    def __init__(self, parent: QtWidgets.QWidget = None):
        super().__init__(parent)
        main_layout = QtWidgets.QGridLayout()
                                    
        # 将控件绑定为实例属性
        self.DC01 = QtWidgets.QDoubleSpinBox()
        self.DC01.setObjectName("DC01")
        self.DC02 = QtWidgets.QDoubleSpinBox()
        self.DC02.setObjectName("DC02")

        main_layout.addWidget(self.DC01, 0, 1)
        main_layout.addWidget(self.DC02, 1, 1)       
        CHECK = QtWidgets.QPushButton('CHECK')      
        CHECK.setObjectName("CHECK")
              
        main_layout.addWidget(CHECK, 10, 0)
        CHECK.clicked.connect(self.check)
        
        # 添加APPLY按钮
        APPLY = QtWidgets.QPushButton('APPLY')
        APPLY.setObjectName("APPLY")
        main_layout.addWidget(APPLY, 10, 1)
        APPLY.clicked.connect(self.apply)
        
        self.setLayout(main_layout)   

# 标签页1,直接继承基类
class tab1UI(BaseTab):
    def __init__(self, parent: QtWidgets.QWidget = None):
        super().__init__(parent)

# 标签页2,直接继承基类
class tab2UI(BaseTab):
    def __init__(self, parent: QtWidgets.QWidget = None):
        super().__init__(parent)

# 主窗口类
class Ui_MainWindow(QtWidgets.QWidget):
    def __init__(self, parent: QtWidgets.QWidget = None):
        super().__init__(parent)
        
        self.setFixedSize(500, 400)
        tabs = QtWidgets.QTabWidget()       
        tabs.addTab(tab1UI(),"Tab 1")
        tabs.addTab(tab2UI(),"Tab 2")
        RESET = QtWidgets.QPushButton('RESET')
        RESET.setObjectName("RESET")
        # 可补充reset功能逻辑
        # RESET.clicked.connect(self.reset)
        
        main_layout = QtWidgets.QVBoxLayout()
        main_layout.addWidget(tabs)
        main_layout.addWidget(RESET)
        self.setLayout(main_layout)
        self.setWindowTitle("Voltage control")

# 运行程序
def main():
    app = QtWidgets.QApplication(sys.argv)
    ex = Ui_MainWindow()
    ex.show()
    sys.exit(app.exec_())
    
if __name__ == '__main__':
    main()

说明

  • 修改后,每个标签页的自旋框都绑定为实例属性,Commands类的check、apply方法可以正常获取控件值。
  • 通过BaseTab基类复用了标签页的UI代码,减少冗余,后续新增标签页只需继承基类即可。
  • 主窗口类专注于整体布局,功能逻辑由标签页类承担,职责更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 07:17:05