0

Hi guys I want the user to choose the motor speed before going into step. So, in the first class, I made the first window which asked for the motor speed and another one is the recording and predicting process. In the recording process, I want to collect the WAV file as future data and use the motor speed as a file name. But I cannot pass the self.RPM value from one class to another. This is some part of the code.

class Ui_Form(object):
    
    def setupUi(self, Form):

        #The rest of the code

    def retranslateUi(self, Form):

        #The rest of the code

    def start_click(self):
        print('Start button click')
        _translate = QtCore.QCoreApplication.translate
        self.label.setText(_translate("Form", "<html><head/><body><p align=\"center\"><span style=\" color:#000000;\">Recording</span></p></body></html>"))
        app.processEvents()
        time.sleep(1)
        count = 0
        round = 0

        for i in range(3):
            round = i + 1
            text = "Round " + str(round) + "/3"
            self.label.setText(text)
            app.processEvents()
            print(text)

            #Recording
            now = datetime.now()
            day = now.strftime("%d")
            month = now.strftime("%m")
            year = now.strftime("%y")
            hour = now.strftime("%H")
            minute = now.strftime("%M")
            second = now.strftime("%S")
            print(day,"/",month,"/",year,hour,":",minute,":",second)
            
            CHUNK = 1024 #The number of frames in the buffer
            FORMAT = pyaudio.paInt16
            CHANNELS = 1 #Each frame will have 2 samples
            RATE = 44100 #The number of samples collected per second or we can called sample rate
            RECORD_SECONDS = 2 #Duration of recording
            WAVE_OUTPUT_FILENAME = f"Data2/Test/{day}{month}{year}_{hour}{minute}{second}.wav" <--- I want to add RPM value here

            p = pyaudio.PyAudio()

            stream = p.open(format = FORMAT, channels = CHANNELS, rate = RATE, input = True, frames_per_buffer = CHUNK)
            
            print("* recording")
            
            frames = []

            for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
                data = stream.read(CHUNK) #read audio data from the stream
                frames.append(data)
            
            print("* done recording")
            self.label.setText(_translate("Form", "<html><head/><body><p align=\"center\"><span style=\" color:#000000;\">Done Recording</span></p></body></html>"))
            
            stream.stop_stream()
            stream.close()
            p.terminate()
            
            wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') # 'rb' read only, 'wb' write only
            wf.setnchannels(CHANNELS)
            wf.setsampwidth(p.get_sample_size(FORMAT))
            wf.setframerate(RATE)
            wf.writeframes(b''.join(frames)) #
            wf.close()

    #The rest of the code

class Ui_Form2(object):

    def openWindow(self):
        self.window = QtWidgets.QWidget()
        self.ui = Ui_Form()
        self.ui.setupUi(self.window)
        self.window.show()

    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(422, 202)
        Form.setFixedSize(422, 202)
        self.pushButton = QtWidgets.QPushButton(Form, clicked = lambda: self.openWindow())
        self.pushButton.setGeometry(QtCore.QRect(10, 120, 121, 71))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.pushButton.setFont(font)
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(Form, clicked = lambda: self.openWindow())
        self.pushButton_2.setGeometry(QtCore.QRect(150, 120, 121, 71))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.pushButton_2.setFont(font)
        self.pushButton_2.setObjectName("pushButton_2")
        self.pushButton_3 = QtWidgets.QPushButton(Form, clicked = lambda: self.openWindow())
        self.pushButton_3.setGeometry(QtCore.QRect(290, 120, 121, 71))
        font = QtGui.QFont()
        font.setPointSize(15)
        self.pushButton_3.setFont(font)
        self.pushButton_3.setObjectName("pushButton_3")
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(70, 20, 281, 81))
        self.label.setFrameShape(QtWidgets.QFrame.WinPanel)
        self.label.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.label.setObjectName("label")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.pushButton.setText(_translate("Form", "1300 RPM"))
        self.pushButton.clicked.connect(lambda: self.rpm_button_clicked(self.pushButton.text()))
        self.pushButton_2.setText(_translate("Form", "1500 RPM"))
        self.pushButton_2.clicked.connect(lambda: self.rpm_button_clicked(self.pushButton_2.text()))
        self.pushButton_3.setText(_translate("Form", "1800 RPM"))
        self.pushButton_3.clicked.connect(lambda: self.rpm_button_clicked(self.pushButton_3.text()))
        self.label.setText(_translate("Form", "<html><head/><body><p align=\"center\"><span style=\" font-size:18pt; font-weight:600;\">RPM Selection</span></p></body></html>"))
    
    def rpm_button_clicked(self, button_text):
        rpm_values = {'1300 RPM': 1300, '1500 RPM': 1500, '1800 RPM': 1800}
        self.RPM = rpm_values[button_text]
        print(self.RPM)
    
if __name__ == "__main__":
    Form = QtWidgets.QWidget()
    ui = Ui_Form2()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

