pythonqtpyqt5

QPushButton won't pass QDoubleSpinBox values to a function in same class with 2 tabs or more


Context

I would like to create an interface to control the voltages of a power supply. I have designed an interface with PyQt5, with all the fields where I write the voltages, and the buttons I need to apply the voltages, check them, and so on. I want several tabls. This interface looks like this.

enter image description here

I used QDoubleSpinBoxes and QPushButton and I would like that, when pressing buttons, the values from the spin boxes are passed to functions that actually apply the voltages. From there it relies on nidaqmx library that I did not include but using print() to materialise their place. In the program there is all functions in a single class. One function for the ui, and some other functions to apply, check etcetc.

Problem

The push buttons do not pass the values from the spin boxes to the functions that should apply or check the voltages. This is weird because I am following this example from official Qt website where they do something very similar (check Another example) with this way of using classes also from the documentation.

Program sample

I would like to provide a clear MWE, so let's say I have : one spinbox, one tab, just two buttons : CHECK and APPLY.

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

# Some functions needed in every tabs
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")
        # Some functions from nidaqmx to control the instruments.

# Main UI class
class Ui_MainWindow(QtWidgets.QWidget,Commands): # object  QtWidgets.QTabWidget
    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")

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)   

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)   

# running the program
def main():
    app = QtWidgets.QApplication(sys.argv)
    ex = Ui_MainWindow()
    ex.show()
    sys.exit(app.exec_())
    
if __name__ == '__main__':
    main()

Error

If I press the button CHECK I have the following error.

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

Pressing any of the buttons, I find a similar error, as if the QDoubleSpinBoxes were not properly passed to the functions, even if I use self.


Solution

  • As I wrote my questions I found out many things that allow to solve it in a quite neat way, I share my findings with you.

    To have the above program working, just very few changes are required :

    Call the classes with self as argument

    tabs.addTab(tab1UI(self),"Tab 1")
    tabs.addTab(tab2UI(self),"Tab 2")
    

    and define the QDoubleSpinBox as

    self.DC01 = QtWidgets.QDoubleSpinBox()
    self.DC02 = QtWidgets.QDoubleSpinBox()
    

    Also, no need to call the widgets with self as argument such as in main_layout.addWidget(QtWidgets.QLabel(f'V',self),i,2).

    My previous attempt was to put all functions in one class, and all the tabs would be functions. But I also struggled to pass the values. It would have been possible to pass the values as arguments in the clicked.connect() under the form

    self.CHECK.clicked.connect(lambda checked, v=[all values] : self.check(v))
    

    but it would be more tedious. Have to put self in everything, change all the functions to work with the argument, and create all those lambda with the v param where I list all the values, for every button and so on ...