How to keep the dialog open after message box in PyQt5? - python

I have a QmainWindow called "first page" it has two buttons in it "Signin" and "Signup".Both buttons will open Qdialogs. In my sign in dialog I have two line edits that takes user's input and two buttons "cancel" and "ok". When "ok" is clicked I want to check some validations such as If the line edits are empty then show a QmessageBox on top of the dialog and then close the messagebox after user click "ok" on messagebox.
MY PROBLEM: When the messagebox opens, the dialog closes.
P.S: I've been implementing my code by modifing the QtDesigner code which I just found out was the worst thing to do! so I'm doing everything again. I didn't have this problem back then.
my code:
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from first_page import Ui_first_page
from signin_page import Ui_signin_page
from signup_page import Ui_signup_page
class SignIn(qtw.QDialog):
def __init__(self, *args, **kwargs):
"""SignIn constructor."""
super().__init__(*args, **kwargs)
self.ui = Ui_signin_page()
self.ui.setupUi(self)
# Connects the function that inputs data for sign in to the OK button.
self.ui.signin_buttons.accepted.connect(self.sign_in_authenticate)
def sign_in_authenticate(self):
"""Inputs the user's username and password for sign in process and checks validations"""
input_username = self.ui.signin_username_lineEdit.text()
input_password = self.ui.signin_password_lineEdit.text()
# Check if both are filled
if input_username == "":
#MY PROBLEM IS HERE
qtw.QMessageBox.critical(self,"Note", "Please input your username.")
elif input_password == "":
qtw.QMessageBox.critical(self, "Note", "Please input your password.")
else:
# Checks validations and opens mainpage
open_main_page(self, username, status)
def open_main_page(self, username, status):
""" Opens the main page after sign in"""
pass
class FirstPage(qtw.QMainWindow):
def __init__(self, *args, **kwargs):
"""FirstPage constructor."""
super().__init__(*args, **kwargs)
self.ui = Ui_first_page()
self.ui.setupUi(self)
# Connecting the buttons to open Sign in and Sign out pages
self.ui.first_page_sign_in_button.clicked.connect(self.open_sign_in_page)
self.ui.first_page_sign_up_button.clicked.connect(self.open_sign_up_page)
self.show()
def open_sign_in_page(self):
self.sigin = SignIn()
self.sigin.show()
def open_sign_up_page(self):
self.signup = SignUp()
self.signup.show()
class SignUp(qtw.QDialog):
#Doesn't do anything yet.
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.ui = Ui_signup_page()
self.ui.setupUi(self)
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
window = FirstPage()
sys.exit(app.exec_())
I'm very new so if I'm doing anything very wrong please point it out.
thanks in advance.
Mini example of my problem:
Main code:
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from mainwindow import Ui_MainWindow
from dialog import Ui_signin_Dialog
class SignIn(qtw.QDialog):
def __init__(self, *args, **kwargs):
"""SignIn constructor."""
super().__init__(*args, **kwargs)
self.ui = Ui_signin_Dialog()
self.ui.setupUi(self)
# Connects the function that inputs data for sign in to the OK button.
self.ui.signin_buttonBox.accepted.connect(self.sign_in_authenticate)
def sign_in_authenticate(self):
input_text = self.ui.input_lineEdit.text()
if input_text == "":
qtw.QMessageBox.critical(self,"Note", "Please input your data.")
class FirstPage(qtw.QMainWindow):
def __init__(self, *args, **kwargs):
"""FirstPage constructor."""
super().__init__(*args, **kwargs)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# Connecting the buttons to open Sign in and Sign out pages
self.ui.signin_pushButton.clicked.connect(self.open_sign_in_page)
self.show()
def open_sign_in_page(self):
self.sigin = SignIn()
self.sigin.show()
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
window = FirstPage()
sys.exit(app.exec_())
Ui_MainWindow:
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(311, 293)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.signin_pushButton = QtWidgets.QPushButton(self.centralwidget)
self.signin_pushButton.setGeometry(QtCore.QRect(100, 110, 89, 25))
self.signin_pushButton.setObjectName("signin_pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 311, 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.signin_pushButton.setText(_translate("MainWindow", "Sign in "))
Ui_signin_Dialog
class Ui_signin_Dialog(object):
def setupUi(self, signin_Dialog):
signin_Dialog.setObjectName("signin_Dialog")
signin_Dialog.resize(400, 300)
self.signin_buttonBox = QtWidgets.QDialogButtonBox(signin_Dialog)
self.signin_buttonBox.setGeometry(QtCore.QRect(290, 230, 80, 56))
self.signin_buttonBox.setOrientation(QtCore.Qt.Vertical)
self.signin_buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.signin_buttonBox.setObjectName("signin_buttonBox")
self.input_lineEdit = QtWidgets.QLineEdit(signin_Dialog)
self.input_lineEdit.setGeometry(QtCore.QRect(140, 130, 113, 25))
self.input_lineEdit.setObjectName("input_lineEdit")
self.retranslateUi(signin_Dialog)
self.signin_buttonBox.accepted.connect(signin_Dialog.accept)
self.signin_buttonBox.rejected.connect(signin_Dialog.reject)
QtCore.QMetaObject.connectSlotsByName(signin_Dialog)
def retranslateUi(self, signin_Dialog):
_translate = QtCore.QCoreApplication.translate
signin_Dialog.setWindowTitle(_translate("signin_Dialog", "Dialog"))
I want the Qmessagebox to open like a popup message instead of closing the dialog.

Try it:
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore, QtGui, QtWidgets # +++
#from mainwindow import Ui_MainWindow
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(311, 293)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.signin_pushButton = QtWidgets.QPushButton(self.centralwidget)
self.signin_pushButton.setGeometry(QtCore.QRect(100, 110, 89, 25))
self.signin_pushButton.setObjectName("signin_pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 311, 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.signin_pushButton.setText(_translate("MainWindow", "Sign in "))
#from dialog import Ui_signin_Dialog
class Ui_signin_Dialog(object):
def setupUi(self, signin_Dialog):
signin_Dialog.setObjectName("signin_Dialog")
signin_Dialog.resize(400, 300)
self.signin_buttonBox = QtWidgets.QDialogButtonBox(signin_Dialog)
self.signin_buttonBox.setGeometry(QtCore.QRect(290, 230, 80, 56))
self.signin_buttonBox.setOrientation(QtCore.Qt.Vertical)
self.signin_buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.signin_buttonBox.setObjectName("signin_buttonBox")
self.input_lineEdit = QtWidgets.QLineEdit(signin_Dialog)
self.input_lineEdit.setGeometry(QtCore.QRect(140, 130, 113, 25))
self.input_lineEdit.setObjectName("input_lineEdit")
self.retranslateUi(signin_Dialog)
# self.signin_buttonBox.accepted.connect(signin_Dialog.accept) # ---
self.signin_buttonBox.rejected.connect(signin_Dialog.reject)
QtCore.QMetaObject.connectSlotsByName(signin_Dialog)
def retranslateUi(self, signin_Dialog):
_translate = QtCore.QCoreApplication.translate
signin_Dialog.setWindowTitle(_translate("signin_Dialog", "Dialog"))
class SignIn(qtw.QDialog):
def __init__(self, *args, **kwargs):
"""SignIn constructor."""
super().__init__(*args, **kwargs)
self.ui = Ui_signin_Dialog()
self.ui.setupUi(self)
# Connects the function that inputs data for sign in to the OK button.
self.ui.signin_buttonBox.accepted.connect(self.sign_in_authenticate)
def sign_in_authenticate(self):
input_text = self.ui.input_lineEdit.text()
if input_text == "":
qtw.QMessageBox.critical(self,"Note", "Please input your data.")
else: # +++
self.accept() # +++
class FirstPage(qtw.QMainWindow):
def __init__(self, *args, **kwargs):
"""FirstPage constructor."""
super().__init__(*args, **kwargs)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# Connecting the buttons to open Sign in and Sign out pages
self.ui.signin_pushButton.clicked.connect(self.open_sign_in_page)
self.show()
def open_sign_in_page(self):
self.sigin = SignIn()
self.sigin.show()
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
window = FirstPage()
sys.exit(app.exec_())

Related

xbbg pulling bdp data with multithreading

I am trying to develop a pyqt5 app where I can live stream stock prices from Bloomberg. I put some field names (eg. LAST_TRADE) in the ThreadClass (QThread) to pull price every second. I also have a function in the main class to pull some non-realtime data (eg. PX_YEST_CLOSE) from Bloomberg whenever a push button is clicked. I ran into this issue that when the push button clicked, it sometimes returns LAST_TRADE data instead of PX_YEST_CLOSE. I think this is because the API only allow one request at a time. Is there a better way to workaround it?
I've included a simple version of my code below just to illustrate. Thank you!
import sys, time
from xbbg import blp
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow
from ui_interface import Ui_MainWindow
ticker = ['AMD Equity', 'NVDA Equity', 'CHK Equity', 'ABNB Equity', 'AFRM Equity', 'U Equity']
live_fields = ['LAST_TRADE']
class MainWindow(QMainWindow, Ui_MainWindow):
"""Class for the Main window"""
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.thread={}
self.getStaticData()
self.connectSignalsSlots()
self.start_worker()
def getStaticData(self):
'''Pull static data from Bloomberg'''
self.staticData = blp.bdp(list(set(ticker)), flds=['CUR_MKT_CAP', 'PX_YEST_CLOSE'])
self.label_2.setText(str(self.staticData.iat[0,0]))
def start_worker(self):
self.thread[1] = ThreadClass(parent = None)
self.thread[1].start()
self.thread[1].any_signal.connect(self.liveFeed)
def liveFeed(self,liveData):
self.label.setText(str(liveData.iat[0,0]))
def updateData(self):
'''Update table if clicked'''
print(blp.bdp(['AAPL Equity'], flds=['CUR_MKT_CAP', 'PX_YEST_CLOSE']))
def connectSignalsSlots(self):
'''Signal-slots connections'''
self.pushButton.clicked.connect(self.updateData)
class ThreadClass(QtCore.QThread):
any_signal = QtCore.pyqtSignal(object)
def __init__(self, parent=None):
super(ThreadClass, self).__init__(parent)
self.is_running = True
def run(self):
print('Starting...')
while (True):
data=blp.bdp(ticker, flds=live_fields)
time.sleep(0.1)
self.any_signal.emit(data)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
control = MainWindow()
widget = QtWidgets.QStackedWidget()
widget.addWidget(control)
widget.show()
sys.exit(app.exec())
UI below:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(590, 582)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.pushButton = QPushButton(self.centralwidget)
self.pushButton.setObjectName(u"pushButton")
self.pushButton.setGeometry(QRect(360, 80, 75, 23))
self.label = QLabel(self.centralwidget)
self.label.setObjectName(u"label")
self.label.setGeometry(QRect(90, 70, 171, 41))
self.label_2 = QLabel(self.centralwidget)
self.label_2.setObjectName(u"label_2")
self.label_2.setGeometry(QRect(90, 140, 171, 41))
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 590, 21))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QStatusBar(MainWindow)
self.statusbar.setObjectName(u"statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
self.pushButton.setText(QCoreApplication.translate("MainWindow", u"Update", None))
self.label.setText(QCoreApplication.translate("MainWindow", u"TextLabel", None))
self.label_2.setText(QCoreApplication.translate("MainWindow", u"TextLabel", None))

How to stop a thread using a button

We are creating an object detection project using Object detection API. We are train the program making pyqt5 GUI application. Trying to run the training part using thread. We want to stop the running thread using a push button. Here the code sample
class stopClass(QtCore.QThread):
def __init__(self, parent=None):
super(stopClass, self).__init__(parent)
def startTrain(self):
#changing directory
os.chdir(r"c://tensorflow_1//models//research//object_detection")
args3 = shlex.split('python train.py --logtostderr --train_dir=training/ --
pipeline_config_path=training/faster_rcnn_inception_v2_pets.config')
subprocess.run(args3, shell = True)
return
def run(self):
self.startTrain()
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(701, 495)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.Annotation = QtWidgets.QPushButton(self.centralwidget)
self.Annotation.setGeometry(QtCore.QRect(480, 10, 181, 41))
self.Annotation.setToolTip("")
self.Annotation.setObjectName("Annotation")
self.Start_train = QtWidgets.QPushButton(self.centralwidget)
self.Start_train.setGeometry(QtCore.QRect(480, 110, 181, 41))
self.Start_train.setObjectName("Start_train")
self.Stop_train = QtWidgets.QPushButton(self.centralwidget)
self.Stop_train.setEnabled(False)
self.Stop_train.setGeometry(QtCore.QRect(480, 160, 181, 41))
self.Stop_train.setObjectName("Stop_train")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 701, 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)
self.Start_train.clicked.connect(self.starting)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Start_train.setText(_translate("MainWindow", "start train"))
self.Stop_train.setText(_translate("MainWindow", "stop train"))
def starting(self):
self.stopThread = stopClass()
self.stopThread.start()
self.Stop_train.setEnabled(True)
self.Stop_train.clicked.connect(self.stopThread.exit)
self.Start_train.setEnabled(False)
In this case I do not see the need to use threads since it is enough to use QProcess that allows a simple handling of the execution of the script. On the other hand, do not modify the script generated by pyuic so my solution assumes that you must recreate that script that must be called gui.py:
import shlex
import sys
from PyQt5.QtCore import QObject, QProcess
from PyQt5.QtWidgets import QApplication, QMainWindow
from gui import Ui_MainWindow
class Manager(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._process = QProcess()
working_directory = r"c://tensorflow_1//models//research//object_detection"
self.process.setWorkingDirectory(working_directory)
self.process.setProgram(sys.executable)
args = shlex.split(
"train.py --logtostderr --train_dir=training/ --pipeline_config_path=training/faster_rcnn_inception_v2_pets.config"
)
self.process.setArguments(args)
#property
def process(self):
return self._process
def start(self):
if self.process.state() == QProcess.NotRunning:
self.process.start()
def stop(self):
if self.process.state() != QProcess.NotRunning:
self.process.kill()
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.manager = Manager()
self.Start_train.clicked.connect(self.manager.start)
self.Stop_train.clicked.connect(self.manager.stop)
self.manager.process.stateChanged.connect(self._handle_stateChanged)
def _handle_stateChanged(self, state):
self.Start_train.setEnabled(state != QProcess.Running)
self.Stop_train.setEnabled(state == QProcess.Running)
def main():
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Start a QT Thread when button is clicked

This is a sample code with just a push button and a textedit, i need to write line x line using a loop in a textedit when button is clicked.
The problem is that i need to implement threads because without them the program crashes or it doesn't write line x line, but all together when the loop ends;
and i need to implement in my application a textedit that shows info while the program loads "something".
So my question is, how to rewrite this code using threads to write in textedit when button is clicked?
The method i should run when the button is clicked is "write"
it should work like a print inside a for loop , it would print not all at once
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 480)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
self.textEdit.setGeometry(QtCore.QRect(150, 220, 321, 71))
self.textEdit.setObjectName("textEdit")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(240, 100, 75, 23))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 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.pushButton.setText(_translate("MainWindow", "PushButton"))
self.pushButton.clicked.connect(self.write)
def write(self):
string=""
for i in range(1000):
string="\n"+str(i)
self.textEdit.insertPlainText(string)
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
First of all it is recommended not to modify the class generated by Qt Designer so you must regenerate the file and assume that it is called mainwindow.py: pyuic5 your_file.ui -o mainwindow.py -x.
Considering the above, the logic is to generate the information in another thread and send it to the GUI to modify it:
main.py
import threading
from PyQt5 import QtCore, QtGui, QtWidgets
from mainwindow import Ui_MainWindow
class WriterWorker(QtCore.QObject):
textChanged = QtCore.pyqtSignal(str)
def start(self):
threading.Thread(target=self._execute, daemon=True).start()
def _execute(self):
string = ""
for i in range(1000):
string = "\n"+str(i)
self.textChanged.emit(string)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.writer_worker = WriterWorker()
self.writer_worker.textChanged.connect(self.on_text_changed)
self.pushButton.clicked.connect(self.writer_worker.start)
#QtCore.pyqtSlot(str)
def on_text_changed(self, text):
self.textEdit.insertPlainText(text)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Why my QThread class drastically slows PyQT5 app?