I want to use the value from one class on another or anyone got a better idea than this can suggest

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • I am not 100% as not an expert myself but have you tried adding return self.RPM to rpm_button_clicked? I think you may be able to use it that way (try UIForm2.RPM). On phone so please double check spelling – Lord_Amenegg Jan 04 '23 at 15:06
  • Object Oriented Programming ensure data encapsulation. Search somthing about `getter()` and `setter()` , e.g. [stackOverflow](https://stackoverflow.com/a/36943813/12621346) – Hermann12 Jan 04 '23 at 16:50
  • Thx for all suggestions – Kittapon Pama Jan 06 '23 at 10:18

1 Answers1

0

Either you use signal/slots (a Qt mechanism for observer/observable), or do it the Python object way.

Signal and slot

In the first case, you need to declare a signal in the class (A) where you select the motor speed, then in your other class (B) you connect the signal for your instance of A to a slot in your B instance.

When doing Qt graphical applications, I prefer to use toy examples to better understand how it works.

Here is what I mean :

import sys
from typing import Optional

from PyQt5 import QtWidgets, QtCore


class WindowA(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__(parent=None)
        self.setWindowTitle("A")

        central_widget = QtWidgets.QPushButton("Choose")
        central_widget.clicked.connect(self.on_button_Choose_pushed)

        self.setCentralWidget(central_widget)

    def on_button_Choose_pushed(self, checked: bool) -> None:
        print("'choose' button clicked")
        file_dialog = QtWidgets.QFileDialog(parent=self)
        if file_dialog.exec():
            print("a file was selected")
            filenames = file_dialog.selectedFiles()
            print(filenames)
            assert len(filenames) == 1
            print("emitting the signal")
            self.file_selected.emit(filenames[0])
        else:
            print("no file selected")

    file_selected = QtCore.pyqtSignal(str)


class WindowB(QtWidgets.QMainWindow):
    def __init__(self, window_a: WindowA):
        super().__init__(parent=None)
        self.setWindowTitle("B")

        self.filename: Optional[str] = None

        central_widget = QtWidgets.QPushButton("Do something")
        central_widget.clicked.connect(self.on_button_Do_Something_pushed)

        self.setCentralWidget(central_widget)

        window_a.file_selected.connect(self.on_file_selected)

    def on_button_Do_Something_pushed(self, checked: bool) -> None:
        print("'do something' button clicked")
        print("filename is :", repr(self.filename))
        # do something

    @QtCore.pyqtSlot(str)
    def on_file_selected(self, filename: str) -> None:
        print("'file selected' slot received a signal, filename =", repr(filename))
        self.filename = filename


def main() -> int:
    app = QtWidgets.QApplication([])
    window_a = WindowA()
    window_a.setVisible(True)
    window_b = WindowB(window_a)  # passing A to B
    window_b.setVisible(True)
    return app.exec()


if __name__ == "__main__":
    sys.exit(main())

(the 2 windows may appear one on top of the other)

Click the button B "do something" button, then the A button "choose" and select a file, then click B again. You will get :

'do something' button clicked
filename is : None
'choose' button clicked
a file was selected
['/home/stack_overflow/log.log']
emitting the signal
'file selected' slot received a signal, filename = '/home/stack_overflow/log.log'
'do something' button clicked
filename is : '/home/stack_overflow/log.log'

Just objects

This is the over way around. You need your A to know of B, so that when a file is selected from A, it sets the variable for B.

import sys
from typing import Optional

from PyQt5 import QtWidgets, QtCore


class WindowA(QtWidgets.QMainWindow):
    def __init__(self, window_b: "WindowB"):
        super().__init__(parent=None)
        self.setWindowTitle("A")

        self._window_b = window_b  # save it for later

        central_widget = QtWidgets.QPushButton("Choose")
        central_widget.clicked.connect(self.on_button_Choose_pushed)

        self.setCentralWidget(central_widget)

    def on_button_Choose_pushed(self, checked: bool) -> None:
        print("'choose' button clicked")
        file_dialog = QtWidgets.QFileDialog(parent=self)
        if file_dialog.exec():
            print("a file was selected")
            filenames = file_dialog.selectedFiles()
            print(filenames)
            assert len(filenames) == 1
            print("setting the variable of B")
            self._window_b.filename = filenames[0]
        else:
            print("no file selected")


class WindowB(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__(parent=None)
        self.setWindowTitle("B")

        self.filename: Optional[str] = None

        central_widget = QtWidgets.QPushButton("Do something")
        central_widget.clicked.connect(self.on_button_Do_Something_pushed)

        self.setCentralWidget(central_widget)

    def on_button_Do_Something_pushed(self, checked: bool) -> None:
        print("'do something' button clicked")
        print("filename is :", self.filename)
        # do something


def main() -> int:
    app = QtWidgets.QApplication([])
    window_b = WindowB()
    window_b.setVisible(True)
    window_a = WindowA(window_b)  # passing B to A
    window_a.setVisible(True)
    return app.exec()


if __name__ == "__main__":
    sys.exit(main())

This way, A sets the variable of B.

Conclusion

If you understand these 2 techniques, you can change the structure. You can have a class containing the data, and the other being given a reference to the first class. Or you could make the code that instantiate both of them (here is is the main() function) connect the signal from the first to the slot of the second.

Lenormju
  • 4,078
  • 2
  • 8
  • 22