Search code examples
pythonpyqt5qtcoreqtwidgets

calling of class function inside another class in python


I recently started learning Python + PyQt5. Please help me understand how calling of class function inside another class in python.

I have the following code

from PyQt5 import QtGui, QtWidgets, QtCore, uic
from PyQt5.Qt import *

class mywindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        QtWidgets.QMainWindow.__init__(self)
        self.ui = uic.loadUi('test.ui', self)
        self.resize(820, 300)
        self.setFixedSize(self.size())
        self.pushButton.clicked.connect(self.getValue)
        self.thread = {}
        self.pushButtonStart.clicked.connect(self.start_worker_1)
        self.pushButtonStop.clicked.connect(self.stop_worker_1)

    def getValue(self):
        self.value = self.spinBox.value()
        i = 1
        while i <= self.value:
            os.system('test1.py')
            i += 1
        else:
            print('End, i =', i)

    def start_worker_1(self):
        self.thread[1] = ThreadClass(parent=None, index=1)
        self.thread[1].start()
        self.pushButtonStart.setEnabled(False)
        self.pushButtonStop.setEnabled(True)

    def stop_worker_1(self):
        self.thread[1].stop()
        self.pushButtonStart.setEnabled(True)
        self.pushButtonStop.setEnabled(False)

class ThreadClass(QtCore.QThread):
    any_signal = QtCore.pyqtSignal(int)

    def __init__(self, parent=None, index=0):
        super(ThreadClass, self).__init__(parent)
        self.index = index
        self.is_running = True


    def run(self):
        print('Start...', self.index)
        a = mywindow()
        a.getValue()

    def stop(self):
        self.is_running = False
        print('Stop...', self.index)
        self.terminate()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    application = mywindow()
    application.show()

    sys.exit(app.exec())

I need the test.py file to be executed as many times as specified in the spinBox

Start... 1
End, i = 1

If I do while while i <= 4: then it works. But doesn't work if I pass self.value from SpinBox. What am I doing wrong?


Solution

  • You are complicating your application unnecessarily, besides that you have the error that you are creating a window object in each thread which is illogical in addition to the fact that it is forbidden to create widgets in another thread.

    In this case it is better to use QProcess and the signals to know when the script is finished executing.

    Note: since the .ui is not provided then I will show a trivial example:

    test.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>180</width>
        <height>98</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>MainWindow</string>
      </property>
      <widget class="QWidget" name="centralwidget">
       <layout class="QHBoxLayout" name="horizontalLayout">
        <item>
         <widget class="QSpinBox" name="spinBox"/>
        </item>
        <item>
         <widget class="QPushButton" name="pushButton">
          <property name="text">
           <string>Start</string>
          </property>
         </widget>
        </item>
       </layout>
      </widget>
      <widget class="QMenuBar" name="menubar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>180</width>
         <height>28</height>
        </rect>
       </property>
      </widget>
      <widget class="QStatusBar" name="statusbar"/>
     </widget>
     <resources/>
     <connections/>
    </ui>
    

    main.py

    import os
    import sys
    from functools import cached_property
    from pathlib import Path
    
    from PyQt5 import QtGui, QtWidgets, QtCore, uic
    
    CURRENT_DIRECTORY = Path(__file__).resolve().parent
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self):
            super().__init__()
            self.ui = uic.loadUi(os.fspath(CURRENT_DIRECTORY / "test.ui"), self)
    
            self.ui.pushButton.clicked.connect(self.handle_clicked)
    
        @cached_property
        def manager(self):
            return Manager()
    
        def handle_clicked(self):
            number_of_processes = self.ui.spinBox.value()
            script = os.fspath(CURRENT_DIRECTORY / "test1.py")
            for i in range(number_of_processes):
                self.manager.execute(script, dict(i=i))
    
    
    class Manager(QtCore.QObject):
        @cached_property
        def processes(self):
            return list()
    
        def execute(self, script, metadata=None):
            process = QtCore.QProcess()
            process.setProperty("metadata", metadata or dict())
            process.finished.connect(self.handle_finished)
            process.setProgram(sys.executable)
            process.setArguments([script])
            process.start()
            self.processes.append(process)
    
        def handle_finished(self):
            process = self.sender()
            self.processes.remove(process)
            metadata = process.property("metadata")
            print(f"{metadata} finished")
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
    
        w = MainWindow()
        w.show()
    
        sys.exit(app.exec())