I'm facing the problem with Threads. I'm displaying current CPU usage with progress bar and it seems to be working well but the performance of whole window is terrible. Can't even click the button without laggy behavior. Is there any simple solution to fix it?
Here is my main code
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread, pyqtSignal
import progressBarUI
import sys
import sysnfo
class MainWindow(QtWidgets.QMainWindow, progressBarUI.Ui_MainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.threadclass = ThreadClass()
self.threadclass.start()
self.threadclass.signal.connect(self.updateProgressBar)
def updateProgressBar(self):
current_percentage = sysnfo.getCpuPercentage()
self.progressBar.setValue(current_percentage)
class ThreadClass(QThread):
signal = pyqtSignal(int)
def __init__(self, parent=None):
super(ThreadClass, self).__init__(parent)
def run(self):
while True:
current_percentage = sysnfo.getCpuPercentage()
self.signal.emit(current_percentage)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainAppWin = MainWindow()
mainAppWin.show()
app.exec_()
Here is sysnfo module:
import psutil as ps
def getCpuPercentage():
return ps.cpu_percent(interval=1)
And UI file (converted to .py file):
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(787, 203)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(370, 20, 381, 111))
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(20, 50, 151, 41))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 787, 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.pushButton.setText(_translate("MainWindow", "Click me"))
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_())
When you use the "interval" parameter you are indicating that it measures the information during that time and calculates the average causing the execution of that function to take "interval" seconds, and the correct thing is to execute it in another thread, but you make the mistake of executing it too in the updateProgressBar method that lives in the main thread blocking it, instead use the information that sends you the signal:
#QtCore.pyqtSlot(int)
def updateProgressBar(self, percentage):
self.progressBar.setValue(percentage)

How to properly add OAuth2 Popup in existing PyQt5 Application

I'm pretty new to PyQt, and I've managed to fumble my way through putting together a working Application using Qt Designer. However, I need to add an OAuth2 flow to sign into a particular service, and I'm having trouble getting that to fit in my existing Application.
I found a great example that takes care of the PyQt5/OAuth2 login in Github (https://github.com/alonraiz/QT-OAuth-Example) - as long as I run it standalone. I'm now trying to integrate it so that it pops up when the user selects a specific menu item... and I'm having trouble.
The default code uses this:
app = QApplication(sys.argv)
browser = LoginWindow(app)
Since I already have an app, I've tried just calling:
browser = LoginWindow(app)
Using my existing app object. Which then gets me to this error:
QCoreApplication::exec: The event loop is already running
Which seems to make sense. So I delete this:
sys.exit(app.exec_())
But then I just get nothing.
Based on my limited PyQt5 experience, I'm sure I'm going about this completely wrong...
Here is an example illustrating where I'm at right now. Appreciate any help!
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
import sys
from urllib.parse import urlencode, parse_qs
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication
"""
login anxious-elephant#example.com
password Frantic-Magpie-Tame-Cow-9
"""
ClientId = '0oamu4rr08hdGKd9u0h7'
RedirectUrl = 'www.oauth.com/playground/authorization-code.html'
RedirectScheme = 'https://'
Scopes = ['photo offline_access']
ResponseType = 'code'
Headers = {'client_id': ClientId, 'redirect_uri': RedirectScheme+RedirectUrl, 'response_type': ResponseType,
'scope': str.join(' ', Scopes), 'state': 'RT6TfGb4jEWbz7SI'}
AuthUrl = 'https://dev-396343.oktapreview.com/oauth2/default/v1/authorize?{headers}'.format(
headers=urlencode(Headers))
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(234, 167)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 234, 22))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionLogin = QtWidgets.QAction(MainWindow)
self.actionLogin.setObjectName("actionLogin")
self.menuFile.addAction(self.actionLogin)
self.menubar.addAction(self.menuFile.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.actionLogin.setText(_translate("MainWindow", "Login"))
class RequestInterceptor(QWebEngineUrlRequestInterceptor):
def __init__(self, app):
super(RequestInterceptor, self).__init__()
self.app = app
def interceptRequest(self, info):
if RedirectUrl == (info.requestUrl().host()+info.requestUrl().path()):
params = parse_qs(info.requestUrl().query())
if 'code' in params.keys():
print('OAuth code is {code}'.format(code=params['code']))
self.app.quit()
# return params['code']
class LoginWindow(QWebEngineView):
logged_in = QtCore.pyqtSignal(['QString'])
def __init__(self, app):
super(LoginWindow, self).__init__()
self.nam = self.page()
self.app = app
self.setUrl(QUrl(AuthUrl))
self.show()
self.loadFinished.connect(self._loadFinished)
interceptor = RequestInterceptor(app)
self.page().profile().setUrlRequestInterceptor(interceptor)
# This needs enabled to get the working example running:
# sys.exit(app.exec_())
def _loadFinished(self, result):
self.page().toHtml(self.callable)
def callable(self, data):
self.html = data
class MainMenu(Ui_MainWindow):
def __init__(self, dialog, mainapp):
global fn
Ui_MainWindow.__init__(self)
self.setupUi(dialog)
self.actionLogin.triggered.connect(self.login)
self.mainapp = mainapp
def login(self):
print("login")
browser = LoginWindow(self.mainapp)
if __name__ == "__main__":
# This doesn't work
app = QtWidgets.QApplication(sys.argv)
menu = QtWidgets.QMainWindow()
prog = MainMenu(menu, app)
menu.show()
sys.exit(app.exec_())
# This works:
# app = QApplication(sys.argv)
# browser = LoginWindow(app)
What I'm looking to do is get the OAuth flow work as a popup from the main application rather than a standalone application (or get both applications living together in peace and harmony).
I recommend you read the PyQt5(1) docs so you know how to use the class generated by Qt Designer. Considering the above, the solution is to inherit from QMainWindow and use the Qt Designer class as the interface class. The interceptor object is a local variable that also generates a problem, so that it does not happen, pass the window as parent.
Considering the above, the solution is:
from urllib.parse import urlencode, parse_qs
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineCore, QtWebEngineWidgets
"""
login anxious-elephant#example.com
password Frantic-Magpie-Tame-Cow-9
"""
ClientId = "0oamu4rr08hdGKd9u0h7"
RedirectUrl = "www.oauth.com/playground/authorization-code.html"
RedirectScheme = "https://"
Scopes = ["photo offline_access"]
ResponseType = "code"
Headers = {
"client_id": ClientId,
"redirect_uri": RedirectScheme + RedirectUrl,
"response_type": ResponseType,
"scope": str.join(" ", Scopes),
"state": "RT6TfGb4jEWbz7SI",
}
AuthUrl = "https://dev-396343.oktapreview.com/oauth2/default/v1/authorize?{headers}".format(
headers=urlencode(Headers)
)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(234, 167)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 234, 22))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionLogin = QtWidgets.QAction(MainWindow)
self.actionLogin.setObjectName("actionLogin")
self.menuFile.addAction(self.actionLogin)
self.menubar.addAction(self.menuFile.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.actionLogin.setText(_translate("MainWindow", "Login"))
class RequestInterceptor(QtWebEngineCore.QWebEngineUrlRequestInterceptor):
codeChanged = QtCore.pyqtSignal(str)
def interceptRequest(self, info):
if RedirectUrl == (info.requestUrl().host() + info.requestUrl().path()):
params = parse_qs(info.requestUrl().query())
if "code" in params.keys():
code = params["code"][0][0]
print("OAuth code is {code}".format(code=params["code"][0][0]))
self.codeChanged.emit(code)
class LoginWindow(QtWebEngineWidgets.QWebEngineView):
codeChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(LoginWindow, self).__init__(parent)
self.setUrl(QtCore.QUrl(AuthUrl))
self.loadFinished.connect(self._loadFinished)
interceptor = RequestInterceptor(self)
self.page().profile().setUrlRequestInterceptor(interceptor)
self.show()
self.interceptor.codeChanged.connect(self.codeChanged)
#QtCore.pyqtSlot(bool)
def _loadFinished(self, result):
self.page().toHtml(self.callable)
def callable(self, data):
self.html = data
class MainMenu(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainMenu, self).__init__(parent)
self.setupUi(self)
self.actionLogin.triggered.connect(self.login)
lay = QtWidgets.QVBoxLayout(self.centralwidget)
self.code_label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
lay.addWidget(self.code_label)
#QtCore.pyqtSlot()
def login(self):
self.browser = LoginWindow()
self.browser.codeChanged.connect(self.onCodeChanged)
#QtCore.pyqtSlot(str)
def onCodeChanged(self, code):
self.code_label.setText(code)
# self.browser.close()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
menu = MainMenu()
menu.show()
sys.exit(app.exec_())
(1) Using the Generated Code

Categories

Resources