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?
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())