separate functions from gui into process. lagging - python

first i created the functional parts of my code and later decided to add a interface to it, so i have linked the interface and and the main function of the previous code as bellow.
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(921, 988)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.sheet2 = QtWidgets.QLabel(self.centralwidget)
self.sheet2.setObjectName("sheet2")
self.verticalLayout.addWidget(self.sheet2)
self.sheet1 = QtWidgets.QLabel(self.centralwidget)
self.sheet1.setObjectName("sheet1")
self.verticalLayout.addWidget(self.sheet1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 921, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
# self.label_2.setText(_translate("MainWindow", "TextLabel"))
# self.label.setText(_translate("MainWindow", "TextLabel"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
def update_sheet2(self, Image):
qim = ImageQt(Image)
pix = QtGui.QPixmap.fromImage(qim)
pix = pix.scaled(self.sheet2.width(), self.sheet2.height(), QtCore.Qt.KeepAspectRatio)
self.sheet2.setPixmap(pix)
self.sheet2.setAlignment(QtCore.Qt.AlignCenter)
def update_sheet1(self, Image):
qim = ImageQt(Image)
pix = QtGui.QPixmap.fromImage(qim)
pix = pix.scaled(self.sheet1.width(), self.sheet1.height(), QtCore.Qt.KeepAspectRatio)
self.sheet1.setPixmap(pix)
self.sheet1.setAlignment(QtCore.Qt.AlignCenter)
def run_ui():
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
w.background = main(w)
t = Process(target=w.background.process)
t.start()
sys.exit(app.exec_())
in the function named main(ui) in this code, the codes where it uses the ui is as follows. and i used the run_ui() function to run the code
def main(ui):
for i in range(100000000):
x=1
y = x*x*x
img = Image.open('XXX.png'.format(GRAY_PATH,1))
ui.update_sheet1(img)
if __name__ == '__main__':
run_ui()
and i have passed the ui 'w' as an argument to the main funciton, where it uses that reference to call the update_sheet1,2 functions with image data.
this lags the GUI and its always not responding and the images also do not appear on the GUI.
i think this has something to do with the way i liked the interface. but dont know how to fix it.
thanks for any help.

Qt does not support multiprocessing so to remove complexity from the problem use threading. In this case Qt also indicates that the GUI should not be modified from another thread, instead of that I create a QObject and export it to the other thread, this QObject has a signal that transports the image.
On the other hand when you do main(w) you are invoking the heavy task in the main process and that causes the GUI to freeze, instead you have to pass the name of the function, and the arguments of that function through of args:
from PyQt5 import QtCore, QtGui, QtWidgets
from PIL import Image
from PIL.ImageQt import ImageQt
from threading import Thread
# ...
class Signaller(QtCore.QObject):
imageSignal = QtCore.pyqtSignal(Image.Image)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
def update_sheet2(self, Image):
# ...
#QtCore.pyqtSlot(Image.Image)
def update_sheet1(self, Image):
qim = ImageQt(Image)
pix = QtGui.QPixmap.fromImage(qim)
pix = pix.scaled(self.sheet1.width(), self.sheet1.height(), QtCore.Qt.KeepAspectRatio)
self.sheet1.setPixmap(pix)
self.sheet1.setAlignment(QtCore.Qt.AlignCenter)
def run_ui():
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
signaller = Signaller()
signaller.imageSignal.connect(w.update_sheet1)
t = Thread(target=main, args=(signaller,), daemon=True)
t.start()
sys.exit(app.exec_())
def main(signaller):
for i in range(100000000):
x=1
y = x*x*x
img = Image.open('XXX.png')
signaller.imageSignal.emit(img)
if __name__ == '__main__':
run_ui()

Related

How do You get a third script to handle information of two other scripts related to GUIs in pyqt5?

I have recreated a problem I am encountering as a minimal example below.
The situation: I have two Qt Designer generated GUI, each being called by their own separated scripts. A third script is meant to collect information from the first script upon the click of a button on the second script. I does not, yet there is no errors.
I have also attempted to solve this by using signals, but these does not seem to communicate between scripts. I provided a simpler version here that doesn't use signals per se.
My question is: How do You get a third script to handle information of two other scripts related to GUIs in pyqt5 ?
Here is the minimal example:
The first GUI script:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(504, 223)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.TypeHere = QtWidgets.QTextEdit(self.centralwidget)
self.TypeHere.setObjectName("TypeHere")
self.verticalLayout.addWidget(self.TypeHere)
self.HelloButton = QtWidgets.QPushButton(self.centralwidget)
self.HelloButton.setObjectName("HelloButton")
self.verticalLayout.addWidget(self.HelloButton)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 504, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.HelloButton.setText(_translate("MainWindow", "Say hello"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
The second GUI script:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(282, 392)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.pushButton01 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton01.setObjectName("pushButton01")
self.verticalLayout.addWidget(self.pushButton01)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 282, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton01.setText(_translate("MainWindow", "PushButton"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
JustSomeTextv01, the script of the first GUI:
from PyQt5 import QtWidgets
from PyQt5.QtCore import QProcess, QThreadPool
from TypingUIv01 import Ui_MainWindow
import JustSomeButtonsv01 as JSB
import sys
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.HelloButton.pressed.connect(self.openButtons)
self.Display = JSB.Window()
self.ButtonsThread()
def openButtons(self):
self.Display.show()
def ButtonsThread(self):
self.threadpoolbutt = QThreadPool()
self.threadpoolbutt.start(self.runButtons)
def runButtons(self):
self.butt = QProcess()
print("Buttons Running")
self.butt.execute('python',['JustSomeButtonsv01.py'])
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
JustSomeButtonsv01, the script of the second GUI:
from PyQt5 import QtWidgets
from PyQt5.QtCore import QProcess, QThreadPool
from ButtonsUIv01 import Ui_MainWindow
# import JustSomeRecordv01 as JSR
import sys
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.RecordThread()
def RecordThread(self):
self.threadpoolrec = QThreadPool()
self.threadpoolrec.start(self.runRecord)
def runRecord(self):
self.rec = QProcess()
print("Record Running")
self.rec.execute('python',['JustSomeRecordv01.py'])
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
# window.show()
sys.exit(app.exec())
And finally, JustSomeRecordv01, the third script trying to interact with the other two:
from PyQt5 import QtWidgets
import sys
from TypingUIv01 import Ui_MainWindow as JSTWin
from ButtonsUIv01 import Ui_MainWindow as ButtWin
class Record(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# self.setupUi(self)
app2 = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
self.Win = JSTWin()
self.Win.setupUi(MainWindow)
self.Text = self.Win.TypeHere.toPlainText()
print("Running")
self.Butt = ButtWin()
self.Butt.setupUi(MainWindow)
self.Butt.pushButton01.pressed.connect(self.PrintIT)
def PrintIT(self):
print("Texting")
print(self.Text)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Record()
# window.show()
sys.exit(app.exec())
How to reproduce the problem:
You execute the JustSomeTextv01 script. Press the "Hello Button" and a second window will show up. You type anything in the QTextEdit of the first window and then click the button of the second window. The intent is that this second button would print what You wrote, but it doesn't work.
Thank You for your time,
I managed to do it within the example scripts, but the only solution was to put everything not-GUI into the same script as so:
# To test textbox related function
from PyQt5 import QtWidgets, QtCore
from TypingUIv01 import Ui_MainWindow
from ButtonsUIv01 import Ui_MainWindow as Ui2
import sys
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
PatchSignal = QtCore.pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.HelloButton.pressed.connect(self.openButtons)
self.PatchSignal.connect(self.printIT)
def openButtons(self):
self.w2 = Wintwo()
self.w2.show()
def printIT(self):
self.Text = self.TypeHere.toPlainText()
# print("PRINTING")
print(self.Text)
class Wintwo(QtWidgets.QMainWindow, Ui2):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.pushButton01.pressed.connect(self.Emit)
self.emitter = window
def Emit(self):
# print("EMITTING")
self.emitter.PatchSignal.emit()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
It seems sending Signals between scripts is simply not possible in pyqt5!
Somehow this doesn't work in my actual script since "window" isn't recognized, but that's another question for another day.

PyQt5 doesn't launch QProcess in a window-chain

I have a program that requires several scripts to work together.
I managed to recreate the situation with a simplified example.
I have a main window (here called the StartTestUIv01) that is launched from another script (here called LaunchTestv01) so that variables and options can be added in my actual script. This main window have buttons that allows the user to open another window (here the BasicGraphUIv01) that itself uses data obtained by another script (here the LaunchBasicGraphv01).
So the script chain becomes like this:
LaunchTestv01 -> StartTestUIv01 -> LaunchBasicGraphv01 -> BasicGraphUIv01
Here is the code for each:
LaunchTestv01
## This will launch StartTestUIv01 with the button
from PyQt5 import QtWidgets
from PyQt5.QtCore import QProcess
from StartTestUIv01 import Ui_MainWindow
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.startGraph = QtWidgets.QAction('Launch Graph', self)
self.w = None #Set the default value
self.pushButton.clicked.connect(self.LaunchGraph)
def LaunchGraph(self):
if self.w is None:
print("Working")
# self.message("Executing Graph script")
self.w = QProcess()
self.w.finished.connect(self.closeGraph)
self.w.start("python",['LaunchBasicGraphv01.py'])
def closeGraph(self):
print("Closing")
# self.message("Graph script ended")
self.w = None
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
StartTestUIv01
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(313, 196)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(30, 20, 261, 121))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 313, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "START"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
LaunchBasicGraphv01
## This calculates values to insert in the Graph and displays that Window
from PyQt5 import QtWidgets
import BasicGraphUIv01 as ui
from pyqtgraph.Qt import QtCore
import numpy as np
x = np.arange(0,9)
y = np.random.randint(25, size=(9))
MainWindow = ui.QtWidgets.QMainWindow()
win = ui.Ui_MainWindow()
win.setupUi(MainWindow)
MainWindow.show()
# p0 = win.centralwidget.plot(x,y, pen='b')
p0 = win.graphWidget.plot(x,y, pen='y')
class Window(ui.QtWidgets.QMainWindow, ui.Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
def update():
y = np.random.randint(25, size=(9))
p0.setData(x,y)
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(0)
BasicGraphUIv01
from PyQt5 import QtCore, QtGui, QtWidgets
from pyqtgraph import PlotWidget
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(473, 283)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.graphWidget = PlotWidget(self.centralwidget)
self.graphWidget.setGeometry(QtCore.QRect(10, 10, 451, 211))
self.graphWidget.setObjectName("graphWidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 473, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Now the obvious problem is that the chain doesn't start !
It seems that if I'm launching a script that is itself launching another window, it just doesn't happen!
What is the proper way of doing this ?
EDIT: So I got banned because this solved question wasn't good enough or something.
To clarify; I was searching for the proper way of launching a PyQt script from another in the case where a python script is needed in-between to collect data.
Hope this helps.
Solved it!
Thanks to #musicamante for the clues.
I only had to change the two launching scripts as so:
LaunchTestv01
## This will launch StartTestUIv01 with the button
from PyQt5 import QtWidgets
from PyQt5.QtCore import QProcess
from StartTestUIv01 import Ui_MainWindow
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.startGraph = QtWidgets.QAction('Launch Graph', self)
self.w = None #Set the default value
self.pushButton.clicked.connect(self.LaunchGraph)
def LaunchGraph(self):
if self.w is None:
print("Working")
# self.message("Executing Graph script")
self.w = QProcess()
self.w.finished.connect(self.closeGraph)
self.w.execute('python',['LaunchBasicGraphv01.py'])
def closeGraph(self):
print("Closing")
# self.message("Graph script ended")
self.w = None
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
LaunchBasicGraphv01
from PyQt5 import QtWidgets
from BasicGraphUIv01 import Ui_MainWindow
from pyqtgraph.Qt import QtCore
import numpy as np
import sys
app = QtWidgets.QApplication(sys.argv)
x = np.arange(0,9)
y = np.random.randint(25, size=(9))
MainWindow = QtWidgets.QMainWindow()
win = Ui_MainWindow()
win.setupUi(MainWindow)
MainWindow.show()
# p0 = win.centralwidget.plot(x,y, pen='b')
p0 = win.graphWidget.plot(x,y, pen='y')
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
def update():
y = np.random.randint(25, size=(9))
p0.setData(x,y)
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(0)
if __name__ == '__main__':
sys.exit(app.exec())
Thanks for the help !

Updating label text from another class

I'm new at python and i need some help ;-)
I created a window with a label with the QT designer en generated the py file (window.py):
'''
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(847, 283)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.lblMain = QtWidgets.QLabel(self.centralwidget)
self.lblMain.setGeometry(QtCore.QRect(160, 60, 311, 51))
self.lblMain.setObjectName("lblMain")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 847, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.lblMain.setText(_translate("MainWindow", "label main window"))
'''
I created main.py which calls the window:
from PyQt5 import QtWidgets,QtGui
from window import Ui_MainWindow
class window(QtWidgets.QMainWindow):
def __init__(self):
super(window, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = window()
win.show()
sys.exit(app.exec_())
So far so good.
From within main.py i can set the text of the label using:
self.ui.lblMain.setText('some text')
This works also.
Now i would like to create another file with another class which can update the label.
class update.py:
from PyQt5 import QtWidgets,QtGui
from window import Ui_MainWindow
class window(QtWidgets.QMainWindow):
def __init__(self):
super(window, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
def settext(self):
self.ui.lblMain.setText('updated')
And here i'm stuck.
Can anyone give a hand ?
Cheers John
A function to update a label no matter where it came from:
def update_label(label, new_text):
label.setText(new_text)
You can save this function anywhere you like including inside a new class. The function or the new class don't need to know anything about the ui to do this.
If it's in a class you'll have to create an instance of that class before using it.
The class you show should work perfectly, simply call the function settext somewhere.
Under update.py:
class Updater:
def __init__(self, label):
self.label = label
def settext(self):
self.label.setText('updated')
Notice that this class is not another window, it accepts the label object from the Ui_MainWindow class as an argument and saves it as a property. To use it add under main, after you create the app:
my_instance = Updater(win.ui.lblMain)
my_instance.settext()
You could even pass the whole win.ui as an argument. As long as all the classes share the same instance of ui then they will change the same widgets
For completeness, a full program that uses the updater class to change the text in the GUI:
from PyQt5 import QtWidgets,QtGui
from window import Ui_MainWindow
class window(QtWidgets.QMainWindow):
def __init__(self):
super(window, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
class Updater:
def __init__(self, label):
self.label = label
def settext(self):
self.label.setText('updated')
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = window()
win.show()
my_instance = Updater(win.ui.lblMain)
my_instance.settext()
sys.exit(app.exec_())

Trying to send signal between two classes with PyQt5 to change label from configparser

I am trying to use signals and slots to update an element in my program.
The first page opens and reads the config file to set some labels.
I have an "Options" page that you can update the config file.
What I want to happen is when you click "save" on the second window it saves to the config, and then on the first page runs a function (read_Config) that will then read the updated config file and update the label to change. I have tried multiple different methods and am failing to understand how the signals and slots work. Thanks for your help. Here is the code, it is two files. test.py and config.ini.
This is the test.py:
#!/bin/usr/env python
import sys
import configparser
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QApplication
class TestApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(TestApp, self).__init__()
self.setupUi(self)
self.dialogs = []
self.read_Config()
self.window2Button.clicked.connect(self.goto_Pagetwo)
self.closeButton.clicked.connect(self.close)
def read_Config(self):
config = configparser.ConfigParser()
config.read('config.ini')
labelone = config['default']['labelone']
self.label.setText(labelone)
def goto_Pagetwo(self):
dialog = Pagetwo(self)
self.dialogs.append(dialog)
dialog.show()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(244, 113)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.window2Button = QtWidgets.QPushButton(self.centralwidget)
self.window2Button.setObjectName("window2Button")
self.verticalLayout.addWidget(self.window2Button)
self.closeButton = QtWidgets.QPushButton(self.centralwidget)
self.closeButton.setObjectName("closeButton")
self.verticalLayout.addWidget(self.closeButton)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "This is a Label"))
self.window2Button.setText(_translate("MainWindow", "Window 2"))
self.closeButton.setText(_translate("MainWindow", "Close"))
class Pagetwo(QtWidgets.QMainWindow):
trigger = pyqtSignal()
def __init__(self, parent):
super(Pagetwo, self).__init__()
self.setupUi(self)
self.dialogs = []
self.saveButton.clicked.connect(self.save)
self.closeButton.clicked.connect(self.close)
def save(self):
string = self.lineEdit.text()
config = configparser.ConfigParser()
config.read('config.ini')
config.set('default', 'labelone', string)
with open('config.ini', 'w') as configfile:
config.write(configfile)
self.trigger.connect(self.parent().read_Config())
self.trigger.emit()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(246, 128)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit)
self.saveButton = QtWidgets.QPushButton(self.centralwidget)
self.saveButton.setObjectName("saveButton")
self.verticalLayout.addWidget(self.saveButton)
self.closeButton = QtWidgets.QPushButton(self.centralwidget)
self.closeButton.setObjectName("closeButton")
self.verticalLayout.addWidget(self.closeButton)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.saveButton.setText(_translate("MainWindow", "Save"))
self.closeButton.setText(_translate("MainWindow", "Close"))
def main():
app = QApplication(sys.argv)
main = TestApp()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
And this is the config.ini file:
[default]
labelone = This is a label
Thanks to anyone who takes the time to help me with this.
UnclassedPenguin
You have the following errors:
The Pagetwo constructor does not use the parent parameter so parent() will be None:
class Pagetwo(QtWidgets.QMainWindow):
trigger = pyqtSignal()
def __init__(self, parent): # <-----
super(Pagetwo, self).__init__() # <---- You have to pass
# ...
It is recommended that the connection be made only once because the connection does not discriminate if there was already the connection, for example if you press n times the save button of Pagetwo then there will be n connections so it will call the same slot n times, in this case what It is better to do it in the constructor.
When it is connected, the name of the function is used, that is, you should not invoke it with the ().
Considering the above, the solution is:
class Pagetwo(QtWidgets.QMainWindow):
trigger = pyqtSignal()
def __init__(self, parent=None):
super(Pagetwo, self).__init__(parent) # <---
self.setupUi(self)
self.dialogs = []
self.saveButton.clicked.connect(self.save)
self.closeButton.clicked.connect(self.close)
self.trigger.connect(self.parent().read_Config) # <---
def save(self):
string = self.lineEdit.text()
config = configparser.ConfigParser()
config.read('config.ini')
config.set('default', 'labelone', string)
with open('config.ini', 'w') as configfile:
config.write(configfile)
self.trigger.emit()
# ...

PyQt5 - cannot create new widgets dynamically on button press to function [duplicate]

I have a method named 'test()' that loads 3 one-row tables into a scrollbar.
For some reason that I cannot figure out, however, the while it works if I simply activate test() on load, it doesn't work if I comment it out and then try to activate it via the push of a button.
Here is the main module (with test())
from PyQt5 import QtCore, QtWidgets
from design import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
#test(self)
def test(self):
from random import randint
x = randint(0, 99)
print(x)
height = 30
yPos = 0
for i in range(3):
rowVals = ['test%s' % str(x + i)]
qTbl = QtWidgets.QTableWidget(self.sawDoc)
qTbl.setObjectName("tbl%s" % (i))
qTbl.setGeometry(QtCore.QRect(0, yPos, 880, height))
qTbl.horizontalHeader().setVisible(False)
qTbl.verticalHeader().setVisible(False)
yPos += height
qTbl.setRowCount(1)
qTbl.setColumnCount(len(rowVals))
for r, cell in enumerate(rowVals):
item = QtWidgets.QTableWidgetItem()
item.setText(str(cell))
qTbl.setItem(0, r, item)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
And here is the design module (with the button)
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(896, 453)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.scrDoc = QtWidgets.QScrollArea(self.centralwidget)
self.scrDoc.setGeometry(QtCore.QRect(0, 0, 891, 391))
self.scrDoc.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrDoc.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.scrDoc.setWidgetResizable(False)
self.scrDoc.setObjectName("scrTest")
self.sawDoc = QtWidgets.QWidget()
self.sawDoc.setGeometry(QtCore.QRect(0, 0, 869, 300))
self.sawDoc.setObjectName("sawDoc")
self.scrDoc.setWidget(self.sawDoc)
self.btnTest = QtWidgets.QPushButton(self.centralwidget)
self.btnTest.setGeometry(QtCore.QRect(430, 400, 80, 15))
self.btnTest.setObjectName("btnTest")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.btnTest.clicked.connect(self.test)
def test(self):
import main
main.test(self)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "昊珩のCAT工具"))
self.btnTest.setText(_translate("MainWindow", "Test"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Simply nothing happens when I push the button (except for the print out working successfully).
Can someone tell what's wrong?
The parents show the children at the beginning, but afterwards it is the responsibility of the children to show themselves, the simple solution is to use show():
qTbl = QtWidgets.QTableWidget(self.sawDoc)
qTbl.show()
But I see that you are implementing the solution in an inelegant way, the connection do it in main.py, do not modify the file generated by Qt Designer (delete the connection and the test method in design.py)
You must use a layout and there add the QTableWidget.
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
self.btnTest.clicked.connect(self.test)
def test(self):
from random import randint
x = randint(0, 99)
lay = QtWidgets.QVBoxLayout(self.sawDoc)
for i in range(3):
rowVals = ['test%s' % str(x + i)]
qTbl = QtWidgets.QTableWidget()
qTbl.setObjectName("tbl%s" % (i))
qTbl.horizontalHeader().hide()
qTbl.verticalHeader().hide()
qTbl.setRowCount(1)
qTbl.setColumnCount(len(rowVals))
for r, cell in enumerate(rowVals):
item = QtWidgets.QTableWidgetItem()
item.setText(str(cell))
qTbl.setItem(0, r, item)
qTbl.resize(qTbl.sizeHint())
lay.addWidget(qTbl)

Categories