简体   繁体   English

如何将一个 window class 中的值传递给另一个?

[英]How to pass the value in one window class to one another?

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.因此,在第一个 class 中,我制作了第一个 window,它询问电机速度,另一个是记录和预测过程。 In the recording process, I want to collect the WAV file as future data and use the motor speed as a file name.在录音过程中,我想采集WAV文件作为以后的数据,使用电机转速作为文件名。 But I cannot pass the self.RPM value from one class to another.但我无法将 self.RPM 值从一个 class 传递给另一个。 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我想将一个 class 中的值用于另一个或任何人有比这更好的建议

Either you use signal/slots (a Qt mechanism for observer/observable), or do it the Python object way.要么使用信号/槽(用于观察者/可观察的 Qt 机制),要么使用 Python object 方式。

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.在第一种情况下,您需要在 class ( A ) 中声明一个信号,其中您 select 电机速度,然后在您的另一个 class ( B ) 中,您connect A 实例的信号连接到 B 实例中的插槽。

When doing Qt graphical applications, I prefer to use toy examples to better understand how it works.在做 Qt 图形应用程序时,我更喜欢使用玩具示例来更好地理解它是如何工作的。

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) (2 windows 可能会出现在另一个之上)

Click the button B "do something" button, then the A button "choose" and select a file, then click B again.单击按钮 B“做某事”按钮,然后单击按钮 A“选择”和 select 一个文件,然后再次单击 B。 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.你需要你的 A 知道 B,这样当从 A 选择一个文件时,它会为 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.这样,A 就设置了 B 的变量。

Conclusion结论

If you understand these 2 techniques, you can change the structure.如果你了解这2个技术,你可以改变结构。 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.你可以有一个包含数据的 class,另一个被赋予对第一个 class 的引用。或者你可以使实例化它们的代码(这里是main()函数)将信号从第一个连接到第二个插槽。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